<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:thr='http://purl.org/syndication/thread/1.0' version='2.0'><channel><atom:id>tag:blogger.com,1999:blog-6488575</atom:id><lastBuildDate>Mon, 10 May 2010 13:44:26 +0000</lastBuildDate><title>Jeff's Blog</title><description>Musings about software development, Java, OO, agile, life, whatever.</description><link>http://www.langrsoft.com/blog/blog.shtml</link><managingEditor>noreply@blogger.com (Jeff L.)</managingEditor><generator>Blogger</generator><openSearch:totalResults>129</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-8987653427445501937</guid><pubDate>Wed, 20 Jan 2010 16:36:00 +0000</pubDate><atom:updated>2010-01-20T09:36:19.587-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>test-driven development</category><category domain='http://www.blogger.com/atom/ns#'>TAD</category><category domain='http://www.blogger.com/atom/ns#'>TDD</category><title>Tradeoffs</title><description>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://www.langrsoft.com/blog/uploaded_images/tradeoffs-751776.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="178" src="http://www.langrsoft.com/blog/uploaded_images/tradeoffs-751774.jpg" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
This graph, intended to show the differences in outcome between TDD and not, is a sketch of my observations combined with information extrapolated from other people's anecdotes. One datapoint is backed by third party research: Studies show that it takes about 15% longer to produce an initial solution using TDD. Hence I show in the graph the increased amount of time under TDD to get to "done."
&lt;/p&gt;&lt;p&gt;
The tradeoff mentioned in the title is that TDD takes a little longer to get to "done" than code 'n' fix. It requires incremental creation of code that is sometimes replaced with incrementally better solutions, a process that often results in a smaller overall amount of code.
&lt;/p&gt;&lt;p&gt;
When doing TDD, the time spent to go from "done" to "done done" is minimal. When doing code 'n' fix, this time is an unknown. If you're a perfect coder, it is zero time! With some sadness, I must report that I've never encountered any perfect coders, and I know that I'm not one. Instead, my experience has shown that it almost always takes longer for the code 'n' fixers to get to "done done" than what they optimistically predict.
&lt;/p&gt;&lt;p&gt;
You'll note that I've depicted the overall amount of code in both graphs to be about the same. In a couple cases now, I've seen a team take a TDD mentality, apply legacy test-after techniques, and subsequently refactor a moderate-sized system. In both cases they drove the amount of production code down to less than half the original size, while at the same time regularly adding functionality. But test code is usually as large, if not a bit larger, than the production code. In both of these "legacy salvage" cases, the total amount of code ended up being more or less a wash. Of course, TDD provides a large bonus--it produces tests that verify, document, and allow further refactoring.
&lt;/p&gt;&lt;p&gt;
Again, this graph is just a rough representation of what I've observed. A research study might be useful for those people who insist on them.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-8987653427445501937?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2010/01/tradeoffs.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-9031186048165166010</guid><pubDate>Thu, 14 Jan 2010 04:38:00 +0000</pubDate><atom:updated>2010-01-13T22:19:52.636-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>IDE</category><category domain='http://www.blogger.com/atom/ns#'>pair programming</category><category domain='http://www.blogger.com/atom/ns#'>IDEA</category><category domain='http://www.blogger.com/atom/ns#'>Eclipse</category><category domain='http://www.blogger.com/atom/ns#'>pairing</category><title>Roaming Keymap Profiles</title><description>&lt;p&gt;When pairing, I often learn little shortcuts and tips that I might never pick up otherwise (even though I'm the compulsive sort who comprehensively &lt;em&gt;reads&lt;/em&gt; things like the entire list of commands, just to find some new trick). I try to impart at least as many tips as I take on. Pairing makes it happen, as there's little better than to have an insistent partner who keeps reminding you to "just hit Ctrl-Alt-v" (introduce variable in IDEA, an essential refactoring). In the absence of a pair, IDEA's Key Promoter plugin helps a bit.
&lt;/p&gt;&lt;p&gt;
As someone who pairs across many teams, I regularly encounter different IDEs and programmer editors. Usually teams standardize on one tool, but not long ago I worked in a C++ team where there were 8, count 'em, 8 different editors in play. Currently I am working with a team where some people are piloting Eclipse, while the rest of the team uses IDEA.
&lt;/p&gt;&lt;p&gt;
Give me a few minutes and I can ramp up OK, but switching IDEs throughout the day will make just about anyone feel stupid. Ctrl-d, duplicate line in IDEA. Switch to Eclipse, oops, Ctrl-d, I just deleted a line. Nope, it's Alt-Ctrl-Down to duplicate a line. Move a line up, Ctrl-Shift-Up in IDEA. Wait, though, I can't remember the Eclipse corollary, but I do have muscle memory, and so I now have to go try it... wait for me... it's Alt-Up. And so on.
&lt;/p&gt;&lt;p&gt;
Why don't I just change the keymaps so that they're more in synch with each other? Or why not use, say, a vi keymap everywhere? The problem is that I'm pairing with others, and so the simplest thing is to go along with the IDE defaults (which is what the predominance of programmers uses).
&lt;/p&gt;&lt;p&gt;
On my wish list and/or backlog of things to work on, I'd love it if IDEs would support a standardized roaming keymap protocol, as well as a simple mechanism for toggling profiles. I would be able to specify a URL from which the IDE would download my profile. From there on, a simple keystroke would toggle from the active keymap profile to mine and vice versa, in order to expedite pairing.
&lt;/p&gt;&lt;p&gt;
I've been hoping to see more support in IDEs for things like TDD and pairing. It's coming, albeit slowly. Any plugin fanatics out there who want to give this one a go?
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-9031186048165166010?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2010/01/roaming-keymap-profiles.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-4515477788791139111</guid><pubDate>Thu, 17 Dec 2009 02:56:00 +0000</pubDate><atom:updated>2009-12-16T20:55:23.730-07:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>agile</category><category domain='http://www.blogger.com/atom/ns#'>UML</category><category domain='http://www.blogger.com/atom/ns#'>design</category><category domain='http://www.blogger.com/atom/ns#'>class model</category><category domain='http://www.blogger.com/atom/ns#'>modeling</category><title>Framing Your Design</title><description>&lt;p&gt;A while back, I worked with a team in a cube bullpen to help mentor them primarily in test-driven development (TDD). Their goal was to deliver a decent-sized web product--not huge, not trivial.
&lt;/p&gt;&lt;p&gt;
The first time I paired with the programmer nearest the bullpen opening, I noticed a large framed document on a nearby cube wall, outside the bullpen, and asked what it was. All I could tell from that distance was that it was a highly detailed diagram of some sort.
&lt;/p&gt;&lt;p&gt;
I asked my pair about the document.&lt;br /&gt;
"It's our class model."&lt;br /&gt;
"How do you use it?"&lt;br /&gt;
"We don't. It's out of date."&lt;br /&gt;
Of course it was. We went back to building code.
&lt;/p&gt;&lt;p&gt;
When we took a break, I walked to the diagram. Sure enough, it was a UML class model--with gobs of detail. Public methods, attributes, private methods, annotations on the associations, attribute types, return types, and so on, all specified in what looked like a couple hundred classes. Arrows all over the place. As I previously mentioned, the document was framed (albeit cheaply), which meant that the model itself was enshrined in a protective layer of glass (plastic?).
&lt;/p&gt;&lt;p&gt;
The framed model sure looked pretty! And it no doubt looked quite impressive to any non-technical observer (such as a vice president): "They built all that!"
&lt;/p&gt;&lt;p&gt;
Of course, the team that actually produced the detailed model no longer found it useful. During the remainder of my engagement, I never once saw a developer look at the diagram. And most amusing, when I took my one visit to inspect the model, a closer look revealed that the programmers &lt;em&gt;had&lt;/em&gt; briefly attempted to keep the model up to date. On the surface of the glass, there were various scribbles and attempted modifications, all written directly on the glass.
&lt;/p&gt;&lt;p&gt;
Your software is special, but your design models are not, and they change rapidly. Don't enshrine your design.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-4515477788791139111?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/12/framing-your-design.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-4293284549414129112</guid><pubDate>Thu, 06 Aug 2009 13:55:00 +0000</pubDate><atom:updated>2009-08-06T08:31:37.898-06:00</atom:updated><title>NetBeans</title><description>&lt;p&gt;
I was very excited to start using &lt;a href="http://infinitest.org/"&gt;Infinitest&lt;/a&gt; once &lt;a href="http://www.langrsoft.com/blog/2009/06/infinitest.html"&gt;again&lt;/a&gt;. But as things seem to go with me, I ended up moving on to something else that dominated my mindshare--in this case, a new project where I am using NetBeans. Why NetBeans? Because someone set up the project to use Maven, and all I've heard is that NetBeans is magical when it comes to integrating with Maven (and Eclipse, not so much).
&lt;/p&gt;&lt;p&gt;
As I would expect, both Maven and Maven support in NetBeans are really nice as long as they're working well. But Maven seems to adhere to the 80/20 rule. It's great 80% of the time, up until you have to do something a little out of the ordinary, or when things aren't working like they're supposed to. Then the numbers reverse--you spend 80% of your time trying to work on the remaining 20%. In the case of Maven, I'm struggling with getting coverage reports against multiple modules, and it's also presenting me with a defect (operator error?) where NetBeans reports half the Maven modules as "badly formed Maven projects." Google searches, and assistance from others with more Maven experience than me, have not been very fruitful.
&lt;/p&gt;&lt;p&gt;
This is the third time I've used Maven, and I'm warming up to it more each time, but it's still been a frustration. Part of frustration is always lack of knowledge, particularly around the behind-the-scenes workings that you need to know when you hit the 20% esoterica. Thanks to those who have helped!
&lt;/p&gt;&lt;p&gt;
On the other hand, this is also the third time I've used NetBeans heavily. I'm not really warming to it much. Granted, part of my disappointment with NetBeans is the same problem. The best way to learn not to hate something is to pair with someone who knows it well, and I've not been able to get much pairing time.
&lt;/p&gt;&lt;p&gt;Other than the Maven support, NetBeans seems much weaker than Eclipse. It's slower (e.g. a Ctrl-O to search for types takes many seconds to return class names, compared to Eclipse's Ctrl-Shift-t which is almost immediate). It's flakier (e.g. half the time, ctrl-F6 to run a test pops up its JUnit GUI, the other half the time I see only the console output; also, the formatting mechanism appears to be broken). It seems to be the last of the three main Java IDEs for which people write plugins (e.g. Infinitest is only available for Eclipse and IDEA, not NetBeans). And it's just missing key important things (e.g. there is no inline method refactoring until NetBeans 7.0).
&lt;/p&gt;&lt;p&gt;
I can live without every last bell and whistle. But it's always disappointing to see other people whistle in cool little ways, like Kerievsky's &lt;a href="http://tech.groups.yahoo.com/group/refactoring/message/10102"&gt;nice trick with inline method&lt;/a&gt;, and not get to play along.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-4293284549414129112?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/08/netbeans.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-6942786480210376840</guid><pubDate>Thu, 06 Aug 2009 13:34:00 +0000</pubDate><atom:updated>2009-08-06T07:50:39.948-06:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>SRP</category><category domain='http://www.blogger.com/atom/ns#'>agile</category><category domain='http://www.blogger.com/atom/ns#'>TimerTask</category><category domain='http://www.blogger.com/atom/ns#'>Java</category><category domain='http://www.blogger.com/atom/ns#'>single responsibility principle</category><category domain='http://www.blogger.com/atom/ns#'>Timer</category><category domain='http://www.blogger.com/atom/ns#'>mockito</category><category domain='http://www.blogger.com/atom/ns#'>TDD</category><title>Easier Testing Using the SRP</title><description>&lt;p&gt;
This simple file monitor class notifies listeners when a watched file is modified:
&lt;/p&gt;&lt;pre&gt;
public class FileMonitor {
 private Set&amp;lt;FileChangeListener&amp;gt; listeners =
    new HashSet&amp;lt;FileChangeListener&amp;gt;();
 private int duration;
 private File file;
 private long lastModified;

