Jeff's Blog

Musings about software development, Java, OO, agile, life, whatever.

Note: This blog is no longer active. Please visit Jeff's current blog instead. Unfortunately, any new comments entered cannot be retained or displayed. If you feel strongly about a blog entry, please contact us.



Monday, June 29, 2009 
Infinitest

I recently re-downloaded Ben Rady's Infinitest, having finally gotten back into some extended Java development work. Infinitest runs tests continually, so that you need not remember to proactively run them.

The last time I played with Infinitest, perhaps over two years ago, there was no Eclipse plugin. As I recall, on save, tests would run in a separate JUnit window external to Eclipse.

At the time, I had had a brief chance to sit with Ben and look at some of the code while at Agile 2007. I thought Inifinitest was a cool idea. But I didn't use it extensively, partly because I'd begun to move into lots of C++ work, but also because I had a hard time fitting it into my very ingrained test-code-refactor cycle habits. Having to deal with an external window seemed disruptive.

Infinitest today is another matter entirely. Plugins have been developed for Eclipse and IntelliJ. In Eclipse, tests run as soon as you save. But they don't run in the JUnit view--instead, test failures are reported in the Problems window, just like compilation errors. Immediately, this means that Infinitest is not disruptive, but is instead built into the normal flow of development.

Showing test failures on save is an extremely important transition, one that will help change the outlook on what TDD means. No longer are tests only an optional afterthought, something that a developer might or might not remember to or choose to run. With Infinitest, you don't think at all about running the tests, they just run themselves. Tests are continual gating criteria for the system: If the code doesn't pass all of its tests, Eclipse continues to point out the problem. This forces the proper mentality for the TDDer: The system is not complete unless the tests pass.

Infinitest uses a dependency tree to determine which tests must be run on save. The nice part for a die-hard TDDer like me is that my tests--my saves--will execute very quickly. This is because the die-hard TDDer knows how to design systems so that the unit tests run fast. I do wonder, however, about what this feels like for the developer on a system with lots of poor dependencies and slow-running tests. I'll have to experiment and see how that feels.

I hate to dredge up an annoying buzzphrase, but Infinitest is really a no-brainer. I've only used it regularly for a few days now, but I can't see doing TDD in Java without it.





Thursday, June 25, 2009 
The Bowling Game

Sometimes the "toy" examples we build lead to something real. A few years ago, I wrote a 13-part article series for Informit, demonstrating TDD using the game of hold 'em poker. Shortly thereafter, I received a call from a company looking for Java developers to help them build an automated poker application for in-casino table. The pitch was that this would eliminate the need for costly human dealers; it would also speed up gameplay, allowing more hands and thus increasing the house's rake. Someone at the small startup had read my articles and figured I at least knew the domain!

That work never materialized. Today I received an email (probably broadcast to wide distribution) from a headhunter with an interesting need: "We’re looking for someone in DFW with C# and C++ development experience who loves to bowl! They will be creating software for the sport of bowling and should have an interest in OR knowledge of the sport…" Ha! I don't know that this is for an agile shop, but is there a hardcore agile developer out there who hasn't coded the bowling game at least once? I wonder if that qualifies. :-)

I'd alert Ron, but I'm sure he wouldn't consider moving to Dallas. Well, if you're interested, let me know and I'll forward the recruiter info. Or if you're looking for work in an agile shop elsewhere, check out the agile jobs list.





Wednesday, June 17, 2009 
Cute Little Abstractions

I'm refactoring several classes of over 2000 lines each. These are classic god-classes that mediate a handful of stubby little data-centric classes around them. I reduced the first, primary domain class by over 1100 lines, to under 1500, by simply pushing responsibilities around. Adding tests after the fact (using WELC techniques, of course) gave me the confidence to refactor. In just a few hours, I've been able to completely eliminate about 700 lines so far out of the 1100 that were shifted elsewhere. I'm loving it!

After cleaning up some really ugly code, I ended up with better (not great) code:

private boolean containsThreeOptionsSameType() {
   Map<String, Integer> types = new HashMap<String, Integer>();
   for (Option option : options)
      increment(types, option.getType());
   return count(types, Option.ALPHA) >= 3 || count(types, Option.BETA) >= 3
        || count(types, Option.GAMMA) >= 3 || count(types, Option.DELTA) >= 3;
}

private int count(Map<String, Integer> map, String key) {
   if (!map.containsKey(key))
      return 0;
   return map.get(key);
}

private void increment(Map<String, Integer> map, String key) {
   if (!map.containsKey(key))
      map.put(key, 1);
   else
      map.put(key, map.get(key) + 1);
}
I could clean up the complex conditional on the return statement (perhaps calling a method to loop through all types). Also, the count and increment methods contain a bit of duplication.

More importantly, the count and increment methods represent a missed abstraction. This is very common: We tend to leave little, impertinent, SRP-snubbing, OCP-violating methods lying about, cluttering up our classes.

