<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
    <channel>
        <title>General - Blogs at Near Infinity</title>


        <link>http://www.nearinfinity.com/blogs/</link>
        <description>Employee Blogs</description>
        <language>en</language>
        <copyright>Copyright 2010</copyright>
        <lastBuildDate>Thu, 10 Jun 2010 18:24:31 -0500</lastBuildDate>
        <generator>http://www.sixapart.com/movabletype/</generator>
        <docs>http://www.rssboard.org/rss-specification</docs>
        
        <item>
            <title>Launching Mini Confluence Enterprise Edition at the Atlassian Summit</title>
            <description><![CDATA[We're in San Francisco this week at the Atlassian Summit lunching Mini 
Confluence Enterprise Edition -- a way to access Confluence on your 
iPhone, Blackberry, Palm or Android. <br />
<br />At last year's summit, we released Mini Confluence Personal Edition,
 an iPhone app that individual users can purchase from the app store and
 run based on Confluence's XML-RPC. <br /><br />The new version is a custom 
plugin installed on the server. For people using an iPhone, they still 
download an app from the app store, but with the Enterprise Edition, 
it's free. For people with other mobile devices, they get to Mini 
Confluence through a web client. <br />
<br />This year's version is two times as fast as the original (!), and 
has some cool new features like filtering on the dashboard based on your
 favorites, status updates, landscape mode, and multiple user accounts. 
Find out more about Mini Confluence at <a href="http://www.miniconfluence.com/">www.miniconfluence.com</a>.<br /><u></u>
<br />We've been talking to lots of the conference attendees the past 
couple 
of days. Some of them have already been using the personal edition, and 
have given us feedback on that. Other people have ideas for MCEE, like 
an iPad version, support for Confluence instances protected by VPN, and 
even "make Mini Jira!"<br /><br />I'm surprised by how many people here are 
on Android. It's still mostly 
iPhones, but a lot less Blackberry users than last year. <br />
<br />
A lot 
of people have been signing up for the<a href="http://www.miniconfluence.com/get-it#beta"> beta program </a>-- we're sending out
 copies of the plugin for free to anyone who's interested and letting 
them try it out for three months. I'm anxious to hear the feedback so we
 can improve it before people start paying for it. <br />
<br />If you try it out, let us know what you think!<br /><br />And now... I 
think it's time for some Ghirardelli Chocolate :-) ]]></description>
            <link>http://www.nearinfinity.com/blogs/caroline_wizeman/launching_mini_confluence_ente.html</link>
            <guid>http://www.nearinfinity.com/blogs/caroline_wizeman/launching_mini_confluence_ente.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">iPhone</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">Mini Confluence</category>
            
            <pubDate>Thu, 10 Jun 2010 18:24:31 -0500</pubDate>
        </item>
        
        <item>
            <title>Learning ANTLR part I</title>
            <description><![CDATA[<div style="font-size: 10pt;">This year one of my goals is to try and become proficient in using ANTLR.  I think that learning to translate text or build an external DSL is skill that, although not used everyday, will be very useful to know. For my first attempt I settled on something fairly easy, a SQL like grammar that could be used to search for files and the content within those files.  You should also be able to narrow the search results based on when the file was last modified.   My goal is to take something like the following:
<pre class="prettyprint">select * from /logs where file="*.out" and pattern="foobar" and modified &lt; 2 days ago
select * from /logs where file='*.out' and pattern='foobar' and modified between 20 and 30 minutes ago
</pre>
and translate it to the corresponding find command and pipe the results to xargs and grep:
<pre class="prettyprint">find /logs -name '*.out' -mtime -2 | xargs grep 'foobar'
find /logs -name '*.out' -mmin +20 -mmin -30 | xargs grep 'foobar'
</pre>
As an aside, if you are not familiar with xargs, check out <a href="http://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct-argument-lists-utility/" target="new">this xargs tutorial</a> or the <a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?xargs" target="new">xargs man pages</a> , it's a great utility that executes a command with the output of a previous command.
<h4>Disclaimer</h4>
Now before the villagers gather up with torches and pitch forks to run me out of town (I'm channeling <a href="http://en.wikipedia.org/wiki/Young_Frankenstein" target="new"> Young Frankenstein</a> here), I would like to make somewhat of a disclaimer.  I am not suggesting a new language or discouraging learning the *nix command line tools.  The point here is to learn ANTLR.  I found it more interesting to translate something I use everyday on my current project, versus some of the other "Hello World" ANTLR examples I have seen.  So other than a using this grammar as a learning exercise, I don't see it as being useful.
<h4>Introduction</h4>
ANTLR is a deep topic, so obviously one blog post can not go into any great detail.   So what follows is not in-depth coverage of ANTLR, but a detailed description of the grammar developed.  I will explain each section as well as  some of the decisions and trade-offs I made.  For my development environment I'm using:
<ol>
	<li>Eclipse 3.5.1</li>
	<li>Java 6</li>
	<li>The <a href="http://antlrv3ide.sourceforge.net/" target="new">ANTLR IDE </a>plugin for Eclipse.  You could also use <a href="http://www.antlr.org/works/index.html" target="new">ANTLRWorks</a>, the gui development environment for ANTLR.  ANTLRWorks is an excellent tool, I just felt more comfortable to do this work in Eclipse.</li>
	<li> ANTLR version 3.2</li>
	<li> Mac OS X 10.6.2.</li>
</ol>
So with all of that out of the way,  let's get started looking at the grammar.
<h3>options, @header</h3>
<pre class="prettyprint">grammar FQL;
options {
     language = Java;
}
@header {
     package bbejeck.antlr.fql;
}
</pre>
Here I am specifying a combined grammar named FQL.  (FQL is short for File Query Language and yes, I know the name sucks)
In options I'm specifying that I want the generated code to be  Java.  I could have also specified C,C++ or Python here as well.  ANTLR also has support for generating code in Ruby, but with the version I am using (v 3.2) I could not get it to work.  I did find <a href="http://rubyforge.org/projects/antlr3/" target="new">ANTLR Ruby</a>.  I have not tried it out, but from the documentation it looks promising.  The @header option is setting the package for the generated parser code.  This is also where I would have specified any needed imports.
<h3>@members</h3>

The @members section is where you place instance variables and methods that will be placed and used in the generated parser.  Most likely the code in the members section will be used in embedded actions in the parser rules.
<pre class="prettyprint"> @members {
  private StringBuilder findBuilder = new StringBuilder("find ");
  
  private StringBuilder filter = new StringBuilder();
  
  private void addString(String s){
    if(s!=null){
        findBuilder.append(s);
     }
  }
  
  private String buildTimeArg(String s, String snum, String sign){
       StringBuilder timeBuilder = new StringBuilder();
       int num = Integer.parseInt(snum);
       
       if(s.equals("days")){
           return timeBuilder.append(" -mtime ").append(sign).append(num).toString();
       }
       if(s.equals("hours")){
           return timeBuilder.append(" -mmin ").append(sign).append((num*60)).toString();
       }
       
       return timeBuilder.append(" -mmin ").append(sign).append(num).toString();
  }
  
  protected void mismatch(IntStream input, int ttype, BitSet follow) throws RecognitionException{
        throw new MismatchedTokenException(ttype,input);
  }
  
  public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException{
     throw e;
  }
  
}
</pre>
The two StringBuilders <i>findBuilder</i> and <i>filter</i> will be used by embedded actions to build up our translated query.   The reason for two StringBuilders will be explained when we cover the parsing rules.  The <i>addString</i> method is to check for optional tokens that could be null.  I could have easily checked for null in the embedded code within each rule,  but I felt it cluttered the grammar too much.  The <i>buildTimeArg</i> method is used as sort of a poor man's symbol table to translate the <i>modified</i> clause to the proper time format for the <i>mmin</i> or <i>mtime</i> arguments.  
The final two methods override how the generated parser responds to recognition errors (the generated parser extends ANTRL's Parser class which in turn extends the BaseRecognizer class).  By default ANTLR will recover from recognition errors and continue on, trying to read more tokens if available.   But in this grammar, if there is a recognition error along the way I want to stop processing right there.  

<h3>@rulecatch</h3>
Each parser rule is converted into a method call in the generated parser with a try - catch block surrounding the parsing code.  The catch statement here will be embedded in each one of the try-catch blocks in the parser.  
<pre class="prettyprint">@rulecatch{
    catch (RecognitionException e){
            throw e;
      }
}</pre>
If you remember from the previous section we want to stop parsing stop when RecognitionExceptions are encountered, so we re-throw the caught exception.
<h3>@lexer::header</h3>
Here we are specifying the package for the generated lexer.
<pre class="prettyprint">@lexer::header {
  package bbejeck.antlr.fql;
}
</pre>

Now let's move on to the parsing rules.

<h3>Parsing Rules</h3>
<pre class="prettyprint">evaluate returns [String query]
      :  query';' {$query = builder.toString() + filter.toString() ;}
      ;

query
       :   select_stmt where_stmt
       ;

select_stmt
      :  'select' '*' 'from' directory
      ;
</pre>
Here <i>evaluate</i> is our top level rule and returns a String, translated and built as the input is parsed.  Anything within the curly braces is code that will be embedded in the generated parser.  Note how we reference query from the grammar by placing a '$' before the word 'query'.  Also note that the string returned is a concatenation from the two StringBuilders we declared in the @members section.  The <i>query</i> rule is comprised of a <i>select_stmt</i> followed by a <i>where_stmt</i>.  The <i>select_stmt</i> is "select * from" followed by the directory rule.
<pre class="prettyprint">directory
       : (p='.'{addString($p.text);} | (p='/'?{addString($p.text);}IDENT{addString($IDENT.text);})+ )
       ;
</pre>
The directory rule accepts either a '.', a relative or an absolute path.  If the first expression is not provided there must be at least one path expression denoted by the '+'.  The variable 'p' is used to give a handle to the '.' or '/' token so it can be extracted . IDENT is a lexer rule which will be explained a little bit later.  All tokens here are passed into the <i>addString</i> method defined in the members section.
<pre class="prettyprint">where_stmt
       :  ('where'  clause ('and' clause)* ) ?
       ;
clause
       : file_name
       | pattern
       | modified
       ;
</pre>
The <i>where_stmt</i> rule expects the string 'where' followed by 0 or more clauses.  Also the entire <i>where_stmt</i>  is optional.  Here I chose form over substance.  By that I mean the grammar as it stands here will allow multiple clause's that would not make sense, i.e multiple file_name arguments etc.  I could have specified an exact order of clauses that would have also effectively set the limit of clauses entered, but I would rather the grammar be flexible and trust that the user knows what they want to do.
<pre class="prettyprint">  
file_name
       : 'file'  '=' STRING_LITERAL
         {addString(" -name ");addString($STRING_LITERAL.text);}
       ;

pattern
       :   'pattern'  '=' STRING_LITERAL
             { filter.append(" | xargs grep  ").append($STRING_LITERAL.text); }
       ;
</pre>
The <i>file_name</i> rule sets the -name argument again using the <i>addString</i> method.  The lexer rule STRING_LITERAL will accept whatever the user inputs.  The <i>pattern</i> rule builds up the grep command.  Here we see the use of the second StringBuilder <i>filter</i> that was defined in the @members section.  I feel that having a second StringBuilder to capture text for the grep filter is a hack.   The issue is that the <i>grep</i> command needs to be last in our translated query, but I really want the where statement to be in any order.  So by placing the tokens captured by the <i>pattern</i> rule in a separate StringBuilder I can easily guarantee the <i>grep</i> statement will be last.  
<pre class="prettyprint">modified
       :  modified_less
       |  modified_more
       |  modified_between
       ;
</pre>
The modified rule has three options.  This portion builds the mmin/mtime argument(s) for the <i>find</i> command.
<pre class="prettyprint">   
modified_less
       :   'modified'  '&lt;'  INTEGER time_span                             
           { addString(buildTimeArg($time_span.text,$INTEGER.text,"-")); }                     
       ; 
  
modified_more                     
       :   'modified'  '&gt;' INTEGER time_span
           { addString(buildTimeArg($time_span.text,$INTEGER.text,"+")); }
       ;

modified_between
       :   'modified' 'between' int1=INTEGER 'and' int2=INTEGER time_span
            { addString(buildTimeArg($time_span.text,$int1.text,"+")); }
            { addString(buildTimeArg($time_span.text,$int2.text,"-")); }
       ;
</pre>
The grammar allows you to specify searching by the time a file was last modified.  Here we use the method <i>buildTimeArg</i> to translate the input to the correct argument for either <i>mmin</i> (minutes modified) or <i>mtime</i> (days modified). Also take note of setting the two variables <i>int1</i> and <i>int2</i>.  Those are used to disambiguate which INTEGER token to use.
<pre class="prettyprint">time_span
       :   'days'
       |   'minutes'
       |   'hours'
       ;
</pre>
The time_span rule allows input of days, minutes or hours.  The hours argument is converted into minutes by the <i>buildTimeArg</i> method.

That's it for the parsing rules, now on to the lexer rules.
<h3>Lexer Rules</h3>
<pre class="prettyprint">fragment DIGIT : '0'..'9';
fragment LETTER : 'a'..'z'|'A'..'Z' ;

STRING_LITERAL : '\''.*'\'';
INTEGER : DIGIT+ ;
IDENT : LETTER(LETTER | DIGIT)* ;
WS : (' ' | '\t' | '\n' | '\r' | '\f')+  {$channel=HIDDEN;};
</pre>
DIGIT and LETTER are not lexer rules, as you can see by the fragment definition.  These are used for making the grammar more readable.  In the WS definition the {$channel=HIDDEN;} is used to ignore whitespace in the input.

<h3>Test Code</h3>
I used the following code to test the grammar from the command line:
<pre class="prettyprint">public class FQLTester {

public static void main(String[] args) throws Exception{
     BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
     String line = null;
     System.out.println("Enter your search:");
     while((line = reader.readLine())!= null){
         if(line.equalsIgnoreCase("quit")){
            System.exit(0);
         }
        CharStream charstream = new ANTLRStringStream(line);
        FQLLexer lexer = new FQLLexer(charstream);

        TokenStream tokenStream = new CommonTokenStream(lexer);
        FQLParser parser = new FQLParser(tokenStream);

        String parsed = null;
        try{
            parsed = parser.evaluate();
            System.out.println("parsed query is ["+parsed+"]");
            Process process = Runtime.getRuntime().exec(new String[]{"sh","-c",parsed});
            InputStream input = process.getInputStream();
            BufferedReader procReader = new BufferedReader(new InputStreamReader(input));
            String searchResults = null;
            while((searchResults=procReader.readLine())!=null){
                  System.out.println(searchResults);
            }
        }catch(Exception e){
               e.printStackTrace();
        }
      System.out.println("Enter your search:");
    }
}
</pre>

Since this blog is just scratching the surface as far as ANTLR's capabilities are concerned, I plan to be writing more about ANTLR in the near future.  Full source code for everything presented is <a href="http://github.com/bbejeck/antlr_code" target="new">available here</a>.
More resources for learning ANTLR are:
<ul>
	<li><a href="http://javadude.com/articles/antlr3xtut/index.html" target="new">Scott Stanchfield's video tutorial on ANTLR</a></li>
	<li><a href="http://www.pragprog.com/titles/tpantlr/the-definitive-antlr-reference" target="new">Definitive Guide to ANTLR, Pragmatic Books</a></li>
</ul>

That's it for now, thanks for your time.</div>]]></description>
            <link>http://www.nearinfinity.com/blogs/bill_bejeck/learning_antlr_part_i.html</link>
            <guid>http://www.nearinfinity.com/blogs/bill_bejeck/learning_antlr_part_i.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Java</category>
            
            
            <pubDate>Sat, 27 Feb 2010 00:44:19 -0500</pubDate>
        </item>
        
        <item>
            <title>Hanging out with industry leaders...</title>
            <description><![CDATA[Thanks to Near Infinity's generous training budget, I had the opportunity last week to spend 3 days with several members of the&nbsp;<a href="http://www.objectmentor.com/">Object Mentors</a>&nbsp;group. These guys have an enormous amount of experience, especially&nbsp;<a href="http://www.objectmentor.com/omTeam/martin_r.html">"Uncle" Bob Martin</a>. So I thought I would share a few of the pearls of wisdom they dropped along the way:<div><br /><div><ul><li>"Programming is a social exercise" - I thought this was a really good point. It was mentioned in the context of pair-programming, but I think it has far-reaching implications. Software development is more than just running through a bunch of formulas and crunching out an answer. Interaction within the team and with domain experts is crucial, to not only build the software right, but build the right software.</li><li>"A refactoring is something that takes a few seconds, or a few minutes at most" - I was really impressed with the importance of automated refactorings in his discussions. I think most of the time that I spend "refactoring" is in small, manual edits, whereas most of the time that he spends is in using automated refactoring to "chunk" his edits. I definitely need to learn these keystrokes and refactorings better. Maybe I should start a "Refactoring Driven Development" movement...</li><li>"Don't put refactoring on the schedule; do it all the time" - Simple, but effective. My tendency is to want to spend all my time refactoring, but this curbs that, because it forces me to refactor while I'm delivering user stories.&nbsp;</li><li>"There are 3 essential design skills: nose, vision, and plan" - A nose for recognizing design smells, a vision for seeing a good design for your codebase, and an ability to come up with a plan to get from point A to point B.&nbsp;</li><li>"Testing trumps good design" - This bothered me at first, but I think it's a really good point. The idea &nbsp;here is not to say that design is not important. But, rather, if you are forced to choose between between a "bad" design that allows better test coverage (e.g., less encapsulation), and "good" design which is hard to test, choose testability. The reason here is that the biggest roadblock to changing your codebase is not bad design, but FEAR of breaking something. If you know you will know when you've broken something, then you can retrofit a better design later.</li><li>"There is self-worth tied up in "finishing" something" - He also drew a distinction between having something working (which some developers will call "finishing" it), and finishing it - making it not only work, but be thoroughly tested, maintainable, etc.</li><li>Presentation layer - he talked about having the thinnest possible UI layer, which talks to a presentation layer to find out everything about how it should render. Then test the UI and business logic completely separately</li><li>"You aren't doing agile development unless you are tracking your velocity and remaining story points in terms of passing, automated acceptance tests" - I balked at this at first, feeling like it was too easy to use this as a performance to beat the team over the head with. After I thought about it, though, it's really about the definition of done. We are done if all the features we said would be working are working. And how can we know this? Only by testing them. Continuously. Which means it should be automated.</li><li>Acceptance tests don't need to be end-to-end, and, in fact, shouldn't be. This is another one that made me hesitate. After all, how do you know the feature is really working unless you go all the way from the UI to the database and back? Well, in short, because you're the developer. There's more value in being able to test features fast, constantly, than in being able to truly test them all the way from one end to the other. Mock/stub out what you need to to make that happen.</li><li>FitNesse is cool. This is the second time I've played around with that tool, and the second time I've been impressed with its power and simplicity. I definitely need to play around with it some more.</li></ul></div></div>]]></description>
            <link>http://www.nearinfinity.com/blogs/andrew_wagner/hanging_out_with_industry_lead.html</link>
            <guid>http://www.nearinfinity.com/blogs/andrew_wagner/hanging_out_with_industry_lead.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Agile Development</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Testing</category>
            
            
            <pubDate>Fri, 26 Feb 2010 09:50:17 -0500</pubDate>
        </item>
        
        <item>
            <title>Hello, World!</title>
            <description>I&apos;m a new software engineer here at Near Infinity, and very excited to be aboard! Hope to put some real content on this blog soon. </description>
            <link>http://www.nearinfinity.com/blogs/andrew_wagner/hello_world.html</link>
            <guid>http://www.nearinfinity.com/blogs/andrew_wagner/hello_world.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">meta</category>
            
            <pubDate>Sun, 31 Jan 2010 17:01:49 -0500</pubDate>
        </item>
        
        <item>
            <title>How to switch your Adobe Creative Suite from a PC to a Mac Platform</title>
            <description><![CDATA[I was considering switching from PC to a Mac, but I have Adobe CS4 Design Premium and didn't want to pay the $1,799 to buy it again. It was surprisingly difficult to find any information about whether or not I could do it, and if so how. Some Adobe employees at a trade show even told me that it couldn't be done.<br /><br />It turns out, though, that for $6.25 shipping and handling and the promise that you'll stop using and destroy your older version, they'll let you change. They call it Cross-Platform Swap. Here's how you do it:<br /><br /><ol><li>Go to <a href="http://www.adobe.com/go/supportportal">http://www.adobe.com/go/supportportal</a> If you have an account, log in. If you don't, you'll need to create one.<br /><br /></li><li>Under Get Support, Click on Orders and Returns<br /><br /></li><li>Choose the issue type Return / Exchange / Refund and then click the button that says Proceed to Online Form<br /><br /></li><li>Fill out the form, typing Cross Platform Swap in the subject line. Submit.<br />-- In the notes field, here's what I typed: <i>I am switching to a Mac and would like to do a cross-platform swap. I understand that my existing copy must be destroyed as soon as the new one arrives.</i><br /><br /></li><li>The next day, you'll get an email saying your issue is resolved and providing no useful information. Instructions for what to do next are actually in the ticket itself, which you can get back to on the support portal. Here's what you do:<br />-- Call 1-800-833-6687 and follow the prompts to customer service (#2 then #4)<br />-- Have your case number and credit card ready<br />-- Give them your credit card info and verify all your contact information<br /></li></ol>And that's it. They charge your credit card for $6.25 shipping and handling. Your old serial number gets invalidated, you destroy the old copy, and they send you the new one.<br /><br />As a side note, here's a tip for getting customer service from Adobe: Instead of going to the support portal when you have a question, go to the pages on their website where they have prices and information about purchasing products. Almost immediately, you'll get a helpful person IMing you asking if they can help. These IM helpers are nowhere to be found (ironically) in the support section of their site.<br /><br />Oh, and their customer support phone numbers aren't that easy to find, so here they are:<br /><b>Adobe Customer Support:</b> 1-800-585-0774 option #4<br />or<br /><b>Adobe Customer Support: </b>1-800-833-6687 option #2 then option #4.<br />&nbsp;<br />Good luck platform-swappers!<br /><br />]]></description>
            <link>http://www.nearinfinity.com/blogs/caroline_wizeman/how_to_switch_your_adobe_creat.html</link>
            <guid>http://www.nearinfinity.com/blogs/caroline_wizeman/how_to_switch_your_adobe_creat.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">Adobe</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">Illustrator</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">InDesign</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">Mac</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">PC</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">Photoshop</category>
            
            <pubDate>Fri, 18 Dec 2009 15:33:37 -0500</pubDate>
        </item>
        
        <item>
            <title>SharePoint Power User - Really?</title>
            <description><![CDATA[<span class="Apple-style-span" style="color: rgb(0, 0, 0); font-family: arial, sans-serif; border-collapse: collapse; "><p>Having just completed a week of SharePoint Power User training, one thing is evident -- I am far from being a Power User. What they should call the class is SharePoint User Tapas. Trainees get just a little taste of all that SharePoint can do. It's enough to make us say "Ooh, I love this," and "I'm not so crazy about that." I can certainly see the benefits of implementing SharePoint in an organization, and I also understand the dangers if it is not done well. This leads me to one conclusion -- don't be afraid to think big, but start small. Choose one business problem to focus on, make sure it's one you think you can get your organization to buy in to, and go from there. It is not very likely that SharePoint will be the best solution for every business problem that you have.</p><p class="MsoNormal" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; ">Training always leaves you with a head full ideas for how to implement solutions based on the new knowledge you have gained. It's like meeting a new love interest for the first time -- you think of all of the things that "could be," but you have to go on a lot of dates before you can sort out what is reality versus fantasy in terms of your expectations.</p></span> ]]></description>
            <link>http://www.nearinfinity.com/blogs/karen_upton/sharepoint_power_user_-_really.html</link>
            <guid>http://www.nearinfinity.com/blogs/karen_upton/sharepoint_power_user_-_really.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
            
            <pubDate>Thu, 10 Dec 2009 20:14:42 -0500</pubDate>
        </item>
        
        <item>
            <title>Installing Go on OSX Snow Leopard</title>
            <description><![CDATA[ Go is a new experimental language that has been released by Google that is suppose to have nearly the speed of C while executing, without a lot of the normal headaches of C/C++ coding.&nbsp; For example Go has garbage collection, dynamic types, reflections, etc. see <a href="http://www.infoq.com/news/2009/11/Go-Google-New-Language">Google Experiments With A New Language, Go</a> for a good overview.&nbsp; So after reading a few things about it, I wanted to try it out, and here is how I got it working on my 64-bit OSX machine.<br /><br />It's pretty basic, all I did was follow the instructions <a href="http://golang.org/doc/install.html">here</a>.<br /><br />First I added:<br /><br /><pre class="prettyprint">export GOROOT=$HOME/go<br />export GOOS=darwin<br />export GOARCH=amd64<br />export GOBIN=$HOME/gobin<br />export PATH=$PATH:$GOBIN</pre>
to ~/.bash_profile<br /><br />Run:<br /><br />
<pre class="prettyprint">. ~/.bash_profile</pre>
Next:<br /><br />
<pre class="prettyprint">sudo easy_install mercurial</pre>
This took a while for me to pull mercurial down, maybe their server was having problems. <br /><br />Note: I had to install the Xcode.mpkg from the Optional Installs on my Snow Leopard DVD to get gcc-4.3 installed.<br /><br />Next:<br /><br />

<pre class="prettyprint">hg clone -r release https://go.googlecode.com/hg/ $GOROOT</pre>
Next:<br /><br />
<pre class="prettyprint">cd $GOROOT/src<br />./all.bash</pre>
Note: One of the http tests goes out and touches google.com, I had to drop the firewall while building everything.&nbsp; After the build and tests were complete I turned it back on.<br /><br />And that's it! Time to make a hello world program.<br /><br />Create hello.go:<br /><br />
<pre class="prettyprint">package main<br /><br />import fmt "fmt"<br /><br />func main() {<br />&nbsp;&nbsp; fmt.Printf("hello world!\n");<br />}</pre>
Compile and Link:<br /><br />
<pre class="prettyprint">6g hello.go<br />6l hello.6</pre>
Run:<br /><br />
<pre class="prettyprint">./6.out</pre>
Output:<br /><br />
<pre class="prettyprint">hello world!</pre>
I am very excited about Go can't wait to write something real with it!<br /><br />]]></description>
            <link>http://www.nearinfinity.com/blogs/aaron_mccurry/installing_go_on_osx_snow_leop.html</link>
            <guid>http://www.nearinfinity.com/blogs/aaron_mccurry/installing_go_on_osx_snow_leop.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">c</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">go</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">google</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">language</category>
            
            <pubDate>Wed, 11 Nov 2009 14:52:23 -0500</pubDate>
        </item>
        
        <item>
            <title>Thinking Matters</title>
            <description><![CDATA[ <p>Aside from the fact that <a href="http://www.forbes.com/2009/04/29/java-oracle-sun-technology-internet-infrastructure-java.html">Oracle's Java Problem</a> contains all kinds of factual and other errors (see the comments on the post) this sentence caught my eye in particular when referring to Java being "quite hard to work with" - "Then, as now, you needed to be a highly trained programmer to make heads or tails of the language."</p>

<p>What's the issue here? That Java is hard to work with? Perhaps more specifically, not just Java but perhaps the artificial complexity in developing "Enterprise" applications in Java? Nope. The problem is that this type of thinking epitomizes the attitude that business people and other "professionals" tend to have about software development in general, in that they believe it is or should be easy and that it is always the tools and rogue programmers that are the problem. Thus, with more and better tools, they reason, there won't be a need for skilled developers and the monkey-work of actually programming could be done by, well, <a href="http://www.newtechusa.com/PPI/main.asp">monkeys</a>.</p>

<p>I believe software development is one of the hardest activities humans currently do, and yes I suppose I do have some bias since I am a developer. Also contrary to what many people think, there is both art and engineering involved, and any given problem can be solved in an almost infinite variety of ways. Unlike more established disciplines that have literally been around for hundreds or thousands of years (law, medicine, accounting, architecture, certain branches of engineering like civil, etc.), the software industry hasn't even reached the century mark yet! As a result there isn't any kind of consensus whatsoever about a completely standardized "body of knowledge" and thus there isn't an industy-recognized set of standard exams and boards like you find in the medical and law professions for example. (That topic is for a future post.)</p>

<p>One thing that is certain is that software development involves logic, and thus people who can solve problems using logic will always be needed, whether the primary medium stays in textual format (source code) or whether it evolves into some different representation like <a href="http://martinfowler.com/bliki/IntentionalSoftware.html">Intentional Software</a> is trying to do. So the statement from the article that "you needed to be a highly trained programmer to make heads or tails of the language" is always going to be true in software development. More generally, highly skilled people are needed in any complex endeavor, and attempts to dumb dumb complex things will likely not succeed in any area, not just software development. Would you trust someone to perform surgery on you so long as they have a "Dummies Guide to Surgery" book? Or someone to represent you in court who stayed at a Holiday Inn Express last night?</p>

<p>I hypothesize that things are becoming more complex as time moves on, not less. I also propose that unless we actually succeed in building <a href="http://www.scifi.com/battlestar/">Cylons</a> who end up wiping us all out or enslaving us, we will never reach a point where we don't need people to actually think and use logic to solve problems. So even though many business-types would love to be able to hire a bunch of monkeys and pay them $0.01 per day to develop software, those who actually realize that highly skilled people are an asset and help their bottom line, and treat them as such, are the ones who will come out on top, because they will smash their competitors who think of software/IT purely as a cost center and not a profit center.</p>]]></description>
            <link>http://www.nearinfinity.com/blogs/scott_leberknight/thinking_matters.html</link>
            <guid>http://www.nearinfinity.com/blogs/scott_leberknight/thinking_matters.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Java</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">cylon</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">logic</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">programming</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">thinking</category>
            
            <pubDate>Thu, 30 Apr 2009 15:59:04 -0500</pubDate>
        </item>
        
        <item>
            <title>Tuning the IBM JVM for large heaps</title>
            <description><![CDATA[
 
 
 
Recently I have been rewriting a lot of our lucene search engine code
for a web application that I'm currently supporting.&nbsp; Our physical
environment is a little different than most, we have a single very
large computer (a left over from a previous project) running several
virtual machines.&nbsp; The virtual machine that we are currently using for
our searching duties is a 64 cpu 128G box.<br />

<br />
Before I go into the tuning saga, I would like to say that in a
previous version of the search engine we ran many more (16), smaller
jvms all on the same box.&nbsp; They work together through a main controller
module that coordinates calls to all the searching jvms.&nbsp; After the
rewrite of the
searchers, there was a lot of pressure to get the new code out the
door.&nbsp; The new code partitions the data and searching duties in a very
similar way to the previous version, however I haven't had time to
focus
on getting all the parts broken up across all the jvms.&nbsp; It's very
doable, but do to customer priorities it hasn't been developed.&nbsp; But I
was in
luck (kinda), our environment was a single computer, so I thought I
will just run one large jvm.&nbsp; I knew going in that garbage collection
(GC) was going to be a
problem, I just didn't realize how much.<br />

<br />
Currently, we are running the 64-bit IBM java 6 jvm, the IBM jvm is very
different from the Sun jvm, but no more so than in the GC tuning
department.&nbsp; In the Sun jvm you have all kinds of settings to tweak,
algorithms to use etc.&nbsp; The IBM jvm just isn't as advanced, you have 4
different GC policies, and sizing for various parts of the internals.&nbsp;
And that's it!&nbsp; Great, it should be simple right?&nbsp; Well sorta.<br />

<br />

First try, bring the system online with a 50G (yes that's gigabytes)
heap, with all the default settings.&nbsp; Run some load tests and see where
we are.<br />

<br />

Everything is running great right up to the first full GC, 25 seconds
doesn't sound that long but when you are waiting for a computer to
return results, it's an eternity.&nbsp; For those that don't know, when a
full GC occurs (some of the newer Sun algorithms are different) it
stops the world (STW).&nbsp; This means the JVM is frozen until the GC is
complete.&nbsp; No good.<br />

<br />

So the default policy is the optthruput policy (-Xgcpolicy:optthruput).&nbsp; After digging through the IBM documentation,
this type of policy should be used for maximum throughput, but at the
expense of pauses during GC.&nbsp; They also mention that this should be
used for batch processing when pauses are really a problem.<br />

<br />

Next I tried the optavgpause policy (-Xgcpolicy:optavgpause), this is
suppose to smooth out the GCs by kicking off the mark phase early.&nbsp; I'm
not going to talk about mark, sweep, and compaction, you can find it
here (<a href="http://www.ibm.com/developerworks/ibm/library/i-incrcomp/">http://www.ibm.com/developerworks/ibm/library/i-incrcomp/</a>).&nbsp; But
basically it's suppose to run a concurrent parallel mark phase before
the jvm runs out of heap space and performs a full GC that STW.&nbsp; This did help,
got us down in the 10-15 second range on average, but the problem was
that the mark phase was too slow to start under heavy load and didn't
give us a whole lot of concurrent marking before the STW.&nbsp; I found this
out by adding -verbose:gc, this adds a lot of debugging information to the
standard out.&nbsp; You should just run this all the time, it provides a lot
of useful information about your application.<br />

<br />

Next I tried subpool (-Xgcpolicy:subpool), it worked fine but was
plagued by the same problem, slow full GCs.&nbsp; Subpool is suppose to work
better on large SMP machines like ours, but in the end it was more of
the same.&nbsp; It's full GCs were in the 10-12 second range, plus the application seemed
to run slower, by about 10%.<br />

<br />
And last I tried gencon (-Xgcpolicy:gencon), the newest of all
their
policies.&nbsp; Gencon is suppose to be used on "transactional systems",
systems that create a lot of short lived objects.&nbsp; Isn't that what most
java applications do?&nbsp; When I started it up, it seemed to be faster,
and our load test confirmed that, 30% more throughput.&nbsp; But the amazing
thing was that the full GCs were fast, really fast, in the 200-400ms
range, for a 50G heap!&nbsp; But wait, it wasn't using most of the heap, and
it was GCing all the time.&nbsp; Back to the verbose:gc log, AHA!&nbsp; The
nursery was too small, it was about 10% of the heap, and because our
application is almost all short lived objects I decided to increase the
size of the nursery.&nbsp; I gave it 50% of the heap, and the time between
GCs slowed down, but the time to perform the GC was still in the 350ms
range.&nbsp; Awesome!<br />

<br />

I finally settled on 100G heap with 50% a nursery, and the full GCs are
now in the 400-600ms range.&nbsp; I can live with that, because this gives
us a huge ceiling for load, and capacity.<br />

<br />

So to summarize, if you application needs to run a huge heap size, and
you are using the IBM jvm, I would start by using the gencon policy.&nbsp;
It seems to be the most modern of all their policies, and it seems to
work the best.<br /><br />Good luck!<br />

]]></description>
            <link>http://www.nearinfinity.com/blogs/aaron_mccurry/tuning_the_ibm_jvm_for_large_h.html</link>
            <guid>http://www.nearinfinity.com/blogs/aaron_mccurry/tuning_the_ibm_jvm_for_large_h.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Java</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Lucene</category>
            
            
            <pubDate>Fri, 24 Apr 2009 20:53:36 -0500</pubDate>
        </item>
        
        <item>
            <title>Use DNS Search Domains for Shorter URLs</title>
            <description><![CDATA[While I was reading through some Apple documentation on Bonjour I stumbled across a discussion on link-local addressing and DNS search domains. While the details of link-local addressing aren't that important here, the discussion on DNS search domains triggered a little light bulb in my brain.<div><br /></div><div>You see, DNS search domains are used as a guide to help your computer lookup an IP address when something simple like "blogs" is typed into your browser's URL. If you setup a DNS search domain of "nearinfinity.com", typing "blogs" will force your computer to first check if there's an address for "blogs.nearinfinity.com". If not it falls back to its default behavior.</div><div><br /></div><div>If you're a person that spends a lot of time on a small number of websites, you could use DNS search domains to your advantage to make navigating to those sites a snap. For instance, I just setup "nearinfinity.com" as an entry in my DNS search domains on my Mac. Simply go to the network preferences pane, click the advanced button at the bottom left, and then the DNS tab on the resulting popup.</div><div><br /></div><div><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="dns_search_domains_osx.jpg" src="http://www.nearinfinity.com/blogs/assets/jkunkle/dns_search_domains_osx.jpg" width="600" height="450" class="mt-image-none" style="" /></span></div><div><br /></div><div>So now, whenever I type "blogs" in my URL I get "blogs.nearinfinity.com". Whenever I type "support" I get "support.nearinfinity.com". I think you probably get the idea. I know I'm no genius for discovering this since it's precisely the reason for having search domains. I just never thought to use them before.</div>]]></description>
            <link>http://www.nearinfinity.com/blogs/jeff_kunkle/use_dns_search_domains_for_sho.html</link>
            <guid>http://www.nearinfinity.com/blogs/jeff_kunkle/use_dns_search_domains_for_sho.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Mac OS X</category>
            
            
            <pubDate>Sat, 24 Jan 2009 20:01:37 -0500</pubDate>
        </item>
        
        <item>
            <title>Why and when I started using GNU Emacs</title>
            <description><![CDATA[<p>Emacs is one of those polarizing topics among software developers. Maybe it's tripolar: Camp Emacs spars with Camp Vi to the great amusement of Camp Everyone Else. The heckling is especially raucous from Camp Java/C# IDE whose devotees ritually launch The Environment to press the '.' and ';' keys all day.
<p>To make up for that rotten attempt at humor I decided to spend some time explaining why and how I use Emacs. This blog post covers the background, the why and when I switched. The next post will cover how I use/depend on it in my daily workflow.
<p>When MacOS X first came out I was a certified <a href="http://www.freescale.com/webapp/sps/site/overview.jsp?code=CW_DEV_STUDIO&amp;tid=CWH">Metrowerks CodeWarrior</a> fanatic. They had the coolest booths at MacWorld, a killer logo, and everyone drooled over the new CWDev tools CD arrived. That powerful, graceful IDE killed Apple's <a href="http://developer.apple.com/tools/mpw-tools/">Macintosh Programmers' Workshop (MPW)</a>. Now <strong>that</strong> IDE was a strange beast:
<ul>
	<li>Ugly, ugly, ugly, and really unintuitive; its icon had binary on it (decimal value 13 I think? 01101?)</li>
	<li>A C compiler with a <a href="http://ask.slashdot.org/comments.pl?sid=42699&amp;cid=4486500">good sense of humor</a></li>
	<li>Regular expressions with bizzaro 8-bit characters in the syntax</li>
	<li>Projector, the unlovable source code pseudo-control software</li>
	<li>Locked in a mortal battle with Jasik's Debugger, which
<ol>
	<li>Was even <a href="http://www.jasik.com/castMenu.html">uglier and less intuitive</a> than <a href="http://developer.apple.com/tools/debuggers/MacsBug/">Macsbug</a>.</li>
	<li>Was the only game in town for source level debugging of system extensions.</li>
	<li>Had "shortcut" commands which used multiple meta keys at once</li>
	<li>Was so uncool it was trés cool</li>
</ol>
</li>
</ul>
<p>Metrowerks really ruled the Classic/Carbon Mac development roost for a while. It was really good software. On awesome days I got use MWPro, Jasik, <a href="http://www.mathemaesthetics.com/ResorcererInfo.html">Resorcerer</a>, <strong>and</strong> <a href="http://www.mindvision.com/macvise.asp">Installer VISE</a>.
<p>The fate of these tools was sad but clear when MacOS X arrived. Apple shed everything except its logo. Lots of good reasons to be sure but the process was messy. All the cool tools on my nerd belt could never keep up with the free, bundled tools built with asymmetric knowledge of Darwin and dyld(1).
<p>At this point my current project was written in C++ and built on several platforms. It used <a href="http://www.snake.net/software/imake-stuff/imake-faq.html">imake</a> to build all platforms from a single imakefile... except the Mac build which was a maintenance drag. MacOS X was Unix, right, so all we had to do was port imake to a new platform (arggggggghhhhh). All the imake work in Terminal.app needed a good text editor. XCode wasn't it. CodeWarrior was doomed. I needed something else.
<p>15 seconds with vi was quite enough, thank you.
<p>I remembered this program called Emacs. Sure enough, it was installed. <strong>And boy howdy was it weird.</strong> Seriously, I had to press control-x and then control-s to save a file???! control-x and control-c to quit?!!! escape-w to paste??? ... for just one brief moment vi started to look better...
<p>... but then Jasik's Debugger came to mind. It used multiple meta keys at once and that was okay, despite them appearing with Ω characters in the menu bar.
<p>That transition to accepting Emacs as probably worth learning happened 5-6 years ago. Emacs is the only program I have used literally almost every work day since then (even using it right now :-). Initially I just used it to flit between a bunch of files quickly and keep a shell prompt up all day. Just in the last year Emacs has become even much more important as a task organizer and scheduler. But more on that in the next post!
<p>Emacs is just one of the horses for a plethora of courses. I prefer vi for quick edits / wimpy *nix installations, and Eclipse for Java coding. Also, while <a href="http://www.gnu.org/software/emacs/">GNU Emacs</a> is a good distribution <a href="http://homepage.mac.com/zenitani/emacs-e.html">Carbon Emacs</a> is not to be missed if you are running a Mac. Grab a copy and have some fun with...
<ul>
	<li>M-x tetris</li>
	<li>M-x list-colors-display</li>
	<li>M-x animate-birthday-present</li>
	<li>M-x glasses-mode (BestAppliedToCamelCaseText)</li>
	<li>M-x artist-mode, then M-x artist-select-op-spray-can, then click and drag</li>
</ul>
<p>Task organization, SQL, and VCS chores are the killer apps within Emacs for me. I'll be discussing those in the next blog post. Until then please respond with questions and comments and (good) jokes about Emacs. If by any chance your curiousity was piqued then run, don't walk to the <a href="http://emacswiki.org">Emacs user community wiki</a>.
<p>(This article was previously <a href="http://blogs.foognostic.net/2008/12/why-and-when-i-started-using-gnu-emacs/">posted</a> to my personal blog.)]]></description>
            <link>http://www.nearinfinity.com/blogs/seth_schroeder/why_and_when_i_started_using_g.html</link>
            <guid>http://www.nearinfinity.com/blogs/seth_schroeder/why_and_when_i_started_using_g.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">emacs</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">gnu</category>
            
            <pubDate>Sat, 10 Jan 2009 19:21:36 -0500</pubDate>
        </item>
        
        <item>
            <title>Get Comfortable Being Uncomfortable</title>
            <description><![CDATA[ <p><a href="http://www.renaebair.com/">Renae Bair's</a> post on <a href="http://www.renaebair.com/2008/11/24/the-ranting-rubyists/">The Ranting Rubyists</a> hits a lot of nails on the head. I will freely admit to being a developer who is interested in continually learning new technologies - perhaps even at the expense of the ones I currently develop in - and I try to contribute a little back by blogging and speaking at conferences like <a href="http://www.nofluffjuststuff.com/">No Fluff Just Stuff</a> on a semi-frequent basis. But Renae's point is that many people in the development world seem to be all about the New, New Thing and ready to dismiss the old things without a second thought. My feeling is that the old things don't go away, often we just end up piling more things on top. (<a href="http://en.wikipedia.org/wiki/Turtles_all_the_way_down">It's new technologies all the way down.</a>) Sometimes there certainly is wholesale replacement, but from what I've experienced usually you just mix in the new things and things become that much more heterogeneous.</p>

<p>I think it's fine to continually push "forward" to newer and better technologies that help you do the same thing in half the time, or in half the code, or allow things to execute on twice the processors, or scale twice as much. But at the same time it is simply not cool or very intelligent to dismiss the very tools that get you paid and perhaps got you where you are today. Sometimes the intent is just that; to dismiss the old in favor of the new for the purpose of making money. Sometimes the intent is merely the <i>intellectual curiosity</i> the best developers usually possess, and in fact the best people in any field possess. A few years ago I told a <a href="http://sixty4bit.com/wp/?p=365">friend</a> "Get Comfortable Being Uncomfortable." What I meant was to learn new things and push yourself to think about doing things better and more efficiently than you currently are doing them. Sometimes this means switching or advocating a new tool; sometimes it means using your existing tools more effectively. And always it means you can't rest on your laurels and you are always challenging the status quo. Many people don't like this. Well, too bad, because reality is that things change and <a href="http://en.wikipedia.org/wiki/Resistance_is_futile">Resistance is futile</a>.</p>

<p>My day job is still mainly Java and web applications, though I also have managed to squeeze Ruby, Groovy, and Python in there (and of course realized the power of JavaScript) over time. I speak on mostly Java-related stuff like Hibernate and Spring and Groovy a bit. And currently I'm learning about new things (to me anyway) like functional languages such as Lisp and Clojure and Scala. Not because I think I'm going to rewrite the application I'm currently working on in a different language and/or framework, but because over time I feel learning new and different things makes me a better developer, architect, designer, etc. I know that the Java code I write today, while still crap, is <i>way</i> better than the crap I wrote several years ago, and has been influenced by learning Python and Ruby and Groovy and others. While it is still Java, I don't try to write overly generic, overly engineered things like I used to (well, perhaps not as much as I used to anyway). I just try to get the tasks I need to get done, done. If I need to make something more generic later, I can do it. But in addition to the power of just learning new things, I think the more well-rounded you are the better off you are and the better equipped you are to solve new problems. And maybe you'll find a much better way to solve them because you have a more diverse knowledge "portfolio" at your disposal.</p>

<p>So, getting back to Renae's <a href="http://www.renaebair.com/2008/11/24/the-ranting-rubyists/">post</a>, I think it's a great idea to continue learning new things and pushing better ways of doing things, if for no other reason than to ensure your own relevance and marketability as a developer but hopefully because you enjoy it! But while it's OK to voice your opinion and seek new and better things, don't just rip to shreds the things that got you to where you are. In the past I've made comments to people like "Java sucks" and "I'd rather be doing <a href="http://www.paulgraham.com/avg.html">Blub</a> programming" and I've tried to curb that and realize that things change, we know more today than yesterday, and to just "Get Comfortable Being Uncomfortable." You might not always get to program in <a href="http://en.wikipedia.org/wiki/Blub">Blub</a> but that shouldn't stop you from expanding what you know, and by the way the sphere of your knowledge should include more than just technical knowledge and probably should include things like economics, finance, culture, art, literature, sports, etc. Whatever. Just make yourself more well-rounded and you'll be better for it, in all aspects of life.</p>]]></description>
            <link>http://www.nearinfinity.com/blogs/scott_leberknight/get_comfortable_being_uncomfor.html</link>
            <guid>http://www.nearinfinity.com/blogs/scott_leberknight/get_comfortable_being_uncomfor.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Ruby</category>
            
            
            <pubDate>Tue, 25 Nov 2008 16:54:47 -0500</pubDate>
        </item>
        
        <item>
            <title>Forget Burndown Use Burnup Charts</title>
            <description><![CDATA[<p>Agile projects traditionally use burndown charts to visually show work remaining over time. This could be for the current iteration or it could be for the duration of the project. Either way they can help managers (or the Project Owner in Scrum) track velocity, estimate either the project or iteration completion date, or find trends in past performance. But burndown charts have a major shortcoming: they fail to show what makes agile projects agile: new requirements. And that's where burnup charts come in. But first let's examine burndown charts.</p>
<div style="FLOAT: right; MARGIN-LEFT: 10px">
<script type="text/javascript">
        var currentPageUrl = 'http://rapidapplicationdevelopment.blogspot.com/2008/10/forget-burndown-use-burnup-charts.html';

        /* Digg */
        var diggIframe = document.createElement('iframe');
        diggIframe.setAttribute('src', 'http://digg.com/tools/diggthis.php?u=' + currentPageUrl);
        diggIframe.setAttribute('height', '80');
        diggIframe.setAttribute('width', '52');
        diggIframe.setAttribute('frameborder', '0');
        diggIframe.setAttribute('scrolling', 'no');
        diggIframe.setAttribute('style', 'margin-left:auto; margin-right:auto; display:block; text-align:center;');

        /* DotNetKicks */
        var dotnetkicksLink = document.createElement('a');
        dotnetkicksLink.setAttribute('href', 'http://www.dotnetkicks.com/kick/?url=' + currentPageUrl);
        var dotnetkicksImg = document.createElement('img');
        dotnetkicksImg.setAttribute('src', 'http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=' + currentPageUrl);
        dotnetkicksImg.setAttribute('alt', 'Kick this article (a good thing) on DotNetKicks');
        dotnetkicksImg.setAttribute('border', '0');
        dotnetkicksImg.setAttribute('style', 'margin-left:auto; margin-right:auto; display:block; text-align:center;');
        dotnetkicksLink.appendChild(dotnetkicksImg);

        /* Reddit */
        var redditIframe = document.createElement('iframe');
        redditIframe.setAttribute('src', 'http://reddit.com/button?t=2&url=' + currentPageUrl);
        redditIframe.setAttribute('height', '80');
        redditIframe.setAttribute('width', '52');
        redditIframe.setAttribute('frameborder', '0');
        redditIframe.setAttribute('scrolling', 'no');
        redditIframe.setAttribute('style', 'margin-left:auto; margin-right:auto; display:block; text-align:center;');

        var div = document.createElement('div');
        div.appendChild(dotnetkicksLink);
        div.appendChild(document.createElement('br'));
        div.appendChild(diggIframe);
        div.appendChild(document.createElement('br'));
        div.appendChild(redditIframe);

        document.write(div.innerHTML);
    </script>
</div>
<p><b>The Problem with Burndown</b></p>
<p>A typical burndown for the life of a project might look like this:</p>
<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gez10dNhuPk/SQExigphzWI/AAAAAAAABlE/CxANEtBwb2Q/s1600-h/Burndown.gif"><img id="Img1" style="WIDTH: 400px; CURSOR: hand; HEIGHT: 271px" alt="" src="http://3.bp.blogspot.com/_gez10dNhuPk/SQExigphzWI/AAAAAAAABlE/CxANEtBwb2Q/s400/Burndown.gif" border="0" /></a></p>
<p>It shows the project started with 100 points of work in the backlog; it's completed eight iterations; the team accomplishes about ten points an iteration; and if everything continues at the current velocity the project will complete all work within another two iterations. Great.</p>
<p>But what happened in iteration six? Very little appears to have been accomplished. Maybe the team all took a vacation. Maybe there was a major problem or the team incorrectly estimated complexity. Or perhaps a large set of new requirements were added to the backlog because the customer decided what they thought they wanted wasn't what they really needed: namely the exact scenario agile was designed for.</p>
<p><b>Burnup Charts</b></p>
<p>The problem is that burndown charts lack two essential pieces of information. First, how much work was actually accomplished during a given iteration (as opposed to how much work remains to be completed) and second how much total work the project contains (or if you prefer how much scope has increased each iteration). A burnup chart for the exact project above might look like this:</p>
<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gez10dNhuPk/SQExi1j16lI/AAAAAAAABlM/pqg4SgFBkIs/s1600-h/Burnup.gif"><img id="BLOGGER_PHOTO_ID_5260540314308176466" style="WIDTH: 400px; CURSOR: hand; HEIGHT: 273px" alt="" src="http://4.bp.blogspot.com/_gez10dNhuPk/SQExi1j16lI/AAAAAAAABlM/pqg4SgFBkIs/s400/Burnup.gif" border="0" /></a></p>
<p>We can now clearly see that the team did not take a breather in iteration six. They continued to complete about ten points per iteration, but during the sixth iteration the scope increased by about twenty points.</p>
<p>One could imagine the opposite happening as well. Later in the project the team might delete old user stories that were envisioned during project inception and thus decrease the total scope. The burndown chart would incorrectly show such a scenario as a sudden increase in velocity.</p>
<p><b>Summary</b></p>
<p>Either way the burndown chart hides essential information. I propose we throw it away and show the slightly more complicated, but infinitely more useful burnup chart. After all you wouldn't want upper management thinking you were lazy in iteration six would you?</p>]]></description>
            <link>http://www.nearinfinity.com/blogs/lee_richardson/forget_burndown_use_burnup_charts.html</link>
            <guid>http://www.nearinfinity.com/blogs/lee_richardson/forget_burndown_use_burnup_charts.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Agile Development</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
            
            <pubDate>Thu, 23 Oct 2008 22:41:25 -0500</pubDate>
        </item>
        
        <item>
            <title>Polyglot Persistence</title>
            <description><![CDATA[<p>In late 2006 Neal Ford wrote about <a href="http://memeagora.blogspot.com/2006/12/polyglot-programming.html">Polyglot Programming</a> and predicted the wave of language choice we are now seeing in the industry to use the right language for the specific job at hand. Instead of assuming a "default" language like Java or C# and then warring over the many different available frameworks, polyglot programming is all about using the right language for the job rather than just the right framework(s). For a while now I've thought about the fact that, paralleling Neal's description of polyglot programming, a relational database seems to be the accepted and default choice for persistence. Sometimes this is due to the fact that organizations have standardized on RDBMS systems and there isn't even any other choice. Other times it is simply what we're used to doing, and possibly we don't even consider alternatives. But now, with things like <a href="http://en.wikipedia.org/wiki/SimpleDB">Amazon SimpleDB</a>, <a href="http://en.wikipedia.org/wiki/BigTable">Google Bigtable</a>, <a href="http://en.wikipedia.org/wiki/SQL_Server_Data_Services">Microsoft SQL Server Data Services (SSDS)</a>, <a href="http://en.wikipedia.org/wiki/CouchDB">CouchDB</a>, and lots more, it seems like we're now seeing the beginning of <strong>Polyglot Persistence</strong> in addition to polyglot programming.</p>

<p>Polyglot Persistence, like polyglot programming, is all about choosing the right persistence option for the task at hand. For example, some co-workers of mine on one project are effectively using <a href="http://en.wikipedia.org/wiki/Apache_Lucene">Lucene</a> as their primary datastore, since the application they've built is mainly to do complex full-text searches very fast against huge datasets. Most people probably don't think of Lucene as a data store and just consider it as their full-text search engine. But for this particular application, which aggregates multiple disparate datasets, glues them together, and performs full-text search against the consolidated view of the data, it makes a good deal of sense. It also helped that in a bake-off against a very popular traditional RDBMS system's full-text add-on product, the Lucene search solution blew the doors off the traditional RDBMS in terms of performance, and that was even after a team of consultants from the vendor came in and tried to optimize the search performance. So, in this case a non-relational data store made more sense in terms of the problem context, which was data aggregation and fast full-text search.</p>

<p>Within the past few years we've started to see and hear about how companies like Amazon and Google are using non-traditional data stores such as SimpleDB and Bigtable for their own applications. <a href="http://code.google.com/appengine/">Google App Engine</a> in fact provides access to Bigtable, <a href="http://labs.google.com/papers/bigtable.html">described as</a> a "sparse, distributed multi-dimensional sorted map," as the sole persistent store for Google App Engine applications. Other organizations like the <a href="http://www.apache.org/">Apache Software Foundation</a> have gotten into the non-relational data store market as well with things like <a href="http://couchdb.org/">CouchDB</a> which is described as "a distributed, fault-tolerant and schema-free document-oriented database accessible via a RESTful HTTP/JSON API." One of the common threads among all these non-relational stores is that they are distributed, designed for fault tolerance, embrace asynchronicity, and are based on <a href="http://www.infoq.com/articles/pritchett-latency">BASE</a> (Basically Available, Soft State, Eventually Consistent) and <a href="http://groups.csail.mit.edu/tds/papers/Gilbert/Brewer6.ps">CAP</a> (Consistency, Availability, Partition Tolerance) principles as opposed to traditional <a href="http://en.wikipedia.org/wiki/ACID">ACID</a> (Atomicity, Consistency, Isolation, Durability) properties found in traditional RDBMS systems. In addition, they are almost all either "schemaless" or provide a flexible architecture that promotes ease of schema changes over time, again as opposed to the rigid and inflexible schemas of traditional relational databases.</p>

<p> I don't think it's a coincidence that the companies creating and now offering these alternative data stores - free, commercial, or hybrid models like Google App Engine which is free up to a certain point - are all giants in distributed computing and deal with data on a massive scale. My guess is that perhaps they initially deployed some things on traditional RBDMS systems and outgrew them or maybe they simply thought they could do it better for their own specific problems. But as a result, I think over time that organizations are going to start thinking more and more about the type of persistence they need for different problems, and that ultimately the RDBMS will be but one of the available persistence choices.</p>]]></description>
            <link>http://www.nearinfinity.com/blogs/scott_leberknight/polyglot_persistence.html</link>
            <guid>http://www.nearinfinity.com/blogs/scott_leberknight/polyglot_persistence.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">acid</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">apache</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">base</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">bigtable</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">cap</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">couchdb</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">lucenesimpledb</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">persistence</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">polyglot</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">ssds</category>
            
            <pubDate>Wed, 15 Oct 2008 17:26:36 -0500</pubDate>
        </item>
        
        <item>
            <title>JSF Editable Datatable</title>
            <description><![CDATA[<p>
I recently needed to create a  "JSF Editable Datatable" where all fields (or a subset) could be edited at once.  Here's what I came up with...
</p>

<p>
My requirements:
</p>

<ul>
<li>Use a standard JSF datatable.</li>
<li>When user clicks the Edit Button, all fields (or a subset) become editable inputText components.</li>
<li>When a user clicks the Save Button, the changes will be saved to the affected objects and persisted to the DB.</li>
</ul>

<p>
My implementation involves the following:
</p>


<ul>
<li>IceFaces, Hibernate, Spring.</li>
<li>1 jspx page with an ice:datatable component.</li>
<li>1 backing bean with edit and save actions for the datatable.</li>
</ul>

<p>
The jspx: <br /></p>
<pre class="prettyprint">&lt;jsp:root
        xmlns:jsp="http://java.sun.com/JSP/Page"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:c="http://java.sun.com/jstl/core"
        xmlns:ice="http://www.icesoft.com/icefaces/component"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        version="2.0"&gt;
    &lt;jsp:directive.page contentType="text/html"/&gt;
    &lt;jsp:output omit-xml-declaration="no"
                doctype-root-element="html"
                doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
                doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/&gt;

    &lt;ice:dataTable id="editableDatatable" value="#{backingBean.elements}" var="element"&gt;
        &lt;ice:column&gt;
            &lt;f:facet name="header"&gt;
                &lt;ice:outputText value="Value 1"/&gt;
            &lt;/f:facet&gt;
            &lt;h:inputText disabled="#{backingbean.elementsDisabled}"
                         value="#{element.value1}"/&gt;
        &lt;/ice:column&gt;
        &lt;ice:column&gt;
            &lt;f:facet name="header"&gt;
                &lt;ice:outputText value="Value 2"/&gt;
            &lt;/f:facet&gt;
            &lt;h:inputText disabled="#{backingbean.elementsDisabled}"
                         value="#{element.value2}"/&gt;
        &lt;/ice:column&gt;
    &lt;/ice:dataTable&gt;

    &lt;br/&gt;

    &lt;!--Buttons will be hidden or visible based on whether the table is in edit mode or display mode--&gt;
    &lt;div id="editElement" style="display:block;"&gt;
        &lt;!--Put the table in edit mode by enabling the inputtext components--&gt;
        &lt;ice:commandButton value="Edit Element" partialSubmit="true"
                           onclick="toggleLayerOn('updateElement');toggleLayerOff('editElement');"&gt;
            &lt;f:setPropertyActionListener value="#{false}" target="#{backingBean.elementsDisabled}"/&gt;
        &lt;/ice:commandButton&gt;
    &lt;/div&gt;
    &lt;div id="updateElement" style="display:none;"&gt;
        &lt;!--Save the changes and return to display mode--&gt;
        &lt;ice:commandButton action="#{backingBean.updateElementValues}" value="Update Element Values"
                           partialSubmit="true"
                           onclick="toggleLayerOn('editElement');toggleLayerOff('updateElement');"/&gt;
        &lt;!--Cancel the changes and return to display mode--&gt;
        &lt;ice:commandButton value="Cancel Changes" partialSubmit="true"
                           onclick="toggleLayerOn('editElement');toggleLayerOff('updateElement');"&gt;
            &lt;f:setPropertyActionListener value="#{true}" target="#{backingBean.elementsDisabled}"/&gt;
        &lt;/ice:commandButton&gt;
    &lt;/div&gt;

&lt;/jsp:root&gt;
</pre>





<p>
The backing bean.  Please note the upateElementValues() method.  This gets the editableDataTable from the FacesContext, casts it to an HtmlDataTable, loops over the rows of this datatable, and casts each row to an Element.  These Elements contain the updated values entered by the user.  You must then load the original Elements via Id and make the necessary changes before persisting the updates back to the database.  Make sure to set your datatable rowIndex back to -1 (see code) or there will be JSF errors.
</p>
<pre class="prettyprint">import com.icesoft.faces.component.ext.HtmlDataTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.context.FacesContext;
import java.util.*;

public class BackingBean {

    public static final Logger log = LoggerFactory.getLogger(BackingBean.class);

    private ElementDao elementDao;
    private boolean elementsDisabled = true;
    private List&lt;Element&gt; elements = new ArrayList&lt;Element&gt;();

    public BackingBean() {
        >//get all the elements from the database
        elements = elementDao.getAllElements();
    }

    public void setElementDao(ElementDao elementDao) {
        this.elementDao = elementDao;
    }

    public void updateElementValues() {
        >//get the datatable as a UI component
        UIComponent comp = FacesContext.getCurrentInstance().getViewRoot().findComponent("editableDataTable");

        if (comp != null) {
            UIData uIData = (UIData) comp;
            HtmlDataTable myTable = (HtmlDataTable) uIData;

            for (int i = 0; i &lt; myTable.getRowCount(); i++) {
                >//loop over the rows
                myTable.setRowIndex(i);
                >//get the values that the user edited for this row
                Element modifiedElement = (Element) myTable.getRowData();
                >//print the values to verify they are correct
                log.info("Value 1 " + modifiedElement.getValue1());
                log.info("Value 2 " + modifiedElement.getValue2());

                >//load the element from the database
                Element originalElement = elementDao.load(modifiedElement.getId());
                originalElement.setValue1(modifiedElement.getValue1());
                originalElement.setValue2(modifiedElement.getValue2());
                >//update the values in the database for the given element
                elementDao.update(originalElement);

            }
            >//make sure to set the row Index back to -1!!!
            myTable.setRowIndex(-1);
        }
        >//disable the inputtext components, they should only be enabled during "edit mode"
        setElementsDisabled(true);
    }

    public boolean isElementsDisabled() {
        return elementsDisabled;
    }

    public void setElementsDisabled(boolean elementsDisabled) {
        this.elementsDisabled = elementsDisabled;
    }

    public List&lt;Element&gt; getElements() {
        return elements;
    }

    public void setElements(List&lt;Element&gt; elements) {
        this.elements = elements;
    }
}</pre>


<p>
The object:
</p>
<pre class="prettyprint">import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;

public class Element {

    @Id
    @GeneratedValue(generator = "hibernate-uuid")
    private String id;

    @Column(nullable = false)
    private String value1;

    @Column(nullable = false)
    private String value2;

    public Element(String value1, String value2) {
        this.value1 = value1;
        this.value2 = value2;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getValue1() {
        return value1;
    }

    public void setValue1(String value1) {
        this.value1 = value1;
    }

    public String getValue2() {
        return value2;
    }

    public void setValue2(String value2) {
        this.value2 = value2;
    }
}
</pre>]]></description>
            <link>http://www.nearinfinity.com/blogs/michael_bevels/jsf_editable_datatable.html</link>
            <guid>http://www.nearinfinity.com/blogs/michael_bevels/jsf_editable_datatable.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">General</category>
            
            
            <pubDate>Tue, 26 Aug 2008 15:55:31 -0500</pubDate>
        </item>
        
    </channel>
</rss>