 public FileMonitor(String filename, int duration) {
     this.file = new File(filename);
     lastModified = file.lastModified();
     this.duration = duration;
 }

 public void start() {
     boolean isDaemon = true;
     long initialDelay = duration;
     new Timer(isDaemon).schedule(
        new FileMonitorTask(), initialDelay, duration);
 }

 public void addListener(FileChangeListener listener) {
     listeners.add(listener);
 }

 class FileMonitorTask extends TimerTask {
     @Override
     public void run() {
         if (file.lastModified() &amp;gt; lastModified) {
             lastModified = file.lastModified();
             for (FileChangeListener listener: listeners) {
                 listener.modified();
             }
         }
     }
 }
}
&lt;/pre&gt;
&lt;p&gt;A FileMonitor schedules a TimerTask that just checks the modified date from time to time, and compares it to the last modified date. The code above seems like a typical and reasonable implementation. FileMonitorTask could be an anonymous inner class, of course.
&lt;/p&gt;&lt;p&gt;
I spent more time than I would have preferred test-driving this solution, since I made the mistake of test-driving it as a single unit. These tests had to deal with the vagaries of threading due to the Timer scheduling.
&lt;/p&gt;&lt;pre&gt;
import java.io.*;
import java.util.*;
import org.junit.*;
import static org.junit.Assert.*;

public class FileMonitorTest {
 private static final String FILENAME = "FileMonitorTest.properties";
 private static final int MONITOR_DURATION = 1;
 private static final int TIMEOUT = 50;
 private FileMonitor monitor;
 private File file;
 private List&amp;lt;FileChangeListener&amp;gt; fileChangeNotifications;
 private Thread waitThread;

 @Before
 public void initializeListenerCounter() {
     fileChangeNotifications = new ArrayList&amp;lt;FileChangeListener&amp;gt;();
 }

 @Before
 public void createFileAndMonitor() throws IOException {
     FileUtils.writeFile(FILENAME, "property=originalValue");
     file = new File(FILENAME);
     monitor = new FileMonitor(FILENAME, MONITOR_DURATION);
 }

 @After
 public void deleteFile() {
     FileUtils.deleteIfExists(FILENAME);
 }

 @Test
 public void shouldNotifyWhenFileModified() throws Exception {
     monitor.addListener(createCountingFileChangeListener());
     waitForFileChangeNotifications(1);

     monitor.start();

     alterFileToChangeLastModified();
     joinWaitThread();
     assertEquals(1, numberOfFileChangeNotifications());
 }

 @Test
 public void shouldSupportMultipleListeners() throws Exception {
     monitor.addListener(createCountingFileChangeListener());
     monitor.addListener(createCountingFileChangeListener());
     waitForFileChangeNotifications(2);

     monitor.start();

     alterFileToChangeLastModified();
     joinWaitThread();
     assertEquals(2, numberOfFileChangeNotifications());
     assertAllListenersDistinctlyNotified();
 }

 @Test
 public void shouldOnlyReportOnceForSingleModification()
         throws InterruptedException {
     // slow--must wait on timeout. Better way?
     monitor.addListener(createCountingFileChangeListener());
     waitForFileChangeNotifications(2);

     monitor.start();

     alterFileToChangeLastModified();

     joinWaitThread();
     assertEquals(1, numberOfFileChangeNotifications());
 }

 @Test
 public void shouldReportMultipleTimesForMultipleModification()
     throws InterruptedException {
     monitor.addListener(createCountingFileChangeListener());
     waitForFileChangeNotifications(1);

     monitor.start();

     alterFileToChangeLastModified();
     joinWaitThread();

     waitForFileChangeNotifications(2);
     alterFileToChangeLastModified();
     joinWaitThread();

     assertEquals(2, numberOfFileChangeNotifications());
 }

 private FileChangeListener createCountingFileChangeListener() {
     return new FileChangeListener() {
         @Override
         public void modified() {
             fileChangeNotifications.add(this);
         }
     };
 }

 private int numberOfFileChangeNotifications() {
     return fileChangeNotifications.size();
 }

 private void waitForFileChangeNotifications(final int expected) {
     waitThread = new Thread(new Runnable() {
         @Override
         public void run() {
             while (numberOfFileChangeNotifications() != expected) {
                 sleep(1);
             }
         }
     });
     waitThread.start();
 }

 private void sleep(int ms) {
     try {
         Thread.sleep(ms);
     } catch (InterruptedException exception) {
         fail(exception.getMessage());
     }
 }

 private void alterFileToChangeLastModified() {
     file.setLastModified(file.lastModified() + 1000);
 }

 private void joinWaitThread() throws InterruptedException {
     waitThread.join(TIMEOUT);
 }

