Jeff's Blog

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


Monday, June 09, 2008 
Less Refactoring

If you could have only one refactoring, which would it be? Which refactoring could you least afford to give up?

To me the obvious answer is the rename refactoring. It's an activity that I do very frequently. In fact, the way I code is dependent upon my ability to do a rapid rename.

I try to follow Uncle Bob's mantra "never be blocked" at even the smallest granularities. I won't stew for more than a few seconds to derive a name for a class, field, method, or other identifier. Instead, I type. If my brain is really frozen, I'll surge forward by typing an "x" or the word "something." No worries--I usually think of a better name shortly thereafter. I then do a ctrl-1/rename, type the new name, press enter, and Eclipse completes the job for me very safely and quickly.

The name isn't final at that point. I'll continue to update an identifier's name as my understanding of what it represents gets refined (or changes).

Recently I committed myself to working more in-depth with Groovy. I'm happy with its improved simplicity, consistency, and expressiveness over the tedium that is Java. As always, I spent a while using Groovy's bare-bones tools (groovyc, groovyConsole, etc.) so that I understood them enough to survive if I had to. Done enough of that! Now I'm looking to my productivity experience by introducing an IDE, so I downloaded and installed the Groovy plugin for Eclipse.

Harumph, and that's even after ignoring (a) a couple bizarre errors that I received because I hadn't forced a clean and (b) the obtuseness of the exceptions. No, the big harumph is that there are no ctrl-1 or refactoring options anywhere to be found. I've heard IDEA is better (and hope to try it out here soon), but as I understand, the rename challenge will never be completely resolved: safe rename refactorings require type information. You can provide that in Groovy, but figure on most developers not bothering.

And for now, the Eclipse plugin isn't even trying. I created a private, typed field--something for which a refactoring operation could be very safe--but now I can't change its name without resorting to search/replace. The fact that I may need to discard my newer programming style of "continual rename" makes me feel dirty.

Even with some forethought, programmers will always choose some names that end up less than ideal. And since developers are notorious for not changing things that might break, the poor names will remain as long as the IDE can't do it safely. Maintenance costs will be higher.

The main point of my post is that after years of using a strongly-typed language, I am now resisting languages like Groovy and Ruby to an extent. Not because I'm worried about the defects that could happen at runtime that wouldn't otherwise-my use of TDD generally means that's not an issue. Instead, my complaint is about lack of productivity, and worse, the decreased amount of refactoring that will likely result.

The question is, do benefits accruing from the increased simplification of the code outweigh the negatives of more difficult refactoring?





Friday, May 23, 2008 
Opinions on Ubuntu Revisited

OK, Ubuntu is still pretty cool, but man, sound driver support is sad. My son, who purchased a SoundBlaster card for his machine, got his sound to work but could not get the microphone to work. I ended up in the same situation, except that I have an on-board Intel HDA sound processor.

The good thing is that lots and lots of people have posted on this topic. That's also the bad thing, because (a) lots and lots of people have similar problems and (b) the resolutions are all over the map. I tried everything recommended, including downloading the latest ALSA drivers, rebuilding, and reinstalling, at which point my sound refused to work at all. Several hours later, I got the sound to work (I found a better posting which properly covered the arguments to pass to the configure script before making) again. I tried a few more things, but my microphone still does not work (it works fine under Vista).

OK, so I'll have to boot into Windoze to use Skype. But otherwise, all else appears to be running well. Next up, I intend on exploring Wine to run a few of the rare Windows programs that are outstanding.

One of the nicer aspects was the ease of keeping Windows around, which I need for a few reasons. While the Vista partition manager sucked (it would not do what it claimed it could do with respect to shrinking my partition), the Ubuntu installation made that a breeze. An important note, though: The partition resizing operation showed no feedback for a couple hours, so I wasn't sure whether or not it was doing anything. I waited patiently, and was probably going to reboot in a few more minutes, but the app must have suspected my anxiety and finished promptly.

I can get at files from either side of the fence, meaning that I don't have to worry about redundancies between Vista and Ubuntu. From Ubuntu, you can see NTFS drives by default, although you have to activate the ability to change them to be writeable. Under Windows, a quick search revealed the existence of Explore2fs, a nice little utility that can read ext2 and ext3 file systems. Unfortunately, it looks to involve copying to local temp files, but it's better than nothing, and should cut down the number of reboots, particularly until I get everything settled in.

So Ubuntu is not going anywhere. Mentally, it's now my primary OS, and Windows is just here as a necessary evil. I'm satisfied.





Wednesday, May 21, 2008 
Ubuntu

I finally got up the energy to spend several hours cleaning and doing a reasonably full backup of my (inexpensive) laptop, which had shipped with Windows Vista. Glutton for punishment that I am, I figured it would be a good idea to learn enough about Vista to survive when working in a place where they happened to use it.

