Tuesday, May 31, 2005

Rock, Paper, Scissors--oh Sh#$%!

What’s your reaction to errors in a technical book or article? If you are like me, you discount the writer’s words if there are too many errors. If I find the topic interesting, however, I ignore infrequent errors and plunge ahead. But sometimes errors impede understanding. In that case, it’s always good to ask what the author meant to say. From time to time I get emails from readers tripping over errors in my own books. I try to thoughtfully answer their questions. Let me share a recent query:

Hi Rebecca,

I'm a little confused with your paper, rock, scissors example and the errata for your Object Design book. I figured out there seemed to be a problem when I got to figure 1-9. I went looking for errata. But the errata seem to have a problem too! For page 21, it mentions figure 1-9, but figure 1-8 is on pg 21! I'm not sure whether the page number is wrong, or the figure.... I'm assuming the figure. But beyond all that, I don't understand the purpose for three added methods beatsRock(), beatsPaper(), and beatsScissors(). Since a rock only calls beatsRock() and a paper only calls beatsPaper(), then why do we need three methods in this interface? Why not just have a "beatsMe()" method that is defined for the particular class being defined? Any clarification would be appreciated.

This reader had every reason to be puzzled. Not only did the example in my design book have a coding error, but the accompanying sequence diagrams did too. Even more frustrating, the errata referenced the wrong figure. After acknowledging the reader’s concerns, I went on to explain at some length that the purpose of this rather contrived example was to illustrate how double dispatching works. While indeed, the answer could’ve been implemented in a single method, that wasn’t the point. Instead it was to illustrate that double dispatching eliminated the need for case or switch statements. Double dispatching (whether you think it is a good idea or not) is a tricky enough to grasp even without the typos!

I didn’t intend to purposefully introduce errors. They crept in because writing and editing, like coding, require concentration and attention to detail. Because I’m human, I’m not perfect at tasks like these. Most people aren’t. With material that you are overly familiar with, you tend to read into it what you meant to say, skipping over small mistakes without even seeing them. One way I’ve found to force my brain to look at text or code with a fresh eye is to read it from the bottom up, one sentence or expression at a time. This shifts my perspective, allowing me to see errors more readily.

When others revise your work, there are even more opportunities for introducing error. Overzealous copyeditors introduce errors because they don’t believe you would want to say something that way (you couldn’t have meant OffF(i), so I’ll just change this to Off(i). Never mind that OffF(i)—for Off-Floor-i—was exactly what you intended). I understand why some insist on typesetting their own books and compiling every line of code. An author has to be really on her toes to catch those ‘thoughtfully’ induced errors. These can be especially difficult to detect because our brains skip over infrequent mistakes, especially when we “know” what is right. Fortunately, the more errors there are, the easier they are to spot. But first the fact that they exist has to be brought to your attention.

Ever wonder why pair programming is advocated by Extreme Programmers? It’s not because geeky software types as a general rule like to socialize, but because one can spot another’s mental lapses. Ever wonder why test-driven development is catching on? Tests force you to think through the functionality you want to implement with a fresh viewpoint, catching errors in your thinking before you code.

The next time you spot an error in a book or an article, consider letting the author know about it. I know I would appreciate hearing from you. Your comments make me a better writer (and you a more actively engaged reader).

Wednesday, May 11, 2005

Whole Systems Thinking and Pesky Details

I wasted an hour today trying to get an email signature line just the way I wanted it. The mail program I use is Eudora. I use it in paid mode. I’m not picking on Eudora so much as I am picking on the state of software tools in general (I’d love to hear your favorite tool horror).

I wanted to create several different signatures for different occasions…one for marketing to local clients, one that is just my “standard tagline”, etc. As part of my signature I wanted a line that included links to my website and blog on a single line:

website: www.wirfs-brock.com blog: www.wirfs-brock.com/rebeccasblog.html

That worked just fine for my standard signature file, where these were the only links. But then I wanted to create another signature which included these links followed by lines with links to upcoming public classes. Each class would be listed on a single line containing a link to the registration page. When I inserted these lines into my file, I encountered problems. The signature looked just fine when created and displayed as I was composing email. But somewhere in the process of sending and receiving the email, that first website link got mangled. I had encountered yet another case of what Scott Meyer’s refers as the keyhole problem. I still don’t know if this is a send or receive error, but trying to fix this problem drove me nuts.