 private void assertAllListenersDistinctlyNotified() {
     Set&amp;lt;FileChangeListener&amp;gt; notifications =
         new HashSet&amp;lt;FileChangeListener&amp;gt;(
);
     notifications.addAll(fileChangeNotifications);
     assertEquals(fileChangeNotifications.size(), notifications.size());
 }
}
&lt;/pre&gt;
&lt;p&gt;
Wow, that's a bit longer than I would have hoped. Yes, there are better ways to test the threading. And there may be better threading mechanisms to implement the monitor, although I think the Timer is pretty simple. I don't do enough threading, so I usually code a "familiar" solution (i.e. something I already know well) initially, and then refactor into a more expressive and concise solution.
&lt;/p&gt;&lt;p&gt;
I'm pretty sure this test is flawed. But rather than invest in fixing it, I reconsidered my design (by virtue of wanting an easier way to test it). The SUT is really two classes, the monitor and the task. Each one can easily be tested separately, in isolation, as a &lt;em&gt;unit&lt;/em&gt;. Sure, I want to see the threading in action, but perhaps that's better relegated to an integration test (which might also double as an acceptance test).
&lt;/p&gt;&lt;p&gt;
I decided to change the solution to accommodate more focused and more robust tests. The file monitor tests are pretty much what was there before (with some small additional refactorings), except that there's now no concern over threading--I just test the run method:
&lt;/p&gt;&lt;pre&gt;
import java.io.*;
import org.junit.*;
import static org.mockito.Mockito.*;
import org.mockito.*;

public class FileMonitor_TaskTest {
 private static final String FILENAME = "FileMonitorTest.properties";
 private FileMonitor.Task task = new FileMonitor.Task(FILENAME);
 @Mock
 private FileChangeListener listener;

 @Before
 public void initializeMockito() {
     MockitoAnnotations.initMocks(this);
 }

 @BeforeClass
 public static void createFile() throws IOException {
     FileUtils.writeFile(FILENAME, "property=originalValue");
 }

 @AfterClass
 public static void deleteFile() {
     FileUtils.deleteIfExists(FILENAME);
 }

 @Before
 public void createTask() {
     task = new FileMonitor.Task(FILENAME);
 }

 @Test
 public void shouldNotNotifyWhenFileNotModified() {
     task.addListener(listener);
     task.run();
     verify(listener, never()).modified();
 }

 @Test
 public void shouldNotifyWhenFileModified() throws Exception {
     task.addListener(listener);
     changeFileLastModifiedTime();

     task.run();

     verify(listener, times(1)).modified();
 }

 @Test
 public void shouldSupportMultipleListeners() throws Exception {
     task.addListener(listener);
     FileChangeListener secondListener = mock(FileChangeListener.class);
     task.addListener(secondListener);

     changeFileLastModifiedTime();
     task.run();

     verify(listener, times(1)).modified();
     verify(secondListener, times(1)).modified();
 }

 @Test
 public void shouldOnlyReportOnceForSingleModification() throws InterruptedException {
     task.addListener(listener);

     task.run();
     changeFileLastModifiedTime();
     task.run();
     task.run();

     verify(listener, times(1)).modified();
 }

 @Test
 public void shouldReportMultipleTimesForMultipleModification() throws InterruptedException {
     task.addListener(listener);

     task.run();
     changeFileLastModifiedTime();
     task.run();
     changeFileLastModifiedTime();
     task.run();

     verify(listener, times(2)).modified();
 }

 private void changeFileLastModifiedTime() {
     File file = new File(FILENAME);
     file.setLastModified(file.lastModified() + 1000);
 }
}
&lt;/pre&gt;
&lt;p&gt;I introduced &lt;a href="http://mockito.org/"&gt;Mockito&lt;/a&gt; to provide a simple  verifying stub for the listener. I suppose I should also stub out interactions with File, but I'll incur the speed penalty for now.
&lt;/p&gt;&lt;p&gt;
Next, I needed to test the remaining FileMonitor code. To do this involved proving that it creates and schedules a task appropriately using a timer, and that it handles listeners appropriately.
&lt;/p&gt;&lt;pre&gt;
import xxx.CollectionUtil;
import java.util.Timer;
import org.junit.*;
import org.mockito.*;
import static org.mockito.Mockito.*;

public class FileMonitorTest {
 @Mock
 private Timer timer;

 @Before
 public void initializeMockito() {
     MockitoAnnotations.initMocks(this);
 }

 @Test
 public void shouldScheduleTimerWhenStarted() {
     String filename = "filename";
     long duration = 10;
     FileMonitor monitor = new FileMonitor(filename, duration) {
         @Override
         protected Timer createTimer() {
             return timer;
         }
     };
     monitor.start();
     verify(timer).schedule(any(FileMonitor.Task.class), eq(duration), eq(duration));
 }

 @Test
 public void shouldDelegateListenersToTask() {
     FileChangeListener listener = mock(FileChangeListener.class);
     FileMonitor monitor = new FileMonitor("", 0);
     monitor.addListener(listener);

     CollectionUtil.assertContains(monitor.getTask().getListeners(), listener);
 }
}

&lt;/pre&gt;
&lt;p&gt;
The design of the production code had to change based on my interest in better
tests. A number of small, incremental refactoring steps led me to this solution:
&lt;/p&gt;&lt;pre&gt;
import java.io.*;
import java.util.*;

public class FileMonitor {
 private final long duration;
 private Task task;

 public FileMonitor(String filename, long durationInMs) {
     task = new Task(filename);
     this.duration = durationInMs;
 }

 public void start() {
     long initialDelay = duration;
     createTimer().schedule(task, initialDelay, duration);
 }

 protected Timer createTimer() {
     final boolean isDaemon = true;
     return new Timer(isDaemon);
 }

 Task getTask() {
     return task;
 }

 public void addListener(FileChangeListener listener) {
     task.addListener(listener);
 }

 static class Task extends TimerTask {
     private final File file;
     private long lastModified;
     private Set&amp;lt;FileChangeListener&amp;gt; listeners = new HashSet&amp;lt;FileChangeListener&amp;gt;();

     Task(String filename) {
         this.file = new File(filename);
         lastModified = file.lastModified();
     }

     public void addListener(FileChangeListener listener) {
         listeners.add(listener);
     }

     Set&amp;lt;FileChangeListener&amp;gt; getListeners() {
         return listeners;
     }

