Code Less: A Language Keystroke Experiment

When I first started writing code in Ruby, it was a breath of fresh air after writing C# code for a year. Ruby had a thesis, a clear purpose, rather than a hodgepodge of features strung together. It was a language obviously written by someone who cared about what the code looked like.

So I jumped into it and loved writing Ruby code (still do!). Recently I had to write a project in Java using IntelliJ, and the powerful IDE was also a breath of fresh air after using text editors to write Ruby code.

The IDE helps me in the same way Ruby helped me. I write less code that does the same thing, without loosing expressiveness or transparency of intent. Less code in this case meaning less keystrokes.

So, I am going to do a little experiment using two editors and languages: Ruby with Textmate and Java with IntelliJ. I want to see how many lines of code I have to write. The application I am going to start is a simple baseball at bat scorer. First, lets see the Ruby version:

 1 class AtBat
 2 
 3     def initialize
 4         @strikes = 0
 5     end
 6 
 7     def pitch(pitch_type)
 8         @strikes = @strikes + 1 if pitch_type == :called_strike
 9     end
10 
11     def result
12         return :strikeout if @strikes == 3
13     end
14 
15 end
16 
17 describe "At Bat Scorer" do
18     
19     it "should call out at 3 strikes" do
20         at_bat = AtBat.new
21         at_bat.pitch(:called_strike)
22         at_bat.pitch(:called_strike)
23         at_bat.pitch(:called_strike)
24         at_bat.result.should == :strikeout
25     end
26 
27 end

We have about 27 lines of code written, and other than the describe method, which I have a macro for, I typed them all by hand. Let’s look at the Java code:

 1 import junit.framework.TestCase;
 2 
 3 public class AtBatTest extends TestCase
 4 {
 5     public void testThreeStrikesAndYourOut() throws exception
 6     {
 7         AtBat atBat = new Atbat();
 8 
 9         atBat.pitch("called_strike");
10         atBat.pitch("called_strike");
11         atBat.pitch("called_strike");
12         
13         assertEquals("strikeout", atBat.result());
14     }
15 }

This is just the JUnit test I wrote, there is no production code. It is about 16 lines of code, which I wrote all of but the import statement. By doing a few alt-enters on the squiggly lines, I can get a stub of a class looking like this:

 1 public class AtBat
 2 {
 3     public void pitch(String pitchType)
 4     {
 5 
 6     }
 7 
 8     public String result()
 9     {
10         return null;
11     }
12 }

That is 13 more lines of code, without really typing, just hitting enter a few times. Now, lets start to make the method pass. I am going to write the algorithm without worrying about all the type definition Java wants. Here is what it looks like:

 1 public class AtBat
 2 {
 3     public void pitch(String pitchType)
 4     {
 5         if(pitchType.equals("called_strike"));
 6             strikes++;
 7     }
 8 
 9     public String result()
10     {
11         if(strikes == 3)
12             return "strikeout";
13         return null;
14     }
15 }

So the code written is around 4 lines of code. Lets use the IntelliJ autocomplete features to help us make a passing test, which looks like:

 1 public class AtBat
 2 {
 3     private int strikes;
 4 
 5     public void pitch(String pitchType)
 6     {
 7         if(pitchType.equals("called_strike"));
 8             strikes++;
 9     }
10 
11     public String result()
12     {
13         if(strikes == 3)
14             return "strikeout";
15         return null;
16     }
17 }

So roughly, the Ruby version was 23 lines of written code and the Java version was about 20 lines of written code. There is an expense to doing all of the alt-enters to auto-generate the method and variable stubs, but IntelliJ is pretty smart about what it generates.

Also, I understand a single test doesn’t tell the whole story, but it is a good indication. I found as I wrote more tests for this application, a smaller amount of keystrokes was needed for the Java version, and the same amount was needed for Ruby.

This is due to the refactoring tools, and Intellisense. As applications get larger, I find the IntelliJ refactorings become more useful. Inversely, Ruby refactorings become more painful, as they are mostly done by hand.

So, in the end the constraints on a static language allows the IDE to make the refactoring tools better. Specifically, when writing Java code, I can lean on the IDE to generate all the uninteresting stubs for me.

All I do is fill in the algorithms: the fun part. When I start to see places where my code can be cleaned up a bit, I can lean on the IDE again to do those refactorings for me once I recognize the need for them.

Removing and optimizing the code is something which is easily deducible in static languages, as it is mostly pattern matching, with no monkey patches, meta-programming, and evals to worry about.

This is a limitation which frustrates me as a developer who wants to have a large set of tools in my bag, but is helpful when it comes to developing a powerful IDE.

The number of lines of code I need to type isn’t the reason I choose a language over another. In fact, it would be pretty low on the list of deciding factors. However, it is interesting to see what each language and its sets of tools do best.

Hopefully the Ruby community can take some notes from them. I would rather solve the other end of the equation, get a powerful Ruby IDE. I know Eclipse and Net Beans have some preliminary refactoring tools, but they are still a ways from being as seamless as their Java counterparts.

Paul Pagel, CEO and Co-founder

Paul Pagel has been a driving force in the software craftsmanship movement since its inception.