Instead of a well-formed link, the link in incoming email was extended with spaces, breaking it. Needless to say, being a software geek, I vowed to tame this problem. I perform twenty or so different experiments over the next hour. I inserted tabs instead of spaces between my website and blog link. This worked, but the formatting was ragged and I don’t like inserting tabs into messages as some people’s mail systems don’t uniformly display text with embedded tabs. I put the website and blog links on separate lines. This worked, but it made my signature longer. I inserted one tab and spaces after the website link. This worked but had resulted in a ragged signature line that looked unprofessional. I copied the line with the links that worked from my other signature file and pasted it into the second signature one (of course this didn’t work, what was I thinking?). I tried re-specifying the links (this didn’t work either). I moved the broken-linked lines to after the single link lines in my signature file . This largely worked, too, except the spacing between the website link and the blog link came back with an extra space between them (making it a ragged line).

I then got the bright idea of creating a signature file in a fixed font, instead of Ariel. This worked. But I didn’t like how Courier looks. Too clunky. When I changed my signature file back to a font more appealing than Courier, Eudora apparently let me change my signature file, but it refused to pick up the new font information as specified in that file. Even rebooting my mail program didn’t correct the problem (obviously it was caching the font style and not really looking at the font specified in my signature file). I was headed even deeper into the weeds... At this point I decided to give up as I had several approaches that would work OK, even if they didn’t let me format the signature file exactly as I wanted.

All the trouble I had making a signature file made me want to chuck Eudora and move to another mailing tool. But I haven’t, just yet. I’m a healthy skeptic. Each software tool I use has its own peculiar quirks and annoying irritations. (But send me some convincing arguments about why I should move to another mail program and I’ll seriously consider it). Is this because developers are lazy or don’t care about quality? I suspect that most developers do not purposefully go about building quirky software. Yet somehow quirks creep in. There are myriad reasons. For one, most software is developed by teams. Each person has their own piece to implement and the system as a whole isn't "owned" by anyone. This traditional view of software development is changing with agile teams. Collective ownership, one of XP's core practices emphasizes teamwork. The more eyes that look at code, the better. But still, you need to pay attention to the system as a whole, even while paying attention to details.

You cannot eliminate these all bugs, but you can certainly waste time writing dumb little unit tests that don’t add any value. Uncovering quirky system behaviors requires spending your testing time wisely. It isn’t enough to write one simple test and declare, “setting up a signature file” seems to work. My quirky bug spanned multiple contexts—composing a signature file, sending email, and then receiving correctly formatted mail. Exploratory testing is a practice worth considering. It involves spending some time poking around, looking for stuff that just might not work. But developers need to take more responsiblity for overall system quality, too. Just checking that your code works isn't good enough.

Monday, May 02, 2005

Good enough domain models

Eric Evans talked about Domain-Driven Design at our Portland SPIN meeting Wednesday. Eric’s thesis is that unless you capture the “ubiquitous language” that people use to talk about the functions of the business and create a domain model representing object concepts, you are developing software at wrong level of detail. Instead of talking about Shipping Routes, Legs, and Itinerary, you’ll be talking about “creating rows in the stop table” for each port along a shipping route. Why create Itinerary and Leg objects when you can get by stuffing a database table with “stop” records? Because it makes other parts of the system easier to program. Re-routing cargo gets easier if you can remove all Legs after a particular destination and splice one Itinerary onto another one. Lack of a domain model can severely limit the effectiveness of software (and make it hard to maintain systems and add new functionality).

Creating a domain model is more complicated than just capturing the language people use to talk about system functionality and creating software objects with appropriate names. In complex software, development teams often work on different sub-problems. Each subsystem may need its own model. Meanwhile, subsystems and teams still need to define appropriate ways to communicate with each other. In addition to ubiquitous languages, you need to define the appropriate common languages for inter-system/inter-team communication. Nothing is ever easy!

Eric’s masterful talk motivated me to ponder about why developers often end up with muddy models instead of ones that more clearly incorporate domain concepts. Eric says that domain modeling isn’t looking for a perfect model, only ones that are “good enough” to support the hardest problem well. Why don’t more development teams end up with “good enough” models? I suspect there are many reasons. What constitutes “good enough” can be so subjective that people don’t want to get bogged down. They give up and take the easiest paths—not the simplest ones. For lack of a good object to relational mapping tool, some developers may compromise on database tables being “good enough” approximations to classes. And their models get compromised. There are many reasons why software falls short of capturing “ubiquitous language” in a domain model. I suspect that a big reason is that it isn’t always obvious that a model is needed. If your code shuffles data back and forth from the UI to a database with few edits…why create a model? Only when there is significant behavior and computation, does a model pay off. Now if we all could agree on what “significant” means. If you have ideas about what constitutes significant enough behavior to warrant a model, I’d like to hear your thoughts.