     @Override
     public void run() {
         if (file.lastModified() &amp;gt; lastModified) {
             lastModified = file.lastModified();
             for (FileChangeListener listener: listeners) {
                 listener.modified();
             }
         }
     }
 }
}
&lt;/pre&gt;
&lt;p&gt;
Well, most interestingly, I no longer have any tests that must deal with additional threads. I test that the monitor delegates appropriately, and I test that the task works properly when run. I still &lt;em&gt;want&lt;/em&gt; the integration tests, but I think they can be relegated to a higher, acceptance level test for the story:
&lt;/p&gt;&lt;pre&gt;
reload properties at runtime
&lt;/pre&gt;
&lt;p&gt;Otherwise, at this point, I have a high level of confidence in my code. I know the Timer class works, and I know my two classes work, and I've also demonstrated to myself that they all work together. I'm ready to move on.
&lt;/p&gt;&lt;p&gt;
Some additional relevant points:
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Threading is tough to get right, and it can be even tougher to test it.&lt;/li&gt;
&lt;li&gt;My final solution is a few more lines of code due to supporting my interest in more focused testing. I'm ok with the additional code because of the flexibility having the tests gives me, and more often than not, having them allows me to easily eliminate duplication elsewhere.&lt;/li&gt;
&lt;li&gt;It's hard to be overdo the SRP. Far more classes than not weigh in the wrong direction of too many responsibilities.&lt;/li&gt;
&lt;li&gt;The original solution, probably fine otherwise, is what you might expect from someone uninterested in TDD. It works (I think) but it represents rigid code, code that is more costly to change.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-6942786480210376840?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/08/easier-testing-using-srp.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-8069754420216557707</guid><pubDate>Mon, 29 Jun 2009 17:21:00 +0000</pubDate><atom:updated>2009-06-29T11:52:19.009-06:00</atom:updated><title>Infinitest</title><description>&lt;p&gt;I recently re-downloaded Ben Rady's &lt;a href="http://infinitest.org/"&gt;Infinitest&lt;/a&gt;, having finally gotten back into some extended Java development work. Infinitest runs tests continually, so that you need not remember to proactively run them.
&lt;/p&gt;&lt;p&gt;
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.
&lt;/p&gt;&lt;p&gt;
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.
&lt;/p&gt;&lt;p&gt;
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.
&lt;/p&gt;&lt;p&gt;
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.
&lt;/p&gt;&lt;p&gt;
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.
&lt;/p&gt;&lt;p&gt;
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.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-8069754420216557707?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/06/infinitest.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-1985897497069440394</guid><pubDate>Fri, 26 Jun 2009 03:19:00 +0000</pubDate><atom:updated>2009-06-25T21:38:35.374-06:00</atom:updated><title>The Bowling Game</title><description>&lt;p&gt;Sometimes the "toy" examples we build lead to something real. A few years ago, I wrote a 13-part &lt;a href="http://www.informit.com/articles/article.aspx?p=434428"&gt;article series&lt;/a&gt; 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!
&lt;/p&gt;&lt;p&gt;
That work never materialized. Today I received an email (probably broadcast to wide distribution) from a headhunter with an interesting need: &lt;em&gt;"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…"&lt;/em&gt; 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 &lt;a href="http://www.objectmentor.com/resources/articles/xpepisode.htm"&gt;the bowling game&lt;/a&gt; at least once? I wonder if that qualifies. :-)
&lt;/p&gt;&lt;p&gt;
I'd alert &lt;a href="http://xprogramming.com/xpmag/miningbowling.htm"&gt;Ron&lt;/a&gt;, but I'm sure he wouldn't consider moving to Dallas. Well, if &lt;em&gt;you're&lt;/em&gt; 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 &lt;a href="http://groups.yahoo.com/group/agile-jobs"&gt;agile jobs&lt;/a&gt; list.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-1985897497069440394?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/06/bowling-game.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>4</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-5110278528634624977</guid><pubDate>Wed, 17 Jun 2009 20:56:00 +0000</pubDate><atom:updated>2009-06-17T15:49:09.904-06:00</atom:updated><title>Cute Little Abstractions</title><description>&lt;p&gt;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 &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0131177052/langrsoftware-20"&gt;WELC&lt;/a&gt; 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!
&lt;/p&gt;&lt;p&gt;
After cleaning up some &lt;em&gt;really&lt;/em&gt; ugly code, I ended up with better (not great) code:
&lt;/p&gt;&lt;pre&gt;
private boolean containsThreeOptionsSameType() {
   Map&amp;lt;String, Integer&amp;gt; types = new HashMap&amp;lt;String, Integer&amp;gt;();
   for (Option option : options)
      increment(types, option.getType());
   return count(types, Option.ALPHA) &amp;gt;= 3 || count(types, Option.BETA) &amp;gt;= 3
        || count(types, Option.GAMMA) &amp;gt;= 3 || count(types, Option.DELTA) &amp;gt;= 3;
}

private int count(Map&amp;lt;String, Integer&amp;gt; map, String key) {
   if (!map.containsKey(key))
      return 0;
   return map.get(key);
}

private void increment(Map&amp;lt;String, Integer&amp;gt; map, String key) {
   if (!map.containsKey(key))
      map.put(key, 1);
   else
      map.put(key, map.get(key) + 1);
}
&lt;/pre&gt;
I could clean up the complex conditional on the &lt;code&gt;return&lt;/code&gt; statement (perhaps calling a method to loop through all types). Also, the &lt;code&gt;count&lt;/code&gt; and &lt;code&gt;increment&lt;/code&gt; methods contain a bit of duplication.
&lt;p&gt;
More importantly, the &lt;code&gt;count&lt;/code&gt; and &lt;code&gt;increment&lt;/code&gt; 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.
&lt;/p&gt;&lt;p&gt;
(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.)
&lt;/p&gt;&lt;p&gt;
I decided to test-drive the soon-to-be-no-longer-missing abstraction, CountingSet. I ended up with an improved implementation of &lt;code&gt;increment&lt;/code&gt; by eliminating the redundancy I spotted above:
&lt;/p&gt;&lt;pre&gt;
import java.util.*;

public class CountingSet&amp;lt;T&amp;gt; {
   private Map&amp;lt;T, Integer&amp;gt; map = new HashMap&amp;lt;T, Integer&amp;gt;();

   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);
   }
}
&lt;/pre&gt;
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?"
&lt;p&gt;
Sure thing, buddy. Here's my client:
&lt;/p&gt;&lt;pre&gt;
private boolean containsThreeOptionsSameType() {
   CountingSet&amp;lt;String&amp;gt; types = new CountingSet&amp;lt;String&amp;gt;();
   for (Option option : options)
      types.add(option.getType());
   return types.count(Option.ALPHA) &amp;gt;= 3 || types.count(Option.BETA) &amp;gt;= 3
      || types.count(Option.GAMMA) &amp;gt;= 3 || types.count(Option.DELTA) &amp;gt;= 3;
}
&lt;/pre&gt;
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.
&lt;p&gt;
Good enough for now. Don't hesitate to create your own cute little abstractions!
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-5110278528634624977?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/06/cute-little-abstractions.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-7776780692953093994</guid><pubDate>Tue, 09 Jun 2009 13:56:00 +0000</pubDate><atom:updated>2009-06-09T13:28:18.727-06:00</atom:updated><title>Eclipse Auto Insert</title><description>&lt;p&gt;In Eclipse, I use Ctrl-1 and Ctrl-Space so much that the wear on those three keys is noticeably more than the others.
&lt;/p&gt;&lt;p&gt;
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.
&lt;/p&gt;&lt;p&gt;
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).
&lt;/p&gt;&lt;p&gt;
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.
&lt;/p&gt;&lt;p&gt;
Keystrokes, then, what about assigning keystrokes? Aha. In the General-&gt;Keys preference page, I filtered for "content assist." The choice named simply &lt;b&gt;Content Assist&lt;/b&gt; is the one triggered by Ctrl-Space, but another choice is &lt;b&gt;Content Assist (type: Template Proposals)&lt;/b&gt;, 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.
&lt;/p&gt;&lt;p&gt;
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.
&lt;/p&gt;&lt;p&gt;
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.
&lt;/p&gt;&lt;p&gt;
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.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-7776780692953093994?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/06/eclipse-auto-insert.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>6</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-1154795274334545126</guid><pubDate>Wed, 03 Jun 2009 13:43:00 +0000</pubDate><atom:updated>2009-06-03T08:00:27.858-06:00</atom:updated><title>Twitter Tracker</title><description>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 &lt;a href="http://www.tonightshowwithconanobrien.com/video/#mea=1116881"&gt;Twitter Tracker&lt;/a&gt; segment promises to keep us all abreast of the dramatic power of this mushrooming fad.

