Listening To The Tests

(Tue Dec 28, 2004) [/TDD#

Ron Jeffries, in his online article (err... upcoming book) Adventures in C#: Using NUnit, sums things up oh so nicely in this statement about test-driven development:

It occurs to me as I write this that in the course of this book, you will probably encounter examples of doing things in ways that seem almost obtusely simple. I assure you that I'm not doing it to make the book suitable for third-graders, nor because I myself am also simple. I work that way because in the half-dozen years I've been doing Extreme Programming, I've been working in simpler and simpler ways, and my work seems to be getting better and better. So, please, when you see something here that looks odd, give it a try. Often I think you'll find it interesting.

I've been seriously practicing test-driven development for over a year now. It hasn't all been in an XP setting, nor does it need to be. Indeed, I think TDD and continous integration bring a lot to the party on their own. Unfortunately, I'm afraid all too often the baby is being thrown out with the bath water.

When I'm letting tests guide my way, I almost always find something interesting that wouldn't have been illuminated had I just slapped down the code that first popped into my brain. At first it felt awkward and a bit silly: Write a failing test, write just enough code that makes it pass, then refactor in the safety of that test. Writing just enough code is sometimes the silly part as I try to tease out the simplest solution. For some reason it's always tempting to speculate and in the process over-engineer. Yet with TDD I'm usually amazed at how little code it actually takes to build something of value.

In keeping with the TDD rhythm, I'm actually cranking out more code than without testing. And I know it's always working the way I intended it should. And the designs tend to be more responsive to change than when I was coding only after dreaming up a pattern-compliant design.

I had to rewire my brain by listening to the tests. I'm sure glad I did.

Gone Retro

(Tue Dec 28, 2004) [/CodeCraft#

I'm sitting here hacking to the sounds of a local radio station's 80s retro weekend. I'm writing this blog in Emacs, which I started learning about a week ago now. I haven't fired up vi since then, if that's any indication of how this new experience is going. It feels a lot like the experience I had learning Ruby after too many years of Java. Oh, I'll use vi again I suppose, but I'm having way too much fun with Emacs right now. It's something new (to me) and different. It feels... deliciously sinful.

Today wraps up a week that included writing several bash scripts. I dabbled in some CVS black magic that turned out to be elegant and intuitive -- it just worked. I scheduled a few 'cron' jobs. Along the way, I periodically ran 'make'. It's been far too long since I've done those things. But more importantly, I had an absolute ball! Writing "enterprise applications" was never this fun.

Test-First JavaScript

(Tue Dec 28, 2004) [/Tools#

If you're thinking of writing some JavaScript, think again. OK, if you must write JavaScript, then it should at least be fun! And what could be more fun than writing JavaScript driven by tests? Wait! Don't answer that. It's all relative, of course, but JsUnit turns that lemon into lemonade, as they say. It's JUnit, only the tests are written in JavaScript and they run in the browser. The test runner even sports a red/green bar that inches forward with each test. Whee! I'll admit, we had some good fun with it at a client site today.

Arise, POJOs!

(Tue Dec 28, 2004) [/CodeCraft#

We're one whole month into this new year now, and I'm continuing to see an encouraging trend back toward simplicity. Perhaps it wasn't just another hopeful resolution with a 30-day shelf life. It started last year when a downtrodden technology sought to bring some reality to a trough brimming with beloved three-letter acronyms (TLAs). But to be welcomed into that world of hype, it too had to conform to the likeness of others before it. From the ashes of the dot-com pyre rose the POJO.

(No, POJO isn't a reference to the unfortunate team member saddled with maintaining all the Java code in JSP scriptlets. It's a pity that nobody can remember now if he started out being a web designer or a server-side geek. Truth is, it's all the same to him now. But I digress.)

POJO is an acryonym for Plain 'Ol Java Object. It's a rather old-school concept, I realize. When gazing upon the totem pole of recent technology, you'll find it at the bottom. You can't directly access one across the network, replicate its state across a cluster, or expect it to save itself to a database. And until recently, a POJO wasn't even given the respect inherent in being called by an acronym. Any technology worth its salt these days must have an acronym, right?

POJOs are perfectly happy going about their humble duties in J2SE squalor. They prefer not to be bothered by those megalomaniacs living large in the J2EE world. Yet often times they get locked up inside some pompous component that proceeds to drag them around hither and yon. Their cry for freedom is unmistakable. The last time I heard one writhing in pain it was a captive of a session bean. I wanted to set it free, if only for my own selfish desire to easily test it. Yet it was difficult to discern where the EJB plumbing ended and the POJO began. Indeed, there was no way to get at it without first passing through the gates of its captor. I did eventually manage to unshackle it, and it went on to do great things. How it became tangled up with the session bean I'll never know. I do know that it wanted to be tested, if only for its own selfish desire to live in isolation from the beginning.

I think this will finally be the year when POJOs rise up against the oppression of their J2EE tyrants. The world will come to realize that J2EE is nothing more than a layering technology. Servlets, session beans, and message consumers alike should simply decorate POJOs. Indeed, these J2EE components are merely ambassadors rolling out red carpets for other technologies to approach the POJO. And yet unadorned by these decorations, a POJO has value in its own right as the keeper of business logic.

Any day now I'm expecting my first issue of POJO Developer's Journal to show up on the doorstep. It will, of course, contain advertisements for the upcoming POJO World conference. There you'll be able to buy fresh copies of Professional POJOs. If it's an O'Reilly title, I expect the cover animal to be something familiar, like a brown cow. It's all good.

Got Filename Completion?

(Tue Dec 28, 2004) [/Tools#

In my travels visiting various projects, I continue to meet developers wearing out their fingers in the Windows command shell. Just watching them type (and re-type) all those file/directory names character by character is like nails on a chalkboard to me. Growing up on UNIX, I can't imagine life without filename completion. It's another one of those things that computers are good for. Yet I'm surprised that many good developers still don't know it's possible on Windows. (Don't ask why it's not set by default.) So here goes...

Filename completion is your friend. You simply type the first few characters of a file or directory, then hit the filename completion key (TAB). The computer then uses its noggin to figure out which file/directory you're referring to and completes the rest of the word. If the characters you enter match multiple files or directories, then continuing to hit TAB will cycle through the choices. It adds up to a whole lot less typing in the long run and you don't have to remember the exact spelling of names.

Here, just look at how lazy I am. I wouldn't dream of typing

cd c:\myBigFatProjectName\tests
when I can coast through the file system like this:
cd c:\m<tab>\t<tab>

Ah. No more chalkboard noise. Life is good. We might actually get some code written today.

Here's how to turn on filename completion in Windows:

  1. Start the registry editor (regedit) and use Edit->Find to locate the CompletionChar registry key (or navigate to HKEY_CURRENT_USER\Software\Microsoft\Command Processor)
  2. Change the CompletionChar registry key value to 09 (the hexadecimal value of the TAB key)
  3. Restart any open console windows

Note: UNIX veterans will be quick to note that the Windows rendition of filename completion has some shortcomings. For example, you have to type in file separators (\) for it to continue walking down a directory structure. Then again, you're all probably using cygwin with a real shell.

So, I'll continue to spread the word whenever I hear that screeching noise while wandering around projects. In the meantime, take the opportunity to wander around your own project. Watch what other folks do. You'll be amazed at what you can pick up just by shoulder surfing. When I was learning to snowboard, I'd wait for another rider to come by and then try to follow their line down the mountain. Everyone rides with their own style and shadowing a lot of different riders helped me learn much faster than I would have alone.

Slowing Down To Speed Up

(Tue Dec 28, 2004) [/CodeCraft#

From this interview of one of my favorite authors, Neal Stephenson:

TCS: I understand that you did all the writing on the Baroque Cycle books by hand, using a fountain pen. Did that make a difference?

NS: Absolutely. The key difference is that it's slower. It's like when you're writing, there's a kind of buffer in your head where the next sentence sits while you're outputting the last one. As long as it's still in your head, it's easy to manipulate that next sentence, or even to reject it. Once it's out, well. . .

[snip]

Quicksilver, the first volume (of three) of the "Baroque Cycle", is a mere 944 pages in length. Given Stephenson's history, we can expect nothing less from each of the upcoming books. What Stephenson reveals is almost unthinkable. I can imagine other authors might be secretly laughing at him for being so... baroque. I can also imagine how boring and physically demanding using a fountain pen must be after about the second paragraph. Sure, the typesetting and print format have a lot to do with the total number of pages, but any way you slice it that's still a very large body of ink. Slower than typing? Indeed, glacially slower.

But writing a book isn't typing any more than programming is typing, a notion credited to Martin Fowler. Writing a book, in my limited experience, is more about thinking and rethinking. Once I know what I want to convey to the reader, writing it down on any medium is easier. Programming is, in my slightly less limited experience, similar in at least one respect. Once I know what the program should do, and how I know when it does that thing, typing it in is easier. Granted, I need to type it in to get feedback that the idealized model in my head can be cast into the reality of working code. And I need an interface that allows me to shape (and reshape) code quickly for rapid feedback. But what I need first and foremost is a construct for thinking and rethinking.

(Faithful readers should pause here to pat themselves on the back for already knowing where I'm going with this woefully inadequate analogy. Green bars for all of you!)

I am certainly no Stephenson, but his response prompted me to think of how slowing down makes a difference for me. Stephenson uses a fountain pen to slow himself down; I use a test. That is, writing the test first has the same buffering effect for me that using a pen does for Stephenson. Forcing myself to slow down by first codifying the "what" question as a test allows the "how" answers to ferment in the mental buffer just a little while longer. While in the buffer, the answers are more fungible and subject to close scrutiny. Once the buffer is flushed out to code, the ideas seem to become more permanent. I'm less inclined to remove code once it's been typed in. Consequently, the accumulation of code leads me down a certain mental path. Sometimes that path is in fact a rat hole -- a series of distractions that corrupt the buffer. It often takes me a while to realize the buffer has been corrupted. We call the result "rework". It's usually more expensive than work.

So how does one slow down to speed up? The trick, for me, is to get into a rhythm of frequently filling and flushing a relatively small buffer. The act of writing a test first creates the logjam for the buffer to begin filling. Once the test passes, the logjam is released and the buffer is flushed. With no buffer, I tend to wander aimlessly. With an infinite buffer, I never take the critical first step into reality. Somewhere in between is my maximum effective throughput. And at the end of the day, I'm more interested in overall throughput of quality code than speed measured at any given point in time.

Safe refactoring

(Tue Dec 28, 2004) [/CodeCraft#

I don't know where I'd be without my tests. I've become so dependent on running JUnit tests that I just can't imagine fiddling with code without seeing the stress-reducing green bar. Writing tests before the code that makes them pass has helped take my design skills to a whole new level. I considered myself to be a darned good OO designer, but I'm finding that simpler designs emerge from testable code. More importantly, I get early and often feedback that the designs actually work. As a second order effect, the code tends to have a lower defect density.

That's all good, but there's more. I continue to be pleasantly surprised by how "testing" actually makes programming more fun. Being able to aggressively add new features and refactor without fearing that something will break has had the biggest influence on my productivity over the last 2 years. That's right, all the whiz-bang tools and technologies I've learned in that time don't hold a candle to the power of this programming technique.

Bill Venners recently posted his interview with Martin Fowler on the virtues of refactoring and testing. Martin says:

One great thing JUnit-style tests give you is the ability to run them and see if you've broken anything. It's no big deal if you aren't changing anything, but if you're adding features or fixing bugs there's always the chance you'll break something. As you get better at your tests, you become more confident about the things you can change. As a result, you can get some high reliability rates.

I heartily recommend reading the refactoring interview, then topping it off by reading Part 2: Design Principles and Code Ownership. Timeless stuff!

There's No "QA" In "Team"

(Tue Dec 28, 2004) [/CodeCraft#

I'm on a mission to help tear down the barriers we've so methodically built up between QA and developers over the years. Having a box labeled "QA" on an org chart is so 90s. More importantly, it's just not efficient, in my experience. Now, before your feathers start ruffling, rest assured that I'm not saying we don't need testing skills on a team. Rather, I believe folks with testing experience are so valuable to the team that I'm proposing they get more involved with developers from the beginning. Waiting until the end of a development cycle and then throwing code over the wall is a disservice to those skills.

I've been struggling a lot lately with the nomenclature we use on projects. I'm frequently guilty of calling some folks "developers" and others "testers" or "QA". And every time I utter one word or the other, it doesn't feel right. I don't like labeling people that way. Worse yet, my words are like one more layer of bricks on the barrier. Indeed, applying the developer or tester label further reinforces the divisive relationship we've been living with for far too long. Don't we all share the common goal of developing better software faster? So, starting right now I'm making a resolution to not use the label "QA" or "tester". I realize that not using those words won't solve the problem, but I believe it puts me in the mindset to help chip away at the barrier.

Another approach I've been using to maximize our collective skills from the beginning is to help the team use tools that everyone has a stake in using. In my experience, testing tools that use a proprietary language targeted specifically at testers do more harm than good because they polarize the team. There are those who know how to use the tool and those that don't. Those that do report to a QA manager and those that don't are considered developers. The software under test is the only common ground. If testing the software is difficult, it's the testers' problem because developers don't understand the testing tool. Add another layer (or ten) of bricks to the barrier.

We need more testing tools that everyone on the team understands and uses from day one. Does that mean if your software is written in Java, everyone on the team must know how to program in Java in order to test that the software works as expected? I think not. Open source tools like FIT offer a convenient middle ground. The test fixtures that poke and prod the software are written in Java, but the data and commands that drive those fixtures are expressed in an HTML table. And with FitNesse, anyone can run FIT tests directly through the browser. That's right, even customers can run the tests!

I'm not alone in this endeavor to employ better testing tools. At the end of my test-driven development talk, I've been mentioning some of the open source tools I've been using and teaching teams to use. I recently started polling the audience to see if they wanted to dive deeper into some of these tools and the response was nearly unanimous. So, by popular demand, I've expanded the talk to a 3-hour session at the upcoming Rocky Mountain Software Symposium. In the first half, I'll teach the mechanics of JUnit -- how to write and run programmer tests -- and the test-first design technique. Then in the second half we'll go beyond JUnit by taking an indepth look at other open source testing and continuous integration tools I've been using heavily as of late, including Ant, Anthill, HttpUnit / HtmlUnit, Cactus, Canoo WebTest, JUnitPerf, FIT, and FitNesse. I have live demos of each of these tools that build and test the example app we develop in the first half of the talk. The talk is actually the basis for a full day of training I tailor to specific project interests. I'm also giving a separate talk on continuous performance testing using JUnitPerf.

A revolution is taking place, methinks. I believe we're on the cusp of a fundamental (and healthy) change in our industry. Ironically, I think this economy is a catalyst for that change as we're challenged with doing more with less. No longer can we afford the feigned comfort of barriers.

Let's Talk About Brian

(Tue Dec 28, 2004) [/CodeCraft#

Brian Marick, a mentor of mine who happens to have mad testing skills among many other talents, posted one of his short STQE essays. It's an insightful piece into how the methodologies and techniques we employ are reflections of our personalities. Just one of my favorite lines:

"Let's stop talking about best practices and start talking about what practices work best for us, right here, in a particular team, with that team's personality."

Spot on.

The End Of The World As I Know It

(Tue Dec 28, 2004) [/MacOSX#

At long last, I now own the latest PowerBook. I wish I could say I'm blogging from it presently, on a backlit keyboard with the lights turned off, but my local Apple Store isn't stocking them yet. Trust me, I was there -- before the doors opened this morning. The salesman mumbled something about not getting a pre-emptive shipment before the announcement because then Apple employees would have known the secret. OK, but I've been reaching false summits since June, and I really don't think the world is that incredibly shocked by the announcement. Relieved perhaps, if only because I'll finally shut up about wanting one, but not surprised. So in this case, I think making them available everywhere on the day they are spoken into existence, and when the buzz is at its zenith, trumps a potential leak of long overdue news.

Nevertheless, my order shipped out today and it's due to land on my doorstep in the next day or two. The UPS driver has absolutely no chance of bringing the vehicle to a full and complete stop before I pounce. I'm already prepping my current laptop for a lobotomy. Since I obsessively store everything of value in CVS, it should be a fairly short and painless procedure.

Of course the real fun, and part of the reason for the switch, will be learning a new environment and set of tools. Between that switch and my explorations into XQuery and other languages (more on that later), it's the end of the world as I know it. A new world awaits.

Breaking FOO Camp

(Tue Dec 28, 2004) [/CodeCraft#

One by one, the tents are disappearing as folks break FOO (Friends Of O'Reilly) Camp -- a weekend social experiment -- here in Sebastopol, CA. It's been an experience like no other, far exceeding any expectations I might have had. The key ingredient was the lack of a recipe. O'Reilly simply provided the kitchen, then invited 200 cooks to hack in the kitchen by tasting concoctions, sharing culinary skills, and collaborating on scrumptious new dishes. The result was a bountiful feast that certainly can't be mass produced. Indeed, all other conferences may feel like chain restaurants after this. As Emril would say: Bam!

Ten Cheap Actions

(Tue Dec 28, 2004) [/CodeCraft#

I'm a minimalist. I travel light. I cautiously approach all things new with a healthy dose of skepticism.

Here's an example: When presented with multiple control levers advertised to help me do something faster and better, I'll pull just one. Then I'll push it back and pull another. Ah, now I see how they independently affect my world. I might then decide to pull both levers to realize their combined effect.

Ten Cheap Actions You Can Take Today To Improve Your IT Team's Performance by Michael Hill and Kent Beck presents ten no-nonsense software development control levers, or practices. I've pulled each one of them in some form or another over the years. But lately I've been helping teams tap into the power of combining these practices into a cogent whole. Our experience has been that we can deliver better software faster. Every few weeks we're beaming with pride in delivering working software that our customers really want. Oh, and it's fun!

If your team is stuck in a rut, try jiggling something. Pull one of these levers today. See if it helps. Tailor it to work best for your team. Above all, just do something new and cheap.

Learning Through Feedback

(Tue Dec 28, 2004) [/CodeCraft#

I'm having oodles of fun with my latest toy - the Canon S-200. What I find really compelling about digital cameras is the instantaneous feedback. Amateurs like me can quickly learn how to take better pictures when the delay between taking a picture and seeing how it turned out is negligible. And taking a digital picture is free, so I'm actually encouraged to learn through experimentation. Indeed, I don't hesitate to snap a picture or ten. With film, I'd be much more cautious and conservative because each picture costs something to develop and I'd want to make sure I get the best shot. It's not until I pick up the film a day or two later that I know whether it was worth the money.

I want this same kind of instant gratification when I'm designing software. That is, I want to know if the design will work as soon as possible rather than wait to see if it will pan out later. If it doesn't work, I want to learn from my mistakes while it's fresh in my mind without incurring much time or opportunity cost. I want the effort of laying down code to be as cheap as possible so that I'm encouraged to scrap it at the first sign that it won't work. And I want a test to tell me straight up when the code isn't working as I expect. Alas, judging my pictures is more subjective than that.

Reston Symposium Review

(Tue Dec 28, 2004) [/Speaking#

If hallway talk and evaluation forms are any indication, this weekend's No Fluff, Just Stuff symposium in Reston, VA was a smashing success. You could almost feel the energy in the air throughout the weekend. As a result, I came back fully recharged.

Just a few highlights from the weekend:

  • Friday night I met Dave Astels and Erik Wenberg for dinner. One of the great things about traveling is meeting new folks and hearing what they're up to, and I really enjoyed exchanging ideas with Dave and Erik. While listening to them, I couldn't help but think that their team is fortunate to have them both. Good developers are hard to find, even in this economy.

  • Uncle Bob made his first appearance on the symposium tour. I had just finished helping a client start using FitNesse, so this was an excellent opportunity to chat with Bob about how he and Micah are building it. We need more applications like this that are developed with simplicity as a design goal.

  • Patrick Linksey, fellow co-author of Bitter EJB and VP of Engineering for SolarMetric, treated a few of us hungry speakers to an outstanding dinner on Saturday night in downtown DC.

  • After dinner on Saturday night, we walked around the Tidal Pool visiting all the monuments and memorials. I've toured DC many times, but this was my first look at the mall after dark. I was struck by how it takes on a different kind of beauty with the illuminations contrasting the night sky. Jason helped me hone my nighttime photography skills and discover the value of inanimate objects as tripods. I thought this picture captured the mood of the nation. It's taken looking across the Korean War Veterans Memorial with the Lincoln Memorial in the background.

Call it as you see it

(Tue Dec 28, 2004) [/CodeCraft#

Glenn reports overhearing this poignant statement in a hallway conversation at last weekend's Atlanta Java Software Symposium:

Our architecture is Big Ball of Mud, and we use Bitter Java as our coding standard.

Been there, done that, and yes I do have a t-shirt to prove it! That sort of honest reflection is the first step toward a simpler and more enjoyable life. Alas, pride often times gets in the way.

pyUnitPerf

(Tue Dec 28, 2004) [/Tools#

Grig Gheorghiu sent word that he has ported JUnitPerf to Python, dubbed pyUnitPerf. His blog has all the deets. He mentioned that he's been using various Python-based test frameworks to basically drive other chunks of software written in Java and C++, so he'll be using pyUnitPerf for this, as well.

One commenter calls the port "unpythonic", which sounds like a really cool name for next year's framework du jour, or a Pixar movie. Seriously, he makes a good point about doing straight ports of Java goodies to other languages. It's easy to overlook powerful features of the destination language and end up with ports that are least common denominators. Consequently, hard-core users don't want to call the code one of their own, and adoption is stifled. I don't know if that's the case here, but Grig strikes me as the type who would welcome any help making pyUnitPerf more "pythonic".

Java's Achilles Heel

(Tue Dec 28, 2004) [/Tools#

While adding some new entries to the JUnit FAQ this morning, I was once again reminded of Java's Achilles Heel - the onerous classpath.

JUnit newbies consistently have trouble correctly setting their CLASSPATH variable. And yet JUnit presents a relatively mild case of classpathitis. All you need is one jar file (junit.jar), your class files, and any other class files your class files depend on. Simple, right? Well, not if the number of mailing list questions regarding the classpath is any indication. The FAQ has helped reduce a lot of confusion, but the scourge of the classpath continues to be widespread throughout the Java community.

I've certainly been bitten by classpath problems more than once. The kind that result in a ClassNotFoundException are usually fairly easy to fix. It typically means your CLASSPATH variable doesn't have all the stuff it should. But the kind of classpath problems that don't conveniently throw exceptions are really nasty. You only suspect there's a problem because the version of a class you think is being used is not. It usually turns out that the class you're expecting to be used is masked by another version of the class at a higher precedence in the CLASSPATH variable. Those kind have a way of robbing massive amounts of your time.

A couple years ago I finally got tired of doing battle with the classpath. After all, it's just like the PATH variable, and the Unix which utility was created as a weapon against pathing problems. Fueled by frustration, I created JWhich to help hunt down insidious classpath problems. After using it to my advantage in a few battles, I wrote an article explaining how it's made my life with Java easier. I generally use it on the command line to check the system classpath, though some folks have adapted it for life inside of a servlet/EJB container. To address classpath problems specifically related to JUnit, WhichJUnit was born.

Perhaps these simple tools will help you spend more time doing the things you'd rather be doing.

Get The Testing Bug

(Tue Dec 28, 2004) [/TDD#

Did you make a New Year's resolution to start writing more tests and enjoy better designs as a result of writing tests first? How's that going so far? If you're having a difficult time getting started or making that resolution stick, don't despair. This stuff takes practice.

To help you get started, my "A Dozen Ways to Get the Testing Bug in the New Year" article is now available on java.net. It gives you 12 practical ways to start (and keep) writing tests, regardless of your development process. It also explains how writing tests first results in the emergence of better designs. I hope you find it helpful and encouraging.

By the way, I love the "delicious" graphic designed for the article. Have I mentioned just how outstanding the java.net staff is to work with?

Staying Fit With Learning Tests

(Tue Dec 28, 2004) [/CodeCraft#

For fun, and to tickle my brain, I'm exploring the machinery that makes FIT go. Oh, I know how to write FIT tests, but I'm curious as to what goes on under the hood when a test is run. And I want to take the opportunity to learn from Ward's coding style. His style is different from mine and that difference makes my brain hurt in the good kind of way. It pushes me outside of my comfort zone to that place where learning isn't inhibited by constraints. What I experience doesn't have to be right or wrong, it just is.

To apply what I learn, I'm writing a custom fixture that hooks into the FIT framework. I'm using a technique someone coined Learning Tests. It's easy. Given an API you want to use, start by writing tests that validate your expectations about the API. My expectations are usually wrong, but I end up learning something in the process. The collection of tests I ultimately write are a record of the things I learned along the way. When I forget how to use a particular method of the API, I can refer back to the learning tests as an example.

When I'm in learning mode, I start by writing a lot of tests that look like:

<SomeType> actual = object.method(someInput);
assertEquals(null, actual);
It's the "I dunno" test. OK, I might have a clue about what the actual return value should be, but I want the computer to tell me straight up what it is. In addition to being accurate, the computer is usually much faster than all my pondering. Running the test generally results in something like:
junit.framework.ComparisonFailure: expected: <null> but was: <actual result>
Stimulus, response. Aha! Then I change the test to:
<SomeType> actual = object.method(someInput);
assertEquals(<actual result>, actual);
Then I run the learning test again just to see green. Now I know that this particular sequence of method calls and inputs results in this particular output. And I've recorded that knowledge in a test. I can then apply what I've learned when using the API in production code. I have an example to draw from.

Wanna hear a secret? Sometimes I actually copy/paste the body of the learning test into a method of production code that has a failing test. That is, I'm literally transferring what I've learned into something usable by the application I'm building. Then I rewire the API inputs and outputs to suit the enclosing method. Finally, I run the failing test to validate if I've correctly applied my learning to the thing I'm building. In the case of FIT, I'm using my learning tests as examples of how to write a custom fixture.

I learn by doing. Learning Tests are one way I practice doing.

Setting the hook

(Tue Dec 28, 2004) [/MacOSX#

I'm still ruminating on the events at last weekend's geek fest. It takes me a while to unwind the stack after those events. I tend to sponge up everything I can while I'm there, then let the 'ol brain churn on the data for a while.

Believe it or not, there's one thing that keeps nagging at me after this weekend. No, it's not the news that web services may not turn out to be exactly what we dreamed. (Actually, it is what we dreamed... about 20 years ago.) OK, what I'm still quite enamored with is the new Mac OS X. The PowerBook is everything I want in a laptop - elegant form factor, beautiful user interface, and Unix under the hood. It's what I was looking for a few years back with Linux, and more!

I just noticed that new drops of Eclipse (my IDE of choice these days) will include a Mac build. It's a plot to rope me in, I tell ya. It doesn't help that everywhere I happen to go these days there's that illuminated piece of fruit like a siren song.

Anyway, it's a strange situation for me because I've never paid homage to the Mac cult. But I must admit, they've got me thinking...

FIT Teaser

(Tue Dec 28, 2004) [/Tools#

Bill Wake has posted an excellent introduction to FIT. It's a challenge really, intended to give folks an opportunity to practice writing FIT test tables and fixtures. When all the tests pass, you've built the core of a spreadsheet application. It will still need a user interface of course, and that will require different types of tests. In the meantime, your FIT tests will give you confidence in the guts of the spreadsheet application. And in the process you'll have built a UI-independent testing interface to the "business logic".

With FitNesse -- FIT and a Wiki rolled into one -- you don't have to run the tests from the command line. Rather, there's a button labeled Test on the HTML page that when pressed runs all the tests (tables) on that page. Here's the output of running Bill's tests. Notice that passing tests are indicated by green cells; failing tests by red cells showing the expected and actual values for each result. The challenge is to get all the cells to turn green using your own FIT test fixtures.

But before you get too focused on turning the cells green, take a few moments to imagine how you might have written these FIT tests yourself. Or, more appropriately, who you might ask to help you write effective acceptance tests using FIT. It seems to require two skill sets: Java programming and testing.

The test fixtures are written in Java. Each fixture is a Java class that has instance variables to capture the test inputs and methods to invoke actions and return expected results. As such, fixtures are simple adapters to the system under test. That is, they form the glue between the HTML table specifying the test and the API of the production code being tested. Though fixtures can be relatively trivial -- simply delegating all work to the system under test -- they do require someone who knows how to cut Java code. But how do you know what variables and methods a test fixture should have? In other words, what shape should any particular test fixture take in order to effectively test a feature of the application?

Without worrying about the API of the system under test, or writing any Java code whatsoever, you can start writing some FIT tables that specify acceptance tests. FitNesse allows us to edit any page using the browser. By virtue of being a Wiki, FitNesse also offers a convenient markup language for expressing HTML tables without having to actually venture into the nefarious world of angle brackets. We can even write some documentation associated with each test, right there along with the test inputs, actions, and expected outputs. Oh, the tests won't actually pass until you write the FIT test fixture and the production code it exercises. But that's a Java implementation detail. First things first: test then code.

Open the browser, create a new page for our tests... and now what? Well, you have to specify a test of course, but what's a good test? Ah, therein lies the difficult part. You're faced with defining a test that when green gives you (and your customer!) confidence that the feature you're building actually does the right things and does them right. That is, you have to figure out what the feature is supposed to do and how you'll know when it does those things. Later on you'll surely write unit and integration tests as you're implementing the feature to validate your design decisions and sanity check individual components. But right now you're confronted with having to define an acceptance test that tells you when the feature is done.

Take another look at the tests in Bill's challenge. Would you have thought of all those tests? I'm quite sure I wouldn't have. I'd do my best, but I'd like some help. Specifically, I'm willing to bet that someone with more testing experience than I would have taught me a thing or two about what might go wrong. Moreover, they'd probably have different perspectives on what a test fixture for any particular feature should offer. Or perhaps this team member has spent more time with our customer learning how a feature will be used, and now they're speaking on that customer's behalf. Together we could design the test right here in the browser -- adding rows and columns -- before ever writing a line of Java code. And if later we paired while writing the test fixture, I might teach them a thing or two about programming in Java. We might both learn something valuable about software development.

Once we've defined the test fixture, driven by the variables and methods declared in the FIT table, then anyone is free to add new test cases without ever firing up a Java compiler. Want to test a new corner case that's been keeping you up at night? Simply add a new row to a existing table, press Test, and we'll see red or green. And if we see red, then the fact that we collaborated on defining the test using a tool we both understand inclines us to work together to fix the problem. It's our test.

Automating tests is the easy part. Computers do all that work for us. Writing good tests that can be automated to continuously tell us if we've built the right thing right, now that's the tough part. I want all the help I can get. I find pairing with someone with testing experience to write FIT tests to be quite efficient and enjoyable. I prefer to do that as a matter of course before I start investing time writing production code.

FIT won't be the only testing tool we use, but it is one way we can proactively take a step (or ten) toward each other. In doing so, we might actually deliver better software faster.

What's JavaDoc done for you lately?

(Tue Dec 28, 2004) [/CodeCraft#

Someone was recently explaining to me how he always wrote the JavaDoc before writing each method. It helped him mentally work through the signature of the method and what it should do. A specification of the method, if you will. I can certainly understand how that might be beneficial, but I lack the discipline it requires. Indeed, I'm quite sure I'd forget to update the JavaDoc to keep it in synch with the method. And the refactoring tools I use wouldn't help me much either. They don't comprende JavaDoc.

Alas, I'm much too lazy and forgetful to keep JavaDoc in synch at the method level. Instead, I just write an executable test before writing the method that makes it pass. The act of writing the test helps me design the method from the outside. Running the test tells me if it does the right thing. Then I let the computer do all the hard work. If later I change the method signature or the result the method produces, the tests will tell me that my "documentation" is out of synch. And if someone wants to see how to use the method, the test is there as a specification by example. They can run it and the gears inside actually turn. Then they can fiddle with the test and see what happens. I figure if someone is looking at the JavaDoc for a class, their intent is to use it somehow. I'd rather just give them a working test that demonstrates the features of the class.

That being said, I do write some JavaDoc, but only if I can't express the same information in code and tests. In other words, the JavaDoc has to do something for its reader, not just pacify some documentation standard. Color me lazy and forgetful.

Evangelizing Test-Driven Development

(Tue Dec 28, 2004) [/TDD#

I had a great turnout for my "Test-Driven Development With JUnit" talk this weekend at the No Fluff, Just Stuff symposium in sunny Seattle, despite going up against Glenn's stacked deck at the same time. ;-)

It's always rewarding to get stellar reviews on a talk, but this time I got a few extra goodies. A number of attendees used the word "convincing" on their evaluation form. Now it's not unusual that folks give TDD a whirl after listening to me extol its virtues. After all, with all those green bars flashing by you can't help but want to pop one yourself. But this is the first time I've received nearly-unanimous reports that the talk was convincing.

So on the plane ride home when I was sifting through the evals, I started thinking about what was different this time. I'm always looking for opportunities to use feedback as a resource. The results of every talk I give get piped into the next talk. And I've given this talk about a dozen times, so it's been... err... mercilessly refactored.

Earlier in the week I had taught a course on TDD using JUnit to a bright team of QA and development folks. Their enthusiasm no doubt kept me wired through the weekend. I'm very much looking forward to watching JUnit and TDD take root on their project. Perhaps that enjoyable experience got me started on the right foot.

But in general I'm just really passionate about TDD. When I'm up there talking, I'm not shy about telling you how insecure and unproductive I am without it. I guess I've never been too shy about sharing my failures. What do I have to hide? Indeed, the more I hide the less I learn. Example: Oh sure, I used to write unit tests after my code seemed to be working, but I loathed doing it and my tests weren't all that good. I was always hurriedly testing in hopes of getting back to the creative process of writing code. (Maybe I'm a bad programmer, methinks.) Only now have I discovered that writing tests first is part of the creativity. Better yet, I'm writing better tests because I'm actually enjoying the design benefits and the freedom the tests afford me to change code with impunity.

And I've been studying and practicing object-oriented design and patterns for over a decade now. I've got all the books and t-shirts to prove it. But when I'm honest with myself I know that most of that time I was really frustrated. Too often my beautiful UML designs turned ugly when I tried to codify them. (Maybe I'm a bad designer, methinks.) It's a bit hard to swallow, but I think I've learned more about OO in the last two years since picking up TDD than I did in all the years previous. But more importantly, I'm having fun with it because my designs are actually working. They're simpler, yet they still exhibit the qualities we associate with a good design: high cohesion and low coupling.

So here's my advice if you're trying to convince your team to use TDD: Just honestly tell them how it's working for you. And then stop talking. Don't worry about trying to convince them that TDD should also work for them. Yeah, I know that the books say it should and x number of programmers can't be wrong, but forget all that. Our industry is already polluted with tools and techniques that were supposed to work. Folks have to decide for themselves to try TDD and then shape it into their own technique -- based on their context. You can't do that for them, and they'll hate you all the more if you try. And if listening to a so-called "OO expert" talk about his frailties helps, I'd love an opportunity to tell them, and show them, how TDD is working for me.

Spreading the TDD Meme

(Tue Dec 28, 2004) [/TDD#

Tim Bray weighs in on his experiences with TDD in Yet Another TDD Sermon. I have a lot of respect for Tim. He says TDD helps him write better programs. I'm obviously already drinking the TDD kool-aid. But if I weren't, why wouldn't I want to try it to see if it helps me write better programs?

I'm happy to see this story play over and over again. I gave two TDD talks in Raleigh, NC last weekend. Both were well attended and folks were enthusiastic about writing more tests on their projects. This TDD stuff is going to catch on, I tell ya.

Using FileMerge with Subversion

(Tue Dec 28, 2004) [/Tools#

I just discovered svnopendiff: a handy Ruby script that opens Subversion file differences in FileMerge.app. By default, it diffs between the pristine copy and the working copy, presenting a side-by-side view with differences highlighted. A slightly less intelligent zsh script is also available.

I moved all of my projects from CVS to Subversion a while back and have been very happy with the results. The only thing I miss is the ability to go into the attic and torch a file or directory that got added by accident (e.g., a Keynote bundled directory). Subversion currently doesn't have support for permanently removing files that it's been introduced to. Here's hoping the svnadmin obliterate command gets implemented someday soon.

Dear Manager, They Need a Build Machine

(Tue Dec 28, 2004) [/CodeCraft#

Dear Manager,

When I talk with the developers on your team, they tell me they need a dedicated build machine. I'm partly to blame. See, I've been showing them a free build scheduler that, after just a few minutes of configuration, will continuously build your software with no human intervention. That's good for them, and it's even better for you. Let me tell you why.

  • If you build and test your software once an hour, no problem is more than an hour old.

  • This makes it easier to find and fix problems, which saves time and money, and lets your team concentrate on adding new stuff, not fixing old stuff.

  • The continuous build process feeds you valuable and timely information, letting you manage the development more tightly.

Here's how it works: Every hour, for example, and only if new work has done, the build scheduler checks out a fresh copy of your project from version control and attempts to build the project. The build process includes compiling all of your project's source files, running an arbitrary number of tests, and generating any other build artifacts, such as project metrics. If, for any reason, the build process is unsuccessful, then the build scheduler can notify you via email, your cell phone, RSS, or a visual device such as a lava lamp. You can also use your web browser to view the current status of the build, or any prior build.

Running builds throughout the day whenever changes are made to the project is a tireless job, which is exactly why you don't want your developers doing it. They would rather focus their time and energy on writing quality code that ultimately helps you deliver valuable software to your customers. But building the software on a frequent interval is also an important job because finding and fixing integration problems right before a release---when you have the lowest tolerance for risk---can be costly. With the build scheduler constantly integrating your software, problems are detected almost as soon as they're introduced, giving your team the maximum amount of time to fix those problems before they start to compound. In turn, you receive the benefit of knowing the health of the software all day, every day.

Your developers already understand the value of continuous builds. They know getting constant feedback about the build will help them stay on track. They know staying on track is equally important to you. And they're happy to invest a few minutes setting up a build scheduler that continues to pay back precious dividends: time and money. There's just one minor problem. Thankfully, it's one of those unique problems that can be quickly solved with a one-time expenditure. That's where you can help by approving that expenditure. Simply put, your project can't afford not to have a dedicated build machine.

Now, you might be thinking that with all the machines on developers' desks you already have plenty of horsepower for continuous builds. But it's not about horsepower; it's about availability and independence. Running continuous builds on a development machine will slow down the developer who owns that machine. The money you save by not purchasing a dedicated build machine will quickly be overrun by paying a developer to work slower. Additionally, a dedicated build machine is independent in the sense that it hasn't been biased toward any particular developer. It takes what's in version control to be all that's necessary to create a build. If the build succeeds on the dedicated build machine, it means that anyone on the project can create a build given access to your version control system. You get the peace of mind of knowing that everything that goes into the release is safely tucked away in a centralized repository.

Finally, please allow me to summarize by presenting the economics that I continue to see ignored by your competitors. Consider that on average your ten-person development team costs, conservatively, $500 per hour. (It's probably more like $1000 per hour when you consider all the care and feeding expenses.) If your team spends a total of two hours over the life of the project debugging integration problems (start counting whenever you hear a developer cry "But it works on my machine!"), then you've already paid for a respectable build machine. Then when you consider that those debugging sessions are delaying your product going to market, you really can't afford not to have a dedicated build machine.

I hope this helps clarify what you may have heard about continuous integration. If you have any questions or concerns, please let me know.

Respectfully,
Mike

Competition Breeds Innovation

(Tue Dec 28, 2004) [/MacOSX#

From today's Wired article:

"We're going to fight illegal downloading by competing with it," said (Steve) Jobs. "We're not going to sue it. We're not going to ignore it. We're going to compete with it."

I like a company with that brand of courage and confidence. It's one important way our industry learns how to innovate. And I love iTunes Music Store. It was great on the Mac, and it's even better now that I'm easily sharing songs between my Mac and Windows boxes.

Foo Camp 2004

(Tue Dec 28, 2004) [/CodeCraft#

Foo Camp is over and the Foo tattoo on my bicep is starting to fade, but the great memories I have will last a lifetime.

This year was inspirational on two fronts. The adventure started with a flight out to Portland to meet James for a 2-day drive down the Oregon coast. Nature has always been a huge source of inspiration for me, and the views along Highway 101 are absolutely gorgeous. Just when you think you've seen the best of it, something else takes your breath away. The drive turned out to be an ideal way to chill before a whirlwind weekend. Thanks, James, for an unforgettable road trip.

There's a lot to do at Foo Camp and yet the majority of it is completely unplanned. It's emergence at its best -- you help make it what it is. As a social experiment, James and I handed out temporary Foo Camp tattoos. It turned out to be a fun way to meet new people and as a result I spent most of my time rubbing cerebrums with other folks in geekdom. Funny thing is, after every chat I walked away with the sorer of the two brains. Trust me that it's a good kind of hurt. I draw inspiration from watching and listening to wicked-smart people.

But Foo Camp is just the beginning. Indeed, I believe I have an implicit obligation afterwards to harness all that inspiration into crafting something valuable to the industry and helping others work on their craft. Then, if I get the privilege of attending Foo Camp next year, I need to share my work and celebrate the work of others.

Many thanks to all the outstanding folks at O'Reilly for inviting me, and for helping me grow by inviting great friends, invaluable mentors, and generally big-brained people. I hope I live up to my end of the bargain.

In Love

(Tue Dec 28, 2004) [/MacOSX#

I've very happily rebooted into a new world. It's a bright and colorful world where things work for me, not against me. This world has an incredibly pleasing and productive facade, yet provides all the tools to hack it and build new things. Every day I wake up to this new world I find something new and different, yet consistent with the journeys of the day before.

My conversion took much less time than I anticipated. Indeed, I've had more trouble switching from one Windows box to another. Perhaps it was all that shovelware I had to wade through with new Windows systems. You'll find none of that in the box or on the desktop here. A PowerBook ships fresh and clean, ready for you to make the world into your own. It just works, though you'd never know it judging by the lack of any noise under the hood. James nails it.

A tip for anyone wanting to get their hands on one of these fast: Buy it at your local Apple Store if you have one nearby. My local store was getting frequent shipments. Had I got on their list I would have had a new PowerBook days earlier than ordering it through the online store.

Automation Gear On Display

(Tue Dec 28, 2004) [/Automation#

Stop by and visit the good folks at Softpro Books in Denver and you'll get a first-hand look (and feel) at some of my project automation gear. You know you've arrived when you see the red and green lava lamps blazing through the storefront window.


Automation Gear

The X10 devices that conveniently power the lamps are also there on the table, ready to be poked and prodded. And, because you know you want to hook up lava lamps to your scheduled build, take a free copy of the instruction booklet back to your boss' office.

While you're in there, please support Softpro and your dear author by purchasing a copy of the book that gives you soup-to-nuts recipes for automating your software project. When you pay, don't forget to ask for a voucher to purchase the PDF version of the book for just 99 cents. (The PDF offer applies to any Pragmatic Bookshelf title you buy at a participating independent bookstore.)

Thanks, and have fun!

Wannabe Switcher

(Tue Dec 28, 2004) [/MacOSX#

I'm a wannabe switcher. Ask anybody who knows me and they'll tell you it's true. Really. I've tasted the Kewl-Aid and it's yummy. Reality distortion field? Consider me ultra-warped.

See, I've already taken the leap, mentally. But I made a public and personal pledge that I'd wait for the new 15" PowerBook. You know, the one with all the 12" and 17" goodies, but that's not too small and not too big. Well, it wanted to be mine yesterday. Indeed, it has been relentlessly seeking me since we met on the Internet. And yesterday we were to finally meet in person.

And as I watched the WWDC Keynote fed by satellite into a big-screen at my local Apple Store, I was so ready. Panther? Great! iChat AV? Killer! XCode? Oh baby! G5? Stunning! New 15" PowerBook? <deafening silence> New 15" PowerBook? <sobbing> Come on, Steve, you brought me this far now please let me buy something before I leave! Or just say something -- anything! -- about the medium-sized laptop that could. We could have had a good life together... starting today.

I'm Mike and I'm a wannabe switcher.

Switchers

(Tue Dec 28, 2004) [/MacOSX#

For a byte to eat at lunch today, I cruised on over to CompUSA with my impulse-buy shield on full power. The store was dead... except for one corner that from a distance looked like the trading floor of the NYSE. Holding the trading tickets was a lone Apple sales rep doing his best, but struggling to keep up with the volley of questions.

You've no doubt seen the "switcher" ads on television profiling folks who have switched from other platforms to using a Mac. It's a brilliant marketing move, in my opinion, and it seems to be working. The latest enticement: Buy any Mac and Microsoft Office before January 7 and save $300 on the spot. Other hardware and software vendors would be well advised to take a lesson from this tactic. Think out of the box and innovate, but don't alienate your users.

Ah yes, the Powerbook G4 was there to tempt me, but my shield was impervious. I was on a mission was to find an AirPort for my wireless network, but alas the store had sold out. I'll hit another store and hope I can wade through the sea of switchers.

Dumbster Diving

(Tue Dec 28, 2004) [/TDD#

I'm currently writing an automated monitoring and notification program for a client. Users of their Java-powered web application can elect to receive email when certain things of interest have changed. The notification frequency is configurable. For example, as a user of this system you might want to be notified at the end of every day if something really important happened that day. For less important stuff you can wait for an email at the end of the week.

The monitoring step involves running a hunk o' Java when a timer pops to determine if something of interest has indeed changed since the last time interval. I'm using Quartz to schedule the monitoring jobs because it's light-weight, supports cron-like schedules, is as portable as Java can be, and it passes the fits-in-one-JAR-file test. Its only downside is that it's difficult to test schedules with long intervals. I'll come back to why I want to control its internal clock in a future blog. For now, trust that I know how many places Quartz directly calls System.currentTimeMillis() and it's greater than one.

The notification step uses JavaMail because my program lives inside of a bigger Java program and, thankfully, JavaMail is one of the less onerous Java APIs. Because successfully sending email is such an important part of the process, I'd like to test that it actually works. However, I'd like to do that without spamming my email account. I'm really only interested in validating that a correctly-formatted email was outbound. I could certainly mock it at the code level to make sure I'm using the API correctly. But wouldn't it be nice to have a fake SMTP server that squirrels away emails it receives and then lets you test for their existence?

That's where Dumbster comes in. It plugs in at the network level and intercepts email sent by JavaMail (or any other mail sender). Here's the test:

import com.dumbster.smtp.SimpleSmtpServer;
import com.dumbster.smtp.SmtpMessage;
import java.util.Iterator;
import javax.mail.MessagingException;
import junit.framework.TestCase;

public class MailSenderTest extends TestCase {
    
    public void testSend() throws MessagingException {
    
        String smtpHost = "localhost";
        int smtpPort = 2525;
        
        SimpleSmtpServer server = SimpleSmtpServer.start(smtpPort);
        
        MailSender sender = new MailSender(smtpHost, smtpPort);

        String toAddress = "barney@rubble.com";        
        String fromAddress = "fred@flintstone.com";
        String subject = "Caveman Greeting";
        String body = "Yabba Dabba Doo!";
          
        sender.send(toAddress, fromAddress, subject, body);

        server.stop();

        assertEquals(1, server.getReceievedEmailSize());
        Iterator inbox = server.getReceivedEmail();
        SmtpMessage email = (SmtpMessage)inbox.next();
        assertEquals(toAddress, email.getHeaderValue("To"));
        assertEquals(fromAddress, email.getHeaderValue("From"));
        assertEquals(subject, email.getHeaderValue("Subject"));
        assertEquals(body, email.getBody());    
    }
}

Notice that it starts the SimpleSmtpServer before sending the email and stops it after the email has been sent. Then the assertions verify that the server received the expected email. That's all there is to it: simple and unintrusive. Now I can deliver this test along with the code and anybody, anywhere can run it without unknowingly sending me email every time the test passes.

FitNesse Beta Released

(Tue Dec 28, 2004) [/Tools#

Uncle Bob and crew just released a beta version of FitNesse: a stand-alone wiki bundled with Ward Cunningham's FIT framework. FitNesse is pure Java (JRE 1.4.0 or newer) and you don't need a web server to make it go. Installation is a piece 'o cake.

With FitNesse, it's never been easier to collaboratively create online documents with embedded acceptance tests expressed in HTML tables. Test fixtures, written in Java, are simple adapters that form the glue between a FIT test and the system behavior being tested. Running the tests on any given page is as simple as clicking a link and watching the rows of each FIT table turn green (or red). Very nice!

Practicing What I Preach

(Tue Dec 28, 2004) [/TDD#

Jeff Brekke astutely responded to my ConfigurationTest:

I'm wondering why you chose to use the constructor instead of setUp()? I guess I've grown a habit to always use setUp() and I was just wondering what the reasoning was. I try to question my habits often. ;)

Good thing you questioned it, Jeff... because I was wrong! Oh, there's nothing fundamentally wrong with using the constructor. The initialization code need run only once to capture the original system properties. But I put that code in the constructor for all the wrong reasons. Indeed, I fell prey to a cunning programmer trap. You see, I wanted to put the initialization code in the setUp() method. It makes for nice symmetry with the tearDown() method. When I'm reading tests and see those two methods, I know just what's going on.

But just as I was going for the setUp() method, I was struck by irrational fear: "Oh no, this initialization code could be slow. I don't want it to run for every test method. That will be really slow!" So, without measuring how slow, I took the bait. That's right, I was prematurely optimizing. And it bit me.

For some reason I forgot that a new instance of the test case is created for each test method. Consequently, the test case constructor is run for every invocation of the setUp() method. That's just how JUnit works. I was assuming the constructor was only run once, and that putting the seemingly slow code in the constructor would save time. I was wrong. Not only did it not save time, but it also compromised the readability of my test.

Here's the really bad (read: embarrassing) part: I've been aggressively preaching the perils of premature optimization. Indeed, my name is on the chapter in Bitter EJB that warns of performance tuning antipatterns. And the very first antipattern in that chapter is, you guessed it... Premature Optimization!

Shame on me. Perhaps by publicly falling on my sword I'll remember next time to focus on code clarity first, then measure for performance, if it matters. Thanks for keeping me on the rails, Jeff.

Makers Of Beautiful Things

(Tue Dec 28, 2004) [/CodeCraft#

From Paul Graham's delightful essay Hackers and Painters:

"A programming language is for thinking of programs, not for expressing programs you've already thought of. It should be a pencil, not a pen. Static typing would be a fine idea if people actually did write programs the way they taught me to in college. But that's not how any of the hackers I know write programs. We need a language that lets us scribble and smudge and smear, not a language where you have to sit with a teacup of types balanced on your knee and make polite conversation with a strict old aunt of a compiler."
No doubt you'll find other favorite quotes in his essay. It touches on many things that have been buzzing about my brain without a spot to land. This particular quote stuck with me because lately I'm doing lots of scribbling and Ruby is quickly becoming the queen bee in my strict old aunt's bonnet.

I don't think I've ever sat down and wrote a program I'd already thought of. I usually have an idea of what I want the program to do, but I generally don't know what the code will look like until my fingers are on the keyboard. So maybe I'm always scribbling, even when I think I'm not.

Test-driven development gives me the courage to challenge the false security of static typing, despite every instinct telling me that static typing is my friend. Too many years of Ada, C++, and Java will do that to you. Bruce Eckel sums it up quite well:

"In fact, what we need is Strong testing, not strong typing."


Update: A friend reminded me of the important distinction between strong and static typing. I'd agree with Bruce's quote if it were reworded to read:

"In fact, what we need is Strong testing, not static typing."
Not the same play on words, but more accurate. Both Java and Ruby are strongly typed. Java checks types at compile time; Ruby checks types at runtime.

Getting FIT

(Tue Dec 28, 2004) [/Tools#

No, I'm not talking about working off all that turkey from yesterday's feast. I'm talking about Ward Cunningham's Framework for Integration Testing. It's a simple, yet elegant, tool intended to help customers write automated acceptance tests. I've been putting it to the test lately, and my impressions are that it will end up being the xUnit of acceptance testing.

Glenn blogged two entries on this topic: his analysis of FIT and the magic of Ward. Truly excellent insights! Glenn's bandwidth never ceases to amaze me.

Monster Hacks

(Tue Dec 28, 2004) [/CodeCraft#

I don't watch much television, but if I'm mindlessly flipping through channels there's one program that invariably causes a full stop: Monster Garage. In each episode, a crew of gearheads -- including mechanics, industrial designers, and welders -- have seven days and nights to transform an ordinary car into an extraordinary machine. The team can spend no more than $3,000 cash for parts and they're allowed to scavenge as much as possible to keep costs low. At the end of the show, they must race the enviable machine.

Teenage ambitions notwithstanding, I'm no gearhead. But you don't have to be a gearhead to enjoy watching Monster Garage. You need only have an appreciation for a small team celebrating their craft by pushing their collective skills to the limit in order to build something insanely cool. Each team member tends to be a generalizing specialist. One guy might be an expert welder, for example, but he's actively learning the skills of a mechanic and an industrial designer. That is, their small team needs experts who also have a general working knowledge of all the other skills necessary to successfully design and build the machine.

When I saw my first episode of Monster Garage, I thought it was just tomfoolery. After all, why would you want to waste the talents of a team in transforming a Chevy Impala into a Zamboni? Alright, so it's great fodder for Hollywood. But in building these crazy contraptions, I think the team gains invaluable experience. It's not often we get to step outside the box and experiment with taking our skills over the top. Indeed, we're usually practicing our craft on the job when failure is not a very good option. Trying new things is incredibly risky in these situations. Instead, what might happen if we had an opportunity to practice with impunity? How might stretching our skills to build something with no obvious business value help us when the business is on the line?

I want to get on the Monster Hacks show. In each episode, a small team of geeks would have a specific amount of time to transform ordinary tech gadgetry -- including software scripts, programming languages, and tools, cell phones, PDAs, iPods, and GPS units -- into an extraordinary hack. At the end of the show, the team must demo the working system. The show would make up for its lack of roaring engines and power tools with unfettered airing of team "discussions" and shiny tech toys.

Anybody have a contact at Discovery Channel?

How Do I Test That? : Properties

(Tue Dec 28, 2004) [/TDD#

Today I'm crafting an app that's configurable through properties. (No, not XML, just plain 'ol properties. Silly me.) I want to write a test that, when it passes, gives me confidence that system-level properties (e.g. -Dkey=value) override properties specified programmatically. How do I test that?

Well, I could fire up the test from the command line, once with a system property set and once without, but that's messy. And my tests are control freaks. They don't like relying on external input.

The solution I settled on is fairly pedestrian. In fact, I'm betting you already have an answer in mind. But since I've written a similar test more than once over the last couple years, I figured it might be worth posting.

Keep in mind, there's no guarantee as to the order in which the test methods will be run. Thus, each test method wants its own "sandbox". So, not only are my tests control freaks, they're also sharing-challenged. Here goes:

public class ConfigurationTest extends TestCase {

    private Properties originalProperties;
    
    public ConfigurationTest() {
        originalProperties = new Properties();
        originalProperties.putAll(System.getProperties());
    }
    
    public void tearDown() {
        System.setProperties(originalProperties);
    }

    public void testSetProperty() {
        String key = "key";
        String value = "setValue";
        
        Properties properties = new Properties();
        properties.setProperty(key, value);
        
        Configuration config = new Configuration(properties);
        assertEquals(value, config.getProperty(key));
    }

    public void testSystemPropertyOverridesSetProperty() {
        String key = "key";
        
        Properties properties = new Properties();
        properties.setProperty(key, "setValue");
        
        System.setProperty(key, "systemValue");
        
        Configuration config = new Configuration(properties);
        assertEquals("systemValue", config.getProperty(key));
    }
}

That's a lot of code for a little bit of testing, you say? Well, it does appear to be a disproportionate amount of code, but I generally err on the verbose side and then wait until enough pressure builds to force a refactoring. I just can't see a good refactoring from here that enhances readability. Perhaps you will. In the meantime, I can continue running these tests at no cost.

I enjoyed writing this test (yet again) because it reminded me of the value of testability hooks. In this case, I can bypass the command-line interface completely and set system-level properties once the system is running. I'm learning that if I write my code driven by tests, then odds are those hooks emerge naturally. That is, my tests uncover new methods based on need rather than speculation. And sometimes those methods turn out to be quite handy outside the context of a text.

Stumped trying to write a test? Let me know. We'll both learn!

Donating Tunes

(Tue Dec 28, 2004) [/CodeCraft#

As a programmer, there's no greater joy for me than creating software that others find useful and usable. On any given day I'm either getting paid to write code for clients or I'm writing code for myself.

I still smile every time I receive an email from a satisfied JDepend or JUnitPerf user. Sometimes they just can't believe it's free software. I'd like to provide an outlet for their guilt. I've often considered asking users to donate their spare change in the form of a micro-payment, but that wouldn't be in the spirit of how or why I write free software. These tools were created first and foremost to scratch itches I had, and then later packaged for public consumption in hopes that they helped others. I certainly didn't have money on my mind when I created them. But there was something else influencing me as I cranked out the code: music.

So if you're using my free software and want to give back, a music donation would be a great way to show your appreciation. Just click here and enter mike@clarkware.com to send me an iTunes Music Store gift certificate. Make sure to tell me who you are so I can say thanks. Just imagine, the music you donate may inspire the next JDepend or JUnitPerf. In the meantime, rest assured that you'll be inspiring me.

Vulgar Code

(Tue Dec 28, 2004) [/CodeCraft#

"It's a lot more challenging to find words to express anger behind a vulgar word than simply relying on a vulgar word. That's how real connections are made."

-- Chester Bennington, singer in the band Linkin Park, on why the band's lyrics are expletive-free


"It's a lot more insightful to choose class and method names to express the true intention of code than simply relying on the first name that comes to mind. That's how real connections are made."

-- Mike Clark, programmer, on how writing tests first encourages less vulgar code

NoFluffJustStuff Tour Begins

(Tue Dec 28, 2004) [/Speaking#

I'm gearing up for the No Fluff Just Stuff symposium tour this year. We had a grand time last year on the tour, and this year I predict it will go over the top. If it's coming to your neck of the woods, let's hook up!

On that topic, Duncan scores a bulls-eye with his timely blog entry On Working for Free. In it he shares his candid thoughts:

If all the speakers at a conference aren't payed, then they are either pushing product (or themselves) or inexperienced. Just the two things that attendees of a conference don't want. They want to get access to the good stuff. The good presentations. The good speakers. The people that will help them have the thoughts that will help them with their careers.
I couldn't agree more. That's exactly why I've paid to attend conferences. Settle for nothing less.

No Mike At Virginia No Fluff

(Tue Dec 28, 2004) [/Speaking#

If you're expecting to see me at the No Fluff show in Virginia this weekend, I won't be there. I canceled out a couple weeks ago, but as of this morning the site still has me slated to give three talks. I don't know what's up with that, but I wouldn't want it to misdirect anyone.

I will be speaking at the Denver show next weekend.

Dialing For Packets

(Tue Dec 28, 2004) [/MacOSX#

Tonight I heard the sound, er wailing, of the internal modem on this Mac for the very first time. If it was a Windows box, before making that awful noise it would have first popped a dialog asking "Are you sure you want to do this, you pathetic excuse for a geek?". Of course, "OK" would have been the only option. But despite being born with WiFi as its mother tongue and, failing that, being able to speak guttural Ethernet, this Mac was respectful enough not to play the prima donna.

So, what do they think you're going to do in these hotel rooms: watch television, take an shower, and go to sleep? I'm sitting at a nice executive desk, next to a conference table with four chairs, and the television is hidden in one of those armoires, so it's not like they think I'm on vacation. If I wasn't working, this room sure would be trying to convince me that I should be. And if I pushed hard-copy paper around for a living, I'd have just dipped my feather quill pen in the ink well and signed the Louisiana Purchase Treaty. But I push packets around for a living, and I need to update a CVS repository that lives on some machine not inside this hotel.

Alas, I wasn't prepared with the list of dial-up phone numbers I carried around in the early 90s. So, without the comfort of packets in the air and without a fat pipe to stream ether through, well, it was time for desperate measures. Thankfully, I had cell phone reception and I frantically dialed somebody who was on the grid to find an access number. You can thank him for this blog.

Conversation Pieces

(Tue Dec 28, 2004) [/MacOSX#

If Mac laptops were dogs, they'd definitely be Golden Retrievers. When you see someone walking a Golden Retriever, you just can't help but want to pet it. And you usually end up chatting with the owner for a while. Indeed, the dog is a conversation piece, as is this laptop. I've met a bunch of cool people as a result of sitting behind this unmistakable emblem while on airplanes, at conferences, and slinking around projects. Folks just want to pet a Mac or they find refuge in spotting another friendly face in a Mac user. Tonight was no exception. Only this time somebody else was walking their Golden.

After visiting a client, I stopped by Barnes & Noble to replenish my supply of the brilliant and inspirational book "Art & Fear" to recommend during my talk in Philly this weekend. As I walk by the coffee shop area, I notice a guy sitting behind the familiar glow of a 17" PowerBook. I recognize him, as well, but I couldn't place where I'd seen him before. So, not wanting to make a fool of myself, I wander around the store for a while trying to remember where I'd seen this fellow before. Things like that bug me, and once I latch on I don't let go easily. It turns out that thumbing through self-help books doesn't jog my memory, so at long last it's time to make an introduction to the dog owner. "So, do they have a wireless hotspot here?"

Indeed, he informs me that we're basking in packets (I knew I felt a disturbance in the Force) and we proceed to exchange pleasantries. I don't recall his name, so I reluctantly admit that I recognize him but I don't remember the situation. Then out of desperation I point at his Mac laptop and mutter something about being a card-carrying member of the software industry and the Mac cult, thinking perhaps that will get the collective synapses firing so we can put an end to this awkward moment. Oh, the hubris of us alpha geeks. We dare to think that once we move into a technology space that we alone dominate the space. "I use a Mac because I'm a musician", he proudly proclaims.

Mystery solved. I'd been assuming that I knew him in the context of software, but once I'd broken free of that constrained view, it all came together. Several years ago my wife and I had listened to him play guitar at one of our favorite restaurants. I never forget a face. The name or situation, well, that's an implementation detail.

I tell you all this because it's just another example of many where I meet somebody new because of a Mac. Would I have approached this person had he been sitting behind a Dell laptop? Not a chance. He'd have probably just been somebody I knew from the software industry. :-)

No Fluff, Just Stuff In Austin

(Tue Dec 28, 2004) [/Speaking#

I'm headed out to Austin tonight for the kick-off of the 2003 No Fluff, Just Stuff symposium tour this weekend. Check out the map on their newly-redesigned website to see all of our stops this year. James, Jason, and I arriving a day early at this stop to take in some local sites and hang out with a few of James' old friends.

I'll be speaking on the following topics:

  • Test-Driven Development with JUnit
  • Bitter Tunes: Performance Tuning Antipatterns
  • Bitter Messages: JMS and Message-Driven Bean Antipatterns

What I especially like about these events is the close-in feel. That is, I don't feel like I'm wading through a sea of nameless faces all weekend. The relatively small number of attendees at each session allows me to tailor each talk. Indeed, you have an opportunity to participate. With a smaller session I can focus on making sure all your questions are answered to the best of my ability, either during or after the talk. And although all the talks are rich in technical content, often times they're only the beginning of a deeper conversation. You can always collar me anytime throughout the weekend to pair program or just chat.

Yeah, I know, training budgets are tight, but you just can't beat the price point of this symposium. Jay Zimmerman and crew do an outstanding job coordinating 4 concurrent sessions throughout the 2.5-day event. The lineup of speakers is impressive and they're all available to help you. I'm confident that by attending one of these shows you'll be making a great investment in your career. See you there!

Panther!

(Tue Dec 28, 2004) [/MacOSX#

I just finished installing Panther. I'm still trying to pry my jaw off the floor. Wow!

I can't imagine the install being any easier. I took the "Archive And Install" route with the "Preserve Users" option which basically moves the old system files to a temp directory and then installs Panther anew, putting my home directory back in place. It just worked! All told, I think it was about 30 minutes of downtime as it installed a country mile of bits, and during that time it required about 1 minute of my attention.

Now to be fair, since I bought this PowerBook recently, I qualified for the $19.95 Panther upgrade. Would I pay full price for Panther? Well, you know when you go to buy a mattress the salesperson always tries to hook you with that line about spending half your life in bed, so you want the best mattress money can buy? Pay no attention to that nonsense. After all, you're asleep! Unless your current mattress is keeping you up at night or putting a crick in your back, you probably won't notice a difference in the mattress they want you to buy.

But I spend most of my waking life wandering around this operating system for business and pleasure. It's a sad state of affairs, I realize, but the point is the new features will pay for themselves many times over in my case. Indeed, Expose and the revamped Finder are already helping me sleep better.

Bulletware

(Tue Dec 28, 2004) [/Speaking#

In preparation for next year's ambitious speaking schedule with a new stable of talks, I'm retooling. Keynote, OmniOutliner, and OmniGraffle are my new presentation tools of choice.

Equipped with those tools, I can quickly crank out cool presentations. I start by outlining my talk in OmniOutliner and then export the outline to a Keynote presentation. Then I emphasize certain talking points with diagrams created in OmniGraffle. And finally I polish up the master slide templates with color and style to make all the slides look uniform with an animated slide transition between each. Yes, I'm very productive with these tools and happy to have learned something new to start the new year.

There's just one problem: The resulting bulletware isn't the content of my presentation. If it were, I could avoid a lot of travel by just letting you download the bits. But the content of my presentation doesn't fit on a bulleted line, nor in a diagram, nor on an endless stream of slides with bullets and diagrams. No, you and I are the content of my presentation. It's a unique and personal conversation that can't be duplicated by firing up a projector at another time and location. The slides are merely canned visual aids for one possible conversation.

So in addition to retooling for next year, I'm also rethinking how to put bulletware in its rightful place. Bullet lists work well to convey certain types of information, but I'm making a concious effort to not reach for them first. I'm drawing inspiration from the following sources, echoed across blogspace many times over by now, but organized for your groking convenience in, er, a bulleted list:

I look forward to having a conversation with you next year!

Yes, Virginia, There Are Packets

(Tue Dec 28, 2004) [/Speaking#

My fanciful wishes of Milwaukee raising the Wi-Fi bar have come true. Yes siree, the Sheraton Milwaukee Brookfield has got packets! And it looks like we showed up just in time. Until a couple days ago they were still ironing out the kinks. But I must say, I'm quite impressed with what they've come up with. When you sign up for high-speed access in your room, which is reasonably priced, you also get access to the wireless network at no additional charge. No confusing and outrageous pricing plans, multiple logins, etc. It just works!

The main floor of the hotel has a couple hot spots that extend into the restaurant, coffee shop, lounge areas, and some conference rooms. Right now I'm sunk deep in one of several fluffy couches getting ready for the No Fluff, Just Stuff show starting tomorrow. After probing the boundaries around the symposium area (picture me walking around with my laptop poised like a Geiger Counter!), it looks like we'll be basking in warm packets all weekend. All the cozy hang spaces also help create the kind of collaborative environment where ideas really flourish.

I haven't done any recon to the downtown parks slated to get imbued with 802.11 this month, but I'll report back. From what I've seen of this town so far, it wouldn't surprise me.

A Book That Pays For Itself

(Tue Dec 28, 2004) [/Misc#

Do the math. At a cost of 65 cents and a sore kicking foot for every time you haven't read Glenn's refreshing and tasty book, it would be well worth the $24.95 cover price.

Brilliant, guys!