(Aside: I'm often challenged during reviews about exposing things so I can test them. Long-term, entrenched developers are usually very good about blindly following the simple rule about making things as private as possible. But they're perfectly willing to throw OO concept #1, cohesion, completely out the window.)

I decided to test-drive the soon-to-be-no-longer-missing abstraction, CountingSet. I ended up with an improved implementation of increment by eliminating the redundancy I spotted above:

import java.util.*;

public class CountingSet<T> {
   private Map<T, Integer> map = new HashMap<T, Integer>();

   public int count(T key) {
      if (!map.containsKey(key))
         return 0;
      return map.get(key);
   }

   public void add(T key) {
      map.put(key, count(key) + 1);
   }
}
Some developers would be appalled: "You built a cruddy little class with just four lines of real code? And for only one client?" And further: "It's only a subset of a counting set, where are all the other methods?"

Sure thing, buddy. Here's my client:

private boolean containsThreeOptionsSameType() {
   CountingSet<String> types = new CountingSet<String>();
   for (Option option : options)
      types.add(option.getType());
   return types.count(Option.ALPHA) >= 3 || types.count(Option.BETA) >= 3
      || types.count(Option.GAMMA) >= 3 || types.count(Option.DELTA) >= 3;
}
My client now only contains intent. The small ugliness with the parameterized map and boxing is now "information hidden." I also have a simple reusable construct--I know I've had a similar need several times before. As for building and/or using a fully-functional CountingSet, there's something to be said for creating "adapter" classes with the smallest possible, and most meaningful, interface.

Good enough for now. Don't hesitate to create your own cute little abstractions!





Tuesday, June 09, 2009 
Eclipse Auto Insert

In Eclipse, I use Ctrl-1 and Ctrl-Space so much that the wear on those three keys is noticeably more than the others.

By default, adding a new (JUnit 4 style) test is a matter of typing "test," then hitting ctrl-space to bring up the appropriate code template. Problem is, Eclipse brings up a number of choices, and hitting enter requires ensuring the right thing is selected (it's not always in first position) and then pressing enter. I've lived with this so far and didn't think much about it until last night, when I created over 50 tests in a 90-minute session, and really resented the overhead.

I edited the template and figured checking the "Auto Insert" box would solve the problem. No dice--Eclipse presents other choices when I type "test," such as one that just inserts the lone @Test annotation. What if I rename the "test" code template to a unique name, like "tst?" No, I get a list with two things--my template, and an option to create a method stub whose name is "tst." No auto insert! I tried a couple other things, such as introducing a special character so that Eclipse would think it couldn't possibly create a method with that name. That didn't work (I don't recall specifically what happened).

I know auto insert works in Eclipse, because I can go into the body of a method, type "sysout" and then press Ctrl-space, and Eclipse auto-completes to "System.out.println()" immediately. It requires no selection on my part. This tells me that auto insert works only if there's one and only one possible selection. Unfortunately, it looks like that will never be the case outside a method but within the class (i.e. where one can create a "Java type member")--any template name could also represent the name for a new method stub.

Keystrokes, then, what about assigning keystrokes? Aha. In the General->Keys preference page, I filtered for "content assist." The choice named simply Content Assist is the one triggered by Ctrl-Space, but another choice is Content Assist (type: Template Proposals), by default assigned no keyboard shortcut. I assigned Ctrl-\ to content assist for template proposals. Now I just type "test" Ctrl-\ and I have my test method stub.

I didn't really want another key combination, mostly because I prefer to go by IDE defaults. My pairing sessions run me through a wide variety of development environments (at last count, within the past year or so, 10 different C++ editors and 3 different Java IDEs), so it's easiest to not create dependencies on my own personal reworking of the key mappings.

Ah well, I suppose there are a few key mappings I'll just have to remember to configure. This is the second one I will want universally for Eclipse; the other is Rerun JUnit Test.

My wish for Eclipse is improved pairing support. The simple idea: you make your key mappings available via a URI. The first time you pair with someone, you add this to Eclipse. From there, a universally defined keystroke allows you toggle through or select from the keymaps.





Wednesday, June 03, 2009 
Twitter Tracker
Conan O'Brien is the new king of late night! Of course that's a premature judgment, but so far I've watched most of both his shows, whereas I could usually only take about 5 minutes of Leno. Last night's Twitter Tracker segment promises to keep us all abreast of the dramatic power of this mushrooming fad. :-)


RSS Feed (XML)

Archives

February 2004   March 2004   May 2004   September 2004   October 2004   January 2005   February 2005   September 2005   October 2005   November 2005   December 2005   January 2006   February 2006   March 2006   June 2006   August 2006   January 2007   February 2007   March 2007   April 2007   September 2007   October 2007   November 2007   December 2007   January 2008   February 2008   March 2008   April 2008   May 2008   June 2008   July 2008   August 2008   September 2008   October 2008   November 2008   December 2008   January 2009   February 2009   March 2009   April 2009   June 2009   August 2009   December 2009   January 2010  

This page is powered by Blogger. Isn't yours?