:-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-1154795274334545126?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/06/twitter-tracker.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-4120938219522315965</guid><pubDate>Thu, 30 Apr 2009 13:00:00 +0000</pubDate><atom:updated>2009-04-30T07:54:04.724-06:00</atom:updated><title>ScrumAlliance (tm)</title><description>&lt;p&gt;
On the scrumdevelopment Yahoo! group, a discussion revolves around &lt;a href="http://orlandoscrum.org/blog/2009/04/29/orlando-scrum-rip-scrum-alliance-service-marks-scrum-user-group-wants-license-agreements-from-groups/"&gt;user group concerns&lt;/a&gt; over the trademarking of the phrase "Sc*um User Group." (Note that I've starred the name in order to avoid trademark violations.) A few inquiries resulted in an &lt;a href="http://groups.yahoo.com/group/scrumdevelopment/message/38213"&gt;official response&lt;/a&gt; from a Sc*umAlliance representative.
&lt;/p&gt;
&lt;p&gt;
I find it odd that (a) no one belonging to the "Sc*umAlliance" (whoever they really are--I'm suspecting maybe Mars, but given their legal nature, maybe Uranus) frequents the scrumdevelopment group, (b) none of them chose to respond directly on the group once apprised of the concerns, and (c) Ken Schwaber didn't have an immediate answer (regardless of his affiliation with the Sc*umAlliance). I suppose there must be people (lawyers, no doubt) who don't have to be at all interested in the product they support, but it just seems wrong somehow.
&lt;/p&gt;
&lt;p&gt;
Agile requires lots of communication and continual negotiation. Bits of command and control have their value at times, but in most cases C&amp;amp;C begins to eat away at the trust relationship required for continual negotiation. I suggest people considering or doing Sc*um dispense with the trappings of a trademarked process and look instead to understanding what agile is really about.
&lt;/p&gt;
&lt;p&gt;
The progenitors of agile--i.e. the &lt;a href="http://agilemanifesto.org/history.html"&gt;agile manifesto&lt;/a&gt; signatories--rightly eschewed "heavyweight" processes--processes centered around lots of documentation and meetings. I think there's a new category of "heavy" that should be spurned, and that includes processes controlled by people so heavily wrapped up in legal and licensing protections that they can't bother discussing changes with the community who would be affected.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-4120938219522315965?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/04/scrumalliance-tm.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-4724958434650791810</guid><pubDate>Wed, 01 Apr 2009 16:16:00 +0000</pubDate><atom:updated>2009-04-01T10:29:11.582-06:00</atom:updated><title>Unit Testing Maturity Scale</title><description>&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Level 0 - Not Performed&lt;/b&gt;: Tests? We don't need no stinkin' tests!&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Level 1 - Performed Informally&lt;/b&gt;: Test-after development (TAD). Sporadic coverage, individual-level process adherence.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Level 2 - TDD&lt;/b&gt;:
&lt;ul&gt;
&lt;li&gt;TDD Level 0: Chaotic. Some developers do TDD. Others don't care if the tests break.&lt;/li&gt;
&lt;li&gt;TDD Level A: Performed Informally. The team agrees that unit tests must pass in the build. Developers pick and choose what should be test-driven.&lt;/li&gt;
&lt;li&gt;TDD Level B: Performed Consistently. All team members build unit tests. Some unit tests are not focused enough (tendency toward integration tests). Tests do not "document" very well. Sporadic production code refactoring enabled as a benefit of having tests.&lt;/li&gt;
&lt;li&gt;TDD Level C: Breakthrough. Team members use each TDD cycle to refactor production code and tests, but constrain to single classes (test+target). Most tests clearly document class capabilities.&lt;/li&gt;
&lt;li&gt;TDD Level D: Optimizing. Standards around test organization, naming, and structure are evident from the code. BDD in heavy use. Team actively looks for reuse across tests, and continually refactors "mother" and other test utility classes.&lt;/li&gt;

&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;
This is a work in progress! Please help me iteratively and incrementally improve it.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-4724958434650791810?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/04/unit-testing-maturity-scale.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-6033168323422976140</guid><pubDate>Mon, 30 Mar 2009 16:29:00 +0000</pubDate><atom:updated>2009-03-30T10:54:54.128-06:00</atom:updated><title>On Email Lists and Advocacy</title><description>&lt;p&gt;
I try to keep up with all of the various agile "Yahoo! Group" lists: extremeprogramming, scrumdevelopment, refactoring, testdrivendevelopment, agile-testing, and so on. I post once in a while when I see a topic I feel qualified to respond to or that I'm passionate about. Lately I've been getting a lot less value out of these lists, some of which I've been following for ten years.
&lt;/p&gt;&lt;p&gt;
Many of the lists degrade into passionate statements of position, i.e. advocacy. Inevitably, people get burnt. Tempers flare, people get upset, some stomp their feet, some &lt;a href="http://tech.groups.yahoo.com/group/agile-testing/message/16646"&gt;simply withdraw&lt;/a&gt;. I myself have gotten burnt on this same list, feeling that someone (probably not coincidentally, the same person who is withdrawing now) was looking to simply piece apart every single word written to find as much fault as possible with it.
&lt;/p&gt;&lt;p&gt;
I withdrew completely from that discussion. I've also withdrawn from perhaps a couple other difficult discussions (out of the hundreds I've engaged in over the years). Sometimes it's because I felt the environment was too hostile, and I justified it to myself by thinking that the individuals involved were being immature or offensive or whatever. But that's not courage speaking. I looked back at my most recent example and regretted how I handled it. Withdrawing didn't solve anything.
&lt;/p&gt;&lt;p&gt;
Sometimes a simple statement, meant to be innocuous by who wrote it, is taken as a stab and affront. We can pout and take our toys and go home, but that's not at all useful or commendable. Courage can help us find a way to face the challenge and learn how to get past the issue. We don't have to agree with everyone or get along with them, but sometimes a sour incident can lead to a valuable relationship.
&lt;/p&gt;&lt;p&gt;
So how is this at all relevant to anything? Well, if we are to succeed, agile software development requires that we face challenges and not bury them in isolated cubes. Similar clashes occur not only on email lists, but in real life, and we're particularly going to see such clashes more frequently in highly collaborative teams. Conflicts that are not handled properly will detract from a team's ability to deliver. The XP value of courage is still essential to learning how to regularly deliver quality software.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-6033168323422976140?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/03/on-email-lists-and-advocacy.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-7473690133653486770</guid><pubDate>Thu, 26 Mar 2009 16:44:00 +0000</pubDate><atom:updated>2009-03-26T11:12:30.726-06:00</atom:updated><title>Trailing the Way in 2009</title><description>&lt;p&gt;
I started reading a very recently published book. I don't want to mention the name of the book, but it is a tome targeted at "application developers." After reading a small number of paragraphs from the book, I had to check my calendar to see whether this was 2009 or 1995.
&lt;/p&gt;&lt;p&gt;
Some choice sentences from the book that just grabbed me right off the bat:
&lt;ul&gt;
&lt;li&gt;"Software applications should simulate (model) the real world with close affinity to the problem domain."&lt;/li&gt;
&lt;li&gt;"...the average developer should spend 40 to 50 percent of his or her time in design and not writing code."&lt;/li&gt;
&lt;li&gt;"Similar to comments and &lt;b&gt;just as important&lt;/b&gt; &lt;em&gt;[emphasis added]&lt;/em&gt;, the design documents a program."&lt;/li&gt;
&lt;li&gt;"An artist does not start with a paintbrush and a canvas. There is considerable preparation before painting can begin. ... Similarly, developers do not simply start writing code. The requirements analysis must be undertaken, a design drafted, the &lt;b&gt;prototyping&lt;/b&gt; &lt;em&gt;[emphasis added]&lt;/em&gt; of class operations, and only then, finally, the implementation."&lt;/li&gt;
&lt;li&gt;"The goal of TDD is simply to be a framework for addressing customer requirements with software through an iterative approach to testing and coding." &lt;/li&gt;
&lt;/ul&gt;
[ All told, the author uses around 10 paragraphs in the book to describe TDD, not providing a single example. ]
&lt;/p&gt;&lt;p&gt;
For me, one of the most illuminating benefits of all this up-front emphasis on design seemed to be realized in the brilliant class diagram for a simple retail banking system. It looks something like:
&lt;/p&gt;
&lt;pre&gt;
  Employee &lt;|---- Teller  &lt;------  Customer
              |
              |-- Manager
&lt;/pre&gt;
&lt;p&gt;
The power of the "real world" comes alive! This ingenious class diagram existed to support building the following code:
&lt;/p&gt;
&lt;pre&gt;
static void Main(string[] args)
{
    Customer cust = new Customer();
    cust.Teller = new Teller();
    cust.Deposit();
    cust.Withdrawal();
}
&lt;/pre&gt;
&lt;p&gt;
Per the author, this code "validates" the design.
&lt;/p&gt;&lt;p&gt;
I'm speechless. (Well, no, I'm fingerless, or something. There must be a better word for being so flabbergasted that you can't start to &lt;em&gt;type&lt;/em&gt; a response.) I could rail on this book to no end, but it would only draw attention to the book (and you'll note that I'm not providing a link to it either).
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-7473690133653486770?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/03/trailing-way-in-2009.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-7014190343184352543</guid><pubDate>Thu, 26 Mar 2009 15:14:00 +0000</pubDate><atom:updated>2009-03-26T11:13:50.698-06:00</atom:updated><title>Reviewing TAD</title><description>&lt;p&gt;
I've recently participated in a number of after-the-fact code reviews. Developers are supposed to be writing tests first, and are supposed to ask for help when they're not sure how to do so. Here's what it looks like:
&lt;/p&gt;&lt;pre&gt;
C = one unit of time spent coding
T = one unit of time spent testing
I =  "    "   "   "    "   in an inspection or review meeting
R =  "    "   "   "    "   doing rework based on results of review
x =  "    "   "   "    "   doing other work

CCCC xxxx TTTTT xxx IIIII RRR II
&lt;/pre&gt;
&lt;p&gt;We're obviously in TAD (test-after development) mode here. Pay attention to the right hand side, which roughly indicates: When could this code actually ship?
&lt;/p&gt;&lt;p&gt;Note that there are multiple Rs because many people are involved in the review meeting. Also note that there is a little more time spent on testing, and yet the coverage never ends up good enough (rarely more than 75%). And finally, note the rework and re-inspection that must take place.
&lt;/p&gt;&lt;p&gt;
What the same model looks like with TDD:
&lt;/p&gt;&lt;pre&gt;
TCTCTCTC xxxx IIII xxx RR I
&lt;/pre&gt;
&lt;p&gt;So, a little less time building the right code in the first place, and also means a little less time in rework. It also means a little less time in review meetings, since the tests can help effectively describe whether or not the developer captured the requirements correctly.
&lt;/p&gt;&lt;p&gt;
With pairing and TDD:
&lt;/p&gt;&lt;pre&gt;
TTCCTTCCTTCC xxxx xxx
&lt;/pre&gt;
&lt;p&gt;I've doubled up the Ts and Cs because there are now two people involved. I'm not even going to claim that pairing developers will produce a &lt;em&gt;better&lt;/em&gt; solution &lt;em&gt;faster&lt;/em&gt;, even though I've seen this to be the case. Note that this is now the shortest line by far. (It will even accommodate some amount of formal review--much smaller now because it's already been actively reviewed at least once and preferably twice by the pairs building it--and still be shorter than the original process.)
&lt;/p&gt;&lt;p&gt;
I'm also not accounting for "ramp-up" time wasted. The intervening xxx's in the inspection-based flow means that minds have moved on to other things. When it comes time to review code, or rework it, developers must put their head back around something that they might have done days ago. Particularly without good tests, this can waste considerable time.
&lt;/p&gt;&lt;p&gt;
I'm in an environment now where test-first is only beginning to take roots. Every day I see ample evidence why test-after is simply a bad, bad idea.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-7014190343184352543?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/03/reviewing-tad.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-8362295542949762449</guid><pubDate>Thu, 12 Mar 2009 01:06:00 +0000</pubDate><atom:updated>2009-03-12T12:10:35.395-06:00</atom:updated><title>Two Greens in a Row</title><description>&lt;p&gt;
I'm not refactoring, I'm test-driving new code, writing assertions first, yet I get two green bars in a row. Stop! I need to figure out what's going on. The first possibility is that I didn't expect to get green:
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Did I compile? Am I picking up the right version of the code?&lt;/b&gt; - D'oh!&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Does the test really specify what I think it does?&lt;/span&gt; - I take a bit of time to read through the test.
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Do I really understand the code well enough?&lt;/b&gt; - I dig into the code, and in rare circumstances fire up the debugger. Maybe someone wasn't following YAGNI.&lt;/li&gt;
&lt;/ul&gt;
Alternatively, if I &lt;em&gt;did&lt;/em&gt; expect to get green:
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Did I take too large a step?&lt;/b&gt; - I consider restarting from the prior red, looking for a way to take more incremental steps. Obviously a more-granular increment of behavior exists, since I felt to compelled to write a distinct assertion for it.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Am I simply being completist?&lt;/b&gt; - I'm not testing, I'm doing TDD, where two greens in a row suggests that I don't need the second assertion. Test-driving is about incrementally growing the system, not ensuring that everything works. But from a confidence standpoint, I want to probe at interesting boundary conditions. Sometimes my compulsion to probe is because I don't understand the code as well as I should. Sometimes there's just too much going on, and I find that adding confidence tests is worthwhile. And finally, I remember that my tests should act as documentation. So most of the time, I'm ok with being a "completist."
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Are there "linked" (i.e. redundant) concepts in the design?&lt;/b&gt; - Maybe the interface is overloaded, deliberately so. More often than not, I can link the two concepts in the test as well, building a custom assert; conceptually I end up with one assert per test. If I find that I have a lot of tests with more than one postcondition, my designs are probably getting less cohesive. Or maybe I'm just writing too broad of a test.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
There are no doubt other reasons for two greens in a row. No matter, the event should always trigger a need to stop and &lt;em&gt;think&lt;/em&gt; about why.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-8362295542949762449?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/03/two-greens-in-row.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-9191748262887922278</guid><pubDate>Thu, 12 Feb 2009 16:53:00 +0000</pubDate><atom:updated>2009-02-12T10:09:09.370-07:00</atom:updated><title>I Know What You Did</title><description>&lt;p&gt;
It takes about two seconds to determine whether or not someone used TDD to derive a set of unit tests. While it's possible for someone to write as high-quality unit tests using TAD (test-after development), it just doesn't happen. Invariably I see many of the same problems, most significant of which is that the TAD tests don't cover nearly enough of the cases.
&lt;/p&gt;&lt;p&gt;
Most of the time, developers doing TAD simply refuse to follow the single-responsibility principle (SRP) at the class or method level. (Despite bizarre and often idiotic claims by &lt;a href="http://www.codinghorror.com/blog/archives/001225.html"&gt;Jeff Atwood&lt;/a&gt; and &lt;a href="http://www.joelonsoftware.com/items/2009/01/31.html"&gt;Joel Spolsky&lt;/a&gt;, asking people to push in the direction of Uncle Bob's five principles of class design is a reasonable and sensible thing to do.) They build large classes and large methods--not small, cohesive, potentially reusable units--and then complain about the difficulty of testing them.
&lt;/p&gt;&lt;p&gt;
My simple answer for now is, "How can you expect to write unit tests when you don't have any units?"
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-9191748262887922278?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/02/i-know-what-you-did.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-2591648077946819634</guid><pubDate>Thu, 05 Feb 2009 04:41:00 +0000</pubDate><atom:updated>2009-02-04T21:42:32.826-07:00</atom:updated><title>Agile In a Flash</title><description>&lt;p&gt;
Make sure you check out the &lt;a href="http://agileinaflash.blogspot.com"&gt;Agile In a Flash&lt;/a&gt; blog, where Tim Ottinger and I will be cranking out an agile flash-card deck.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-2591648077946819634?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/02/agile-in-flash.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-6449877224447381248</guid><pubDate>Tue, 03 Feb 2009 17:33:00 +0000</pubDate><atom:updated>2009-02-03T11:00:42.367-07:00</atom:updated><title>Convention and Case</title><description>&lt;p&gt;
I'm learning Grails. I found a &lt;a href="http://www.infoq.com/minibooks/grails"&gt;good tutorial written by Jason Rudolph&lt;/a&gt;. It does a great job of covering a broad range of the typical things you'd want to do in putting up a quick web site.
&lt;/p&gt;&lt;p&gt;
Unfortunately, it's for an older version of Grails, but so far that hasn't been a barrier; most of the changes I need to make are self-explanatory. I'm almost finished, and feel I have a good grasp on using Grails.
&lt;/p&gt;&lt;p&gt;
Still, I struggled for about two hours last night on a problem in going through the tutorial. Here's a form I defined.
&lt;/p&gt;&lt;pre&gt;
&amp;lt;g:form controller="user" method="post"&amp;gt;
    ...
    &amp;lt;g:actionSubmit value="Log In"/&amp;gt;
    ...
&amp;lt;/g:form&amp;gt;
&lt;/pre&gt;
And here's some of the controller:
&lt;pre&gt;
class UserController extends BaseController {
  def beforeInterceptor =
 [action:this.&amp;amp;auth, except: ['login', 'logout']]

  def index = { redirect(action:list,params:params) }

  def allowedMethods = [delete:'POST', save:'POST', update:'POST']

  def login = {
   // ... 
  }
  // ...
}
&lt;/pre&gt;
I think that's all that's relevant to show. Those of you who know Grails know how the form knows which controller method to call; I wasn't paying enough attention and missed the simple cause of my problem, which was that a simple form submit from the login page kept generating a 404, URL not found. It showed me the request URI:
&lt;pre&gt;
RequestURI=/racetrack/user/index
&lt;/pre&gt;
Yet that is a valid URI (index redirects, of course). In fact, if I copied the URL grails generated, and pasted it into the address bar, the proper page came up. I tried a few things, including explicitly specifying the action:
&lt;pre&gt;
&amp;lt;g:form controller="user" method="post" action="login"&amp;gt;
&lt;/pre&gt;
No dice, same problem:
&lt;pre&gt;
HTTP ERROR: 404

NOT_FOUND

RequestURI=/racetrack/user/login
&lt;/pre&gt;
Well, frustrated, I tried a few other things. No dice. I looked at the HTML provided in the book and looked to ensure I typed it correctly (I almost always type my own sample code rather than paste it, I learn better that way). Looks pretty much the same. Web search, no exact match on my same problem; found a couple odd things that it might be, tried 'em, not the problem.
&lt;p&gt;&lt;/p&gt;&lt;p&gt;
When in doubt, &lt;em&gt;really&lt;/em&gt; make sure you have exactly the same thing. Whitespace and case. Case couldn't possibly matter on button text, could it? Well, yes, especially when you follow this notion of programming by convention or programming by default or whatever you want to call it. An actionSubmit defines the controller method, either explicitly or implicity. Explicity, you can simply say:
&lt;/p&gt;&lt;pre&gt;
&amp;lt;g:actionSubmit value="Log In" action="login"/&amp;gt;
&lt;/pre&gt;
In the absence of the action attribute, it uses the &lt;code&gt;value&lt;/code&gt; attribute. Apparently, it lowercases the first letter for you, but then simply removes spaces, not lower-casing any subsequent letters. Thus it was looking for a controller action named "logIn," apparently. The tutorial code has it typed as "Log in." I typed it "Log In" (I thought it looked nicer). Harumph.
&lt;p&gt;&lt;/p&gt;&lt;p&gt;
Dumb on my part, for not paying enough attention to how the form was supposed to figure out which controller method to call (I hadn't figured this out yet, and thought this was another "by convention" element, perhaps from somewhere else). Dumb on Groovy's part, for not showing me the URI with the improper casing.
&lt;/p&gt;&lt;p&gt;
Lesson for me: Pay more attention. Lesson for tools that play by convention: if you're going to do something as clever as use button text to define an action, make sure you are picky about case everywhere, and make it clear from whence that action name came (i.e. better error messages). Lesson for tutorial writers: It's hard work to write a good tutorial. A good one gets you through all the happy path circumstances. A great one helps you out with all the dumb mistakes you'll inevitably make.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-6449877224447381248?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/02/convention-and-case.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-942620739799759071</guid><pubDate>Fri, 30 Jan 2009 20:53:00 +0000</pubDate><atom:updated>2009-01-30T14:13:22.272-07:00</atom:updated><title>Retrospectives</title><description>&lt;p&gt;Iterations are the heartbeat of agile--a consistent pulse, something that can be measured. If iterations are the heartbeat, the heart is retrospectives, representing the core and true spirit of agile: How do we adapt, how do we continually improve?
&lt;/p&gt;&lt;p&gt;
Too many teams don't run retrospectives, and many of those that do fall off quickly. Often they fell into the trap of running a consistently boring meeting: What things did we do well, what things do we want to improve upon? Worse, they treated the outcome of the retrospective as a bunch of vague promises. I'd certainly stop attending them if that's all they were.
&lt;/p&gt;&lt;p&gt;
A solution to the first is the Esther Derby/Diana Larsen book, &lt;a href="http://www.amazon.com/Agile-Retrospectives-Making-Teams-Great/dp/0977616649/langrsoftware-20"&gt;Agile Retrospectives&lt;/a&gt;. The biggest value of this book is that it provides a number of activities to help you run your retrospectives. It provides a great starting point to devising your own activities--being creative is an important way of keeping people interested in attending retrospectives. There are a number of areas that remain to be explored with respect to retrospectives. For example, I'm currently continuing to explore distributed retrospectives.
&lt;/p&gt;&lt;p&gt;
With respect to the second challenge--lack of commitment--I like treating the retrospective items as stories, or experiments, that are introduced for the upcoming iteration (but these are not project stories). Thus acceptance criteria are required, and the stories must be specific, concrete things that people will (or won't) do. During the subsequent retrospective, the team can't consider the experiment complete if the acceptance criteria has not been met, and thus shouldn't base subsequent actions on that experiment.
&lt;/p&gt;&lt;p&gt;
There's always someone who wants an agile litmus test. "You aren't agile if..." I feel comfortable in saying that "you aren't agile if you aren't consistently doing retrospectives and adapting the process based on them."
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-942620739799759071?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/01/retrospectives.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-6378883863284734968</guid><pubDate>Tue, 27 Jan 2009 19:18:00 +0000</pubDate><atom:updated>2009-01-27T13:36:49.588-07:00</atom:updated><title>Violating Standards in Tests</title><description>&lt;p&gt;Should your test code be subject to the same standards as your production code? I believe there should be different sets of standards. I am collecting interesting idioms that are normally shunned in good production code, but are acceptable and advantageous in test code.
&lt;/p&gt;&lt;p&gt;
An obvious example is the use of macros in tools like James Grenning's &lt;a href="http://sourceforge.net/projects/cpputest/"&gt;CppUTest&lt;/a&gt;. The testing framework (an updated version of CppUnitLite) requires programmers to use macros to identify test functions:
&lt;/p&gt;&lt;pre&gt;
TEST(HelloWorld, PrintOk)
{
   printHelloWorld();
   STRCMP_EQUAL("Hello World!\n", buffer); 
}
&lt;/pre&gt;
No self-respecting C++ programmer uses macros anymore to replace functions; per &lt;a href="http://www.amazon.com/Effective-Specific-Addison-Wesley-Professional-Computing/dp/0321334876/langrsoftware-20"&gt;Scott Meyers&lt;/a&gt; and many others, it's fraught with all sorts of problems. But in CppUTest, the use of macros greatly simplifies the work of a developer by eliminating their need to manually register the name of a new test with a suite.
&lt;p&gt;&lt;/p&gt;&lt;p&gt;
Another example is the use of import static in Java. The general rule of thumb, suggested by &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/static-import.html"&gt;Sun themselves&lt;/a&gt;, is to not overuse import static. Deleting the type information for statically scoped methods and fields can obscure understanding of code. It's considered appropriate only when use of static elements is pervasive. For example, most developers faced with coding any real math do an &lt;code&gt;import static&lt;/code&gt; on the java.lang.Math functions.
&lt;/p&gt;&lt;p&gt;
However, I use static import frequently from my tests:
&lt;/p&gt;&lt;pre&gt;
import static org.junit.Assert.*;
import org.junit.*;
import static util.StringUtil.*;

public class StringUtilCommaDelimitTest {
   @Test public void degenerate() {
      assertEquals("", commaDelimit(new String[] {}));
   }

   @Test public void oneEntry() {
      assertEquals("a", commaDelimit(new String[] {"a"}));
   }
   ...
}
&lt;/pre&gt;
Developers unquestioningly use &lt;code&gt;import static&lt;/code&gt; for JUnit 4 assertions, as they are pervasive. But the additional use here is for the method &lt;code&gt;commaDelimit&lt;/code&gt;, which is defined as static in the target class StringUtil. More frequently, I'll have the test refer to (statically defined) constants on the target class. For a test reader, it becomes obvious where that referenced constant would be defined.
&lt;/p&gt;&lt;p&gt;
What other coding standards are appropriate for tests only, and not for production code?
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-6378883863284734968?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/01/violating-standards-in-tests.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-8781269837791870820</guid><pubDate>Mon, 26 Jan 2009 17:48:00 +0000</pubDate><atom:updated>2009-01-26T11:32:46.909-07:00</atom:updated><title>Test Abstraction</title><description>&lt;p&gt;
I'm staring at a single CppUnit test function spanning hundreds of source lines. The test developer inserted visual indicators to help me pick out the eight test cases it covers:
&lt;pre&gt;
//++++++++++++++++++++++++++++++++++++++++++++++++++
&lt;/pre&gt;
Each of these cases is brief: four to eight lines of data setup, followed by a execution statement enclosed in a CPPUNIT_ASSERT. Of course they could be broken up into eight separate test functions, but otherwise they are reasonable.
&lt;/p&gt;&lt;p&gt;
Prior to the eight tests there are &lt;em&gt;two hundred&lt;/em&gt; lines of setup code. Most of the initialization sets data to reasonable default values so that the application code won't crash and burn while being exercised.
&lt;/p&gt;&lt;p&gt;
I don't know enough about the test to judge it in terms of its appropriateness as a "unit" test. It seems more integration test than anything. But perhaps all I would need to do is cleverly divorce the target function from all of those data setup dependencies, and break it up into eight separate test functions.
&lt;/p&gt;&lt;p&gt;
The aggregation of tests is typical, and no doubt comes from a compulsion to not waste all those 200 lines of work! The bigger problem I have is the function's lack of abstraction. Uncle Bob always says, "abstraction is elimination of the irrelevant and amplification of the essential." When it comes down to understanding tests, it is usually a matter of how good a job the developer was at abstracting intent. Two hundreds of lines of detailed setup does not exhibit abstraction!
&lt;/p&gt;&lt;p&gt;
For a given unit test, I always want to know why a given assertion should hold true, based on the setup context. The lengthy object construction and initialization should be encapsulated in another method, perhaps createDefaultMarket(). Relevant pieces of data can be layered atop the Market object: applyGroupDiscountRate(0.10), applyRestrictionCode(), etc. Not only does it help explain the data differences and correlate the setup with the result, it makes it easier to read the test, and easier to write new tests (reuse!).
&lt;/p&gt;&lt;p&gt;
I often get blank stares when I ask developers to make their tests more readable. Would they respond better to requests to improve their use of abstraction?
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-8781269837791870820?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/01/test-abstraction.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-149820445482181255</guid><pubDate>Mon, 05 Jan 2009 17:15:00 +0000</pubDate><atom:updated>2009-01-05T10:35:18.108-07:00</atom:updated><title>Code to Discuss</title><description>&lt;p&gt;A good software team knows to talk openly about the code. One suggestion is to get together once a day, maybe at day end, to just talk about or look at some code, even if you are already pairing. The get-together need not take long nor be formal in any manner. Fifteen to thirty minutes should be sufficient. Toss some code up on the wall using an LCD projector and have at it.
&lt;/p&gt;&lt;p&gt;
Initially, such discussions can be touchy, as critique can be mistakenly viewed as insults or attacks. Over time, the regular exercise of discussing code should form a group that better understands how to communicate effectively with each other.
&lt;/p&gt;&lt;p&gt;
What to talk about? I brainstormed some ideas for a specific set of teams, things I knew they needed to discuss, and provide that starter list here. Given the almost limitless number of reasons to talk about the code, there is little excuse to forego the forum.
&lt;ul&gt;
&lt;li&gt;"here's something cool that I did today!"&lt;/li&gt;
&lt;li&gt;"how could I better express this test?"&lt;/li&gt;
&lt;li&gt;"here is a mocking technique I found valuable"&lt;/li&gt;
&lt;li&gt;"this test didn't make sense to me"&lt;/li&gt;
&lt;li&gt;"this area of the code concerns me"&lt;/li&gt;
&lt;li&gt;test granularity&lt;/li&gt;
&lt;li&gt;test naming&lt;/li&gt;
&lt;li&gt;BDD&lt;/li&gt;
&lt;li&gt;how TDD changed my design&lt;/li&gt;
&lt;li&gt;naming standards&lt;/li&gt;
&lt;li&gt;coding standards&lt;/li&gt;
&lt;li&gt;warning standards&lt;/li&gt;
&lt;li&gt;JUnit 4.4+: Hamcrest matchers, theories, etc.&lt;/li&gt;
&lt;li&gt;"we're not writing enough tests"&lt;/li&gt;
&lt;li&gt;code coverage (taking a look at the actual lines exercised by tests)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://thedailywtf.com"&gt;WTFs&lt;/a&gt; in the code or test. Can be amusing, but watch the toes!&lt;/li&gt;
&lt;li&gt;test execution speed. Splitting into slow/fast suites.&lt;/li&gt;
&lt;li&gt;identifying and speeding up slow tests&lt;/li&gt;
&lt;li&gt;test smells&lt;/li&gt;
&lt;li&gt;various forms of test double (see XUnit Patterns)&lt;/li&gt;
&lt;li&gt;simple design vs SOLID&lt;/li&gt;
&lt;li&gt;"we're not refactoring our production code enough"&lt;/li&gt;
&lt;li&gt;"we're not refactoring our tests enough"&lt;/li&gt;
&lt;li&gt;object mothers for tests&lt;/li&gt;
&lt;li&gt;"the build is a pain in the rear"&lt;/li&gt;
&lt;li&gt;looking at a new mock tool like &lt;a href="http://code.google.com/p/mockito/"&gt;Mockito&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
And so on. Perhaps get a volunteer (or two) to "open" a topic each week. They talk for a few minutes, and then you open things up for group discussion.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-149820445482181255?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2009/01/code-to-discuss.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-3291918799080003169</guid><pubDate>Tue, 02 Dec 2008 22:27:00 +0000</pubDate><atom:updated>2008-12-02T15:57:46.846-07:00</atom:updated><title>Distributed Project Retrospectives</title><description>&lt;p&gt;
Recently I've done three distributed project retrospectives. I've heavily used the ideas in the Esther Derby/Diana Larsen book &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0977616649/langrsoftware-20"&gt;Agile Retrospectives&lt;/a&gt; to provide a foundation for these online meetings. Here's their general flow with a few comments and one addition:
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Establish base rules&lt;/em&gt; They need to "own" the rules but you should expect to kick off with a few of your own.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Safety exercise&lt;/em&gt;  "I am planning on being very open and vocal during this retrospective." - strongly agree, agree, neutral, disagree, strongly disagree. Answers to this will help you hold at least some people to their promises to talk. It may suggest the need to do even more anonymous polling during the meeting.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Gather data&lt;/em&gt; For project retrospectives, the Time Line activity has been especially useful. I simply share my desktop, put Excel up and start filling in events, with some dates, from left to right.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Generate insights, locate strengths&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Commit to improvements&lt;/em&gt; I solicit as many variant solutions as possible for a given challenge, and then let them vote on what they think the best one is to carry forward on a new project.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Close&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;
Here are some brief suppositions and observations:
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Use "online only." Everyone on the line should be at a separate station, not meeting together in a room. While this can increase phone line costs, it prevents "phone vs. live" dominance issues. Everyone sees the same thing.&lt;/li&gt;
&lt;li&gt;Use some sort of communication software with polling capability. I used WebEx for each of these three sessions. It's flaky but works. Make sure you try creating some questions ahead of time and understand both ends: How are questions defined, and what does the end user see?&lt;/li&gt;
&lt;li&gt;Some of the problems with WebEx polling:&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;No scaling/ranking question type available&lt;/li&gt;
&lt;li&gt;Easy to create a screwed-up poll and not know until answers are submitted&lt;/li&gt;
&lt;li&gt;Crummy interface overall. Too many opportunities for "user error"&lt;/li&gt;
&lt;li&gt;Can't easily share anonymous answers to "free form" questions&lt;/li&gt;
&lt;li&gt;Lame file-based save/load interface&lt;/li&gt;
&lt;li&gt;I didn't see how to change the amount of time a poll was open&lt;/li&gt;
&lt;li&gt;No way to limit the number of "votes" on a multiple-choice answer&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Come prepared with some good poll questions, but also look to create them on the fly. For example, after soliciting things that went poorly, it's useful to find out the top three or so to concentrate on. You might normally do this with dot voting and cards. Here, you can create a poll and ask people to select a certain number of items from the list.&lt;/li&gt;
&lt;li&gt;No matter how hard you try, many people will choose to not talk in a larger (&gt; 15) meeting. With a meeting of ~15 or less, the idea (Derby's?) of starting the retrospective by asking everyone to express their hopes for the meeting is a very good one; it gets people talking.&lt;/li&gt;
&lt;li&gt;Get an assistant to take notes, type questions, monitor chat, etc. They will allow you to focus on listening and steering the retrospective.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;
It's never the same as everyone being there! I view online retrospectives as a microcosm of doing the whole of agile in a highly distributed fashion. Effective communication becomes very difficult.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-3291918799080003169?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2008/12/distributed-project-retrospectives.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-6488575.post-609258256961741350</guid><pubDate>Mon, 01 Dec 2008 16:45:00 +0000</pubDate><atom:updated>2008-12-01T09:56:37.943-07:00</atom:updated><title>Giving Thanks</title><description>&lt;p&gt;Coming back from a long Thanksgiving weekend is always tough. This year it's tougher, as I had eight guests stay for four days and thus didn't keep up to date on things.&lt;/p&gt;&lt;p&gt;
I realized I didn't properly offer up thanks during our chaotic Thanksgiving dinner. So here are some of the things I'm thankful for today.
&lt;/p&gt;&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;Test-driven development, a technique that reinvigorated my interest in programming and made it far more enjoyable and effective for the past ten years.&lt;/li&gt;
&lt;li&gt;The shrinking of the international community through technology.&lt;/li&gt;
&lt;li&gt;People like &lt;a href="http://www.bcs.org/server.php?show=ConBlogEntry.778"&gt;Tim Hunter&lt;/a&gt; who provided much-needed laughter in this industry. I love spoofs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;That's it. Nothing earth-shattering here.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6488575-609258256961741350?l=www.langrsoft.com%2Fblog%2Fblog.shtml' alt='' /&gt;&lt;/div&gt;</description><link>http://www.langrsoft.com/blog/2008/12/giving-thanks.html</link><author>noreply@blogger.com (Jeff L.)</author><thr:total>0</thr:total></item></channel></rss>