Well, it turns out that no one is using it, or at least no one really wants to use it, as far as I can see. And enough is enough--I learned what I need to know, which is that Vista adds almost nothing to the advancement of operating systems or the user experience, as far as I'm concerned.

So after backing up, I decided to load Ubuntu, which I'd previously installed the prior weekend on my son's machine. Tim's machine had been running Windows XP, but somehow got screwed up, at which point he realized he did not have a Windows install disk (and images were nowhere to be found on the machine). The experience was surprisingly better than my last attempts to install Red Hat or Debian--up and (mostly) running in less than an hour.

Still, it reminded me why Ubuntu is far from being something that I can recommend to anyone other than a computer geek. I thought Vista was annoying with its continual interruptions; at least it didn't require me to enter a password everytime I su'did something (maybe there's a way around it, and it had better not involve removing the password).

The bigger problem is that no one, except us of course, wants to muck with the command line. Having to deal with my son (who's not stupid and is on the computer all the time) who is frustrated over figuring out to configure his machine reminded me of that. Finding the right drivers, doing chmods as appropriate, sudoing things where necessary, and so on. God love it and 'em, Ubuntu is not for anyone but a geek. I'm glad I switched--Ubuntu is great, and I guess that makes me a true geek.





Monday, April 28, 2008 
Revisiting BDD in Java

My initial reaction a few years ago to BDD implementations in Java was less than stellar. Since then, I revisited them a couple times, and now I'm digging into them again. They're still around, so someone must be getting value out of them. I certainly have gotten some mileage around naming and organizing my tests in a more BDD fashion.

Right now, I'm being lazy, and haven't done diligent research. But my initial internet searches suggest that there are a handful of tools, none of them the de facto standard. I remember my doctor once saying, "We have about a hundred ways to treat this [a plantar wart]. Usually when there are so many ways, it means we don't know what we're doing."

I started looking at one framework in more depth, and coded some straightforward examples. Didn't seem so bad, until I looked to code a more involved assertion. Here's one (contrived but simple) example:

Ensure.that(name, and(contains("Langr"), startsWith("J")));

One of the core principles of BDD is "getting the words right." I think this example demonstrates that sometimes we try too hard, and perhaps this construct isn't a great idea for Java. The "classic" approach is easily more expressive:

assertTrue(name.contains("Langr") && name.startsWith("J"));
or better...
assertTrue(name.contains("Langr")
assertTrue(name.startsWith("J"));
or even...
assertFirstInitialAndLastName(name, "J", "Langr");
I suppose my complaint could be tempered with the fact that these kinds of compound assertions don't occur so frequently.

Yes, sure, the failure messages are better. That's not significant to me, given that I don't drive my development off of failure messages. Sure, all tests fail at least once, but I usually know why they're failing the first time, so I don't need that message initially. Later, when they fail for unknown reasons, more information might be useful (sometimes it is, not always), but if I need that, I just enhance the assertion I already have and rerun the tests. No big deal.

Writing custom "matchers" is also an example in ugliness, given the limitations of Java. (I need to speed up my move to Groovy or Ruby, so I can stop whining about Java so much...)

I won't give up on the Java BDD tools completely, but I'm not much happier now than I was three or so years ago.





Wednesday, April 23, 2008 
What's the Next Test?

I coded the "Roman numeral kata" for the first time last night. I thought it was a reasonably straightforward exercise, but then I looked at the solutions of others by searching the web.

In agile, there's this notion of "doing the simplest thing that could possibly work," and I think it applies to TDD just fine. It helps keep me in the red-green-refactor rhythm. More importantly, it prevents me from pre-building complexity. It also keeps me in a mode of extreme incrementalism: DSTTCPW keeps teaching me how to truly grow a system incrementally, as agile demands.

From looking at the solutions on the web, however, I suspect that some people translate "do the simplest thing" to "don't think at all." Specifically, I'm referring to their progression of tests. At all times, once I complete a single test method, I spend some time thinking about what the next test should be. I don't spend too much time, but nor do I blindly jump into the next apparently obvious test.

The task in the Roman numeral kata is to convert a positive integer to a Roman numeral. Doing this kata in a TDD fashion, the first test is converting 1 to I, which is a hard-coded return. The second test is converting 2 to II, which is simply done with an if statement. One might refactor at this step to a loop/count construct, or one might wait until 3 (III).

From 3, though, I noted that many of the coders insisted on jumping directly to 4 (IV). Certainly, this works, but most of the solutions I saw derived in this fashion either ended up more complex, or resulted in a fairly excessive solution that scaled back dramatically with some last-step refactoring.

One could argue that this is in the true spirit of incrementalism. After all, we should be able to tackle requirements in any order. Perhaps we need only support the numbers 1 through 4 initially, and later someone will insist on adding 5+.

An argument currently brewing on the XP list goes into the whole YAGNI thing, with one poster suggesting that if you have comprehensive information, there is nothing wrong with taking that into account. Kent Beck subsequently updated his take on YAGNI: "Here's what I do: consider [forthcoming feature] a little, but try not to get so caught up in it that I freeze."

In a similar fashion, TDD doesn't mean "don't think." Determining the next test to write should incorporate some thought about what represents the simpler path to a more complete solution. Sometimes this is a guess, but with more experience, the wiser choices are more apparent. Sometimes you make the wrong choice, but you can still end up in the right place, particularly if you refactor with diligence.

With respect to the Roman numeral solution, the better answer is, try 5 (V) before 4 (IV). Then add combinations of V and I (6, 7); then finalize this logic with X, which pretty much demands a table-driven solution.

A last intuitive leap can dramatically improve the solution, but is not essential: Table entries don't have to represent a single Roman letter. Thus you end up with an entry in the table for 4 (IV), 9 (IX), 40 (XL), 90 (XC), and so on. The logic stays clean and simple:

import java.util.*;

public class Roman {
  private final int number;
  private static final TreeMap<Integer, String> digits = new TreeMap<Integer, String>();
  {
     digits.put(1, "I");
     digits.put(4, "IV");
     digits.put(5, "V");
     digits.put(9, "IX");
     digits.put(10, "X");
     digits.put(40, "XL");
     digits.put(50, "L");
     digits.put(90, "XC");
     digits.put(100, "C");
     digits.put(400, "CD");
     digits.put(500, "D");
     digits.put(900, "CM");
     digits.put(1000, "M");
  }

  public Roman(int number) {
     this.number = number;
  }

  @Override
  public String toString() {
     StringBuilder roman = new StringBuilder();
     int remaining = number;
     for (Map.Entry<Integer,String> entry: digits.descendingMap().entrySet()) {
        int decimalDigit = entry.getKey();
        String romanDigit = entry.getValue();
        while (remaining >= decimalDigit) {
           roman.append(romanDigit);
           remaining -= decimalDigit;
        }
     }
     return roman.toString();
  }
}

If you don't make the intuitive leap, the final solution is a bit more muddy (as I saw in a few solutions out there). But you have a second chance: Since you have all those wonderful tests, you can refactor the heck out of your muddy solution, looking for a more concise expression, and often you'll find it.





Tuesday, April 08, 2008 
Clean Code

Uncle Bob Martin just completed a draft of Clean Code, which the publisher site lists as being available August 22, 2008. The book is a code-intensive collection of thoughts on how to keep, well, your code clean. I was honored to submit two chapters, one on "clean classes" and one on emergent design. Uncle Bob got the last word, putting in even more code than I'd laid out on these chapters.

Many of the chapters are contributions by other current-and-ex-Object Mentors, but Bob put in a significant effort to go through the compiled book as a whole, to make sure everything coheres well and put his personal stamp on it.

The announcement got me stoked again about writing. Developer.com is also looking to compile an e-book of my many articles on design patterns (most with a TDD bent), so look for that in the near future. Still, I think it's time I went back and started on a whole, real book of my own. The C++ tome is still a potential if Mr Koss and I can find mutual time together for it.





Thursday, April 03, 2008 
Open Source Pairing Scheduler

Rather than whine about not having enough good pairing experiences, I've decided to do something about it. Recently I've had a few pairing sessions online, and I decided that the software to build would start around the simple notion of scheduling online pairing sessions.

The idea is to slowly start building an online pairing community. I imagine there are many kinds of participants, people who want to:

  • build quality software via pairing and TDD
  • promote their services and ability to mentor via pairing
  • get some work done on a real product
  • get in touch with other members of the agile community
  • learn about either pairing or TDD
  • learn about the effectiveness of distributed pairing
  • learn a specific technology (Java, Rails, JMock, RSpec, etc.)
  • improve their Ward number for bragging purposes

I hope that the scheduler software will be all that and many more. Initially, I created a wiki (see http://jlangr.wiki.zoho.com/) as a scratch pad area, to help set up sessions, to hold an initial backlog of stories around the scheduler itself, and to record experiences.

I chose Java, but only because of interests in my pairing partner. I'm not sure that the pairing scheduler should be Java, but for now it is. If Java, what represents the best choice for front end (web) technologies?

Please feel welcome to join up and post your recommendations and experiences at the wiki site. Interested developers should send me an email with their intents, and I'll set up their SourceForge account to have appropriate access.



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  

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