Archive

Archive for September, 2004

Version Numbers

September 29th, 2004
Comments Off

Since I was asked… Most projects I’ve worked on have used something
like the following scheme to identify releases. A version number like “6.2.3.1407″ means:

  • major version 6
  • minor version 2
  • patch 3
  • build 1407

The major version number is only incremented when significant changes
are made. In practice, “significant” means “changes that make this
version’s data/configuration/whatever impossible for older versions
to read”. In practice, major version numbers are often under the
control of the marketing department—if a competitor releases a
new major version, we’d pretty much have to as well.

Minor version numbers are what most people think of as releases. If
you’ve added a few new features, changed part of the GUI, etc., you
increment the minor version number and throw it to customers.

Patches are things that don’t have their own installers. If, for
example, you need to change one HTML form, or one DLL, you will often
just mail that out to customers, along with instructions about where
to put it, rather than creating a new installer. You should still
give it a number, though, and make an entry in your release log [1].

The build number is incremented every time you create a new
version of the product for QA to test. Build numbers are never reset,
i.e. you don’t go from 5.2.2.1001 to 6.0.0.0, but from 5.2.2.1001 to
6.0.0.1002, and so on. Build numbers are what developers care about:
they’re often only matched up with version numbers after the fact (i.e.
you create build #1017, QA says, “Yeah, it looks good,” so you say,
“All right, this’ll be 6.1.0,” and voila, you have 6.1.0.1017.)

Finally, groups will sometimes identify pre-releases as “beta 1″, “beta 2″, and so on, as in “6.2 beta 2″. Again, this label is usually attached to a particular build after the fact—you wait until QA (or whoever) says that build #1017 is good enough to send out to customers, then tag it in version control.

[1] A “release log” is a file (often a spreadsheet) that records exactly what was shipped to whom, when.

Uncategorized

Spot the Difference

September 26th, 2004

At 13:26 this afternoon, more than a day and a half after the
deadline I set my students, I finally got the Tapestry/Hibernate
warmup exercise
working to my satisfaction. The final bug took
several hours to track down; when I found out what it was, I almost
decided to throw Tapestry away and use
something a little more predictable.

The problem turned out to be the difference between this:

<!-- Buggy version -->
<tr>
  <td colspan="2">
    <input type="submit" jwcid="@Submit"
           listener="ognl:listeners.returnSubmitAction" value="Return"/>
  </td>
  <td colspan="2">
    <input type="submit" jwcid="@Submit"
           listener="ognl:listeners.borrowSubmitAction" value="Borrow"/>
  </td>
  <td><span jwcid="@TextField"  value="ognl:formBorrower"/></td>
  <td><span jwcid="@TextField"  value="ognl:formEmail"/></td>
  <td><span jwcid="@DatePicker" value="ognl:formBorrowDate"/></td>
</tr>

and this:

<!-- Working version -->
<tr>
  <td colspan="2">
    <input type="submit" jwcid="@Submit"
           listener="ognl:listeners.returnSubmitAction" value="Return"/>
  </td>
  <td><span jwcid="@TextField"  value="ognl:formBorrower"/></td>
  <td><span jwcid="@TextField"  value="ognl:formEmail"/></td>
  <td><span jwcid="@DatePicker" value="ognl:formBorrowDate"/></td>
  <td colspan="2">
    <input type="submit" jwcid="@Submit"
           listener="ognl:listeners.borrowSubmitAction" value="Borrow"/>
  </td>
</tr>

Can you spot the bug? In the first version, the three text fields
used to submit the borrower’s name, email address, and borrow date
come after the button that the user clicks to borrow books.
In the working version, the text fields come before that button.
That is the only difference—I made no changes to the application’s
.page and .application files, or to the Java
class.

After half an hour of Tapestry in Action and on
Google, I still have no idea why the order matters. If anyone knows
why it does, I’d welcome an explanation…

The real problem here, though, isn’t this bug in Tapestry (and yes, it’s
a bug—even if there’s some obscure engineers-rule “but we had to
because…” explanation for it, it’s a bug). The real problem is the
“spooky action at a distance” [1] nature of framework
programming. Everything that happens between me clicking the “submit”
button on an HTML form, and the corresponding action method being
invoked in my Java class, is, for all practical purposes, hidden from
me.

Oh, sure, I could run Tomcat (or Jetty, or some
other container) under a debugger, and watch Tapestry snatch the form
data from the HTTP stream, read my .application and
.page files, load my class, subclass it on the fly to
create implementations of my abstract methods, add some data members
to store form values, and finally invoke the method I actually wrote,
but saints and small mercies, how long would that take to set up? Or
to run? And how much of it would I actually understand?

On the other hand, how much of that do I want to write myself, over
and over again? The whole point of Tapestry is that it
takes care of these routine tasks for me, so that I only have to worry
about application-specific code. I’ve written enough CGI scripts and
naked servlets to recognize just how much grief a good framework can
save.

So, in the end, this turned out to be another example of what Joel
Spolsky dubbed a leaky
abstraction
. Tapestry really does
try to present a high-level model for web programming, but every once
in a while, you can still see what lies beneath. As he said:

Ten years ago, we might have imagined that new programming
paradigms would have made programming easier by now. Indeed, the
abstractions we’ve created over the years do allow us to deal with new
orders of complexity in software development that we didn’t have to
deal with ten or fifteen years ago, like GUI programming and network
programming. And while these great tools, like modern OO forms-based
languages, let us get a lot of work done incredibly quickly, suddenly
one day we need to figure out a problem where the abstraction leaked,
and it takes 2 weeks. And when you need to hire a programmer to do
mostly VB programming, it’s not good enough to hire a VB programmer,
because they will get completely stuck in tar every time the VB
abstraction leaks.

The Law of Leaky Abstractions is dragging us down.

[1] In 1935, several years after quantum mechanics
had been developed, Einstein, Podolsky, and Rosen showed that under
certain circumstances quantum mechanics predicted a breakdown of
locality. Specifically, they showed that if quantum mechanics was
true, then someone could put a particle in a measuring device in one
place and, simply by doing that, instantly influence another particle
light years away. Einstein called this “spooky action at a distance”,
and felt it was proof that quantum mechanics couldn’t be the whole
story. Unfortunately for him, Bell’s work in the 1960s, and
experiments in the years that followed, proved that this actually does
happen. To quote another physicist (Haldane this time), “…the
universe is not only queerer than we suppose, but queerer than we
can suppose.” (Unfortunately, the same seems to be true of
many software systems.)

Uncategorized

Essential Equipment

September 20th, 2004
Comments Off

In an earlier posting, I listed the programming tools I use. As part of setting up at the Blueprint Organization (who have kindly given me desk space for the next few months), I’ve realized that a complete working environment needs more than just software.

Peace and quiet.
Study after study has proved that this has more impact on productivity than a fast network, a fat disk, or caffeine, but most workplaces are still too crowded, too noisy, and filled with too many interrupts. It takes most people ten to fifteen minutes to get back into a state of flow after being distracted, which means that four or five interruptions per hour effectively renders someone zero percent effective. I know people say, “If I can’t overhear what other people are talking about, I might miss something important,” but that’s false economics: the time occasionally saved is greatly outweighed by the time repeatedly lost.
Comfortable seating.
A good chair with a firm back costs one fifth of what a mid-range PC does. A full-sized keyboard (I have large hands—most laptop keyboards force me to bend my wrists uncomfortably) costs fifty dollars, and a lamp with a soft-light bulb is another forty. The combination doesn’t just let me program longer each day; it also helps ensure that I’ll still be able to program five or ten years from now without chronic back and wrist pain.

(Those of you who are in the Computer Science building at the University of Toronto might want to compare this ideal setup with what’s in Bahen 3200. Its lighting gives glare without illumination; the dark wooden counters make the optical mice jerky; and the bar stools are guaranteed to make your lower back ache after an hour. In short, it looks like the kind of places that get full-page spreads in architectural magazines…)
A pad of gridded paper and several ballpoint pens.
I often make notes for myself when programming, or draw box-and-arrow diagrams of my data structures when debugging. I used to keep an editor open in a background window to do the former, but when my wrists started acting up, I discovered that taking my hands away from the keyboard for a few moments to scribble something down provided welcome relief. I also quickly discovered that the odds of me being able to read my own notes the next day rose dramatically if I used gridded paper to line them up.
A heavy mug for coffee or tea.
I don’t know why, but a styrofoam cup, or a normal teacup, just isn’t as satisfying as a little hand-sized ceramic boulder. Maybe it satisfies my subconscious Neanderthal urge to club my computer to death when it misbehaves…
A rubber duck.
One of computing’s many apocryphal stories holds that someone—Brian Kernighan, maybe, or Dennis Ritchie—keeps a rubber duck next to his computer. Whenever a bug takes more than a few minutes to track down, he puts the duck on his desk and explains the problem to it. Why? Because speaking out loud forces you to marshal your thoughts, which in turn highlights any contradictions or missed steps that you hadn’t noticed while everything was just swirling around inside your head.
A squirt bottle of glass cleaner and a box of kleenex.
I can’t stand smears on my screen. They drive me nuts. Whenever I’m showing something to someone, and they actually touch my screen instead of just pointing, I have another Neanderthal fantasy, except this time it’s not subconscious…
A chess set.
I’m a very bad chess player. Luckily, so are most people, so it’s usually possible to find someone at my level for a ten-minute game at lunch. Other programmers I know play euchre, or knit—a programmers’ “stitch and bitch” session can be jaw-dropping to listen to. Few people can focus for more than a few hours before their productivity drops; it’s better to acknowledge this, and take a break in the middle of the day, than to say, “Must… keep… coding…” and produce garbage that just has to be rewritten later.
Three small rubber balls.
As I’ve hinted above, my hands and wrists hurt if I type for more than an hour or two. I recently discovered that if I roll a couple or three small rubber balls around in one hand while I’m thinking, doodling, or sipping tea, it can stave off the aches and pains. A former colleague swore by his Chinese medicine balls, except those made a tinny twanging sound, which eventually led to a Neanderthal moment.
Books.
You can find a lot on-line, but it’s hard to google with your feet up on your desk, and even harder to fold down the corners on web pages. When I want API documentation, I use the web; when I want a tutorial, I still prefer the printed page. Right now, for example, I have Tapestry in Action, Hibernate in Action, the Java Cookbook, a hard copy of the Subversion command reference, the latest edition of Andrew Patzer’s book on JSPs, and JUnit Recipes within reach.
Trainers.
Back when I was a part-time grad student, I had a settled routine: I brought three sets of gym gear to the office on Monday morning, worked out at lunchtime on Monday, Wednesday, and Friday, and took my stuff home at the end of the week. After about two months, I came in to find that my co-workers had hung a little chandelier made of air fresheners over my desk. Since then, I’ve tried not to inflict my laundry on others, but I still store my shoes in my bottom drawer.
Pictures.
Everyone wants to feel at home; everyone wants to make wherever they are uniquely theirs. I do it by hanging four postcard-size pictures wherever I work: a Spanish woman spinning thread, St. John Coltrane, a fully-dressed man in a bathtub reading a book, surrounded by phones that are off the hook, and a sketch of Edinburgh. A photograph of five of my nephews goes on my desk beside my scribble pad. They’re all laughing, because my brother was mooning them as my sister-in-law took the picture. One day, perhaps, a hippo dressed up like a superhero will join them all…

Uncategorized

The Art of Cutting Corners

September 16th, 2004
Comments Off

According to one of my students, I tell the same jokes, the same way, every time I lecture. I apparently make them sound fresh each time, though, so I guess that’s OK.

I give the same introductory lectures to each new group of students as well. In contrast with my jokes, that isn’t because I can’t think of anything new to say. Instead, to paraphrase Tolstoy, it’s because all successful projects are alike, while all failures fail in their own way. If you want to deliver usable software on time, without burning out, there are a few things you simply have to do, so I figure I might as well explain them at the start of each term.

The first thing I explain is how to run a meeting. Circulate the agenda in advance by email, or write it up on the whiteboard; circulate minutes and action items afterward; and be polite (which in practice means “give everyone else a chance to speak too”). It isn’t rocket science, but right now, out there, a room full of supposedly intelligent people are wasting an hour of their lives because they aren’t following these simple rules.

The second thing I explain is what schedules are for. Contrary to popular belief, a schedule’s primary purpose is not to tell you what you’re supposed to be doing on any given day. Instead, its purpose is to tell you when you should start cutting corners. Suppose, for example, that you have ten weeks in order to accomplish some task. Five weeks after you start, you’ve only done the first four weeks’ worth of work. What are your options?

  1. Denial. This is very popular, but doesn’t actually solve the problem.
  2. Tell yourself that you’ll just have to work harder, and start putting in evenings and weekends. This is also very popular, but ultimately self-defeating. When you’re tired, the quality of your work goes down; any ground you gain by working ’til three a.m. you lose again to extra debugging and rewriting.
  3. Ask for more time. Groups working in industry often do this (usually in combination with the previous solution), but it usually isn’t an option in an academic setting. Instructors have to submit marks at the end of the term; as far as the university is concerned, whatever hasn’t been done by then might as well not be done at all.
  4. Cut corners, either by doing less testing (which is quickly self-defeating), or by updating the schedule to reflect the rate at which you’re actually working, and dropping features that you already know you won’t be able to finish in time.

Let’s return to the earlier example. At the start of the project, you believed it would take ten weeks. You’re now half-way through, and you’ve done 4/5 of the work you were supposed to. Looking at it another way, your estimates for how long sub-tasks would take were too optimistic by about a quarter. You should therefore go back to your schedule and add 1/4 to each task’s estimate. That inevitably means that some of the things you originally planned to do now spill off the end of your ten-week window. That’s OK; it’s a shame you won’t get to them, but at least you know it now, and can start taking action (like lowering your customer’s expectations) well in advance of delivery.

But how do you decide what to cut out? The Nevex group I work(ed) with used a very simple procedure, which previous undergraduate teams I’ve supervised have adopted as well. When the project starts, make up a list of the features you intend to implement. Rank each feature High, Medium, or Low on two different scales: how important you think it is, and how long you think it will take to implement. That gives you a three-by-three grid, which you then use to make decisions. Things which are quick to do, and important, are scheduled first; things which will take a long time, and are unimportant, aren’t scheduled at all; and things which are on the diagonal in between are put on the back end of the schedule. That way, when the time comes to cut corners, the things that fall off the wagon either aren’t very important, or couldn’t be done in the remaining time anyway.

The only hard step in this process is coming up with time estimates for particular tasks. The first time you have to do this, it is very frustrating. “How can I possibly guess how long it will take to write a database persistence layer for some Java classes? I’ve never used a persistence layer before!” Well, yes, that’s true, but you’ve had to learn other new technologies before, and then apply them in courses. A guess based on that experience might be off by a factor of two or three, but it probably won’t be off by a factor of ten, and even if it is, it’s better than no guess at all. Plus, everyone in the Nevex group discovered that the more estimating they did, the better they got at doing it. We had to add several completely new things every time we released a major version of our product, but in four and a half years, our worst schedule slippage was only six weeks on a year-long development cycle, with only a handful of late nights (where “late” means “work until 9:00 p.m. once a week”).

Taking scheduling seriously is one of the things that distinguishes good software development teams from bad ones. It’s unfortunate that you’ll only get to do it once during this course, since you only really see the benefits the second time around, but I hope that even once will be enough to convince you that it’s worth doing.

Uncategorized

Knowing What You Know

September 16th, 2004
Comments Off

With time, and a little luck, almost anyone can do something once. The only way to know whether you actually understand how to do it, though, is to see whether it takes you less time to do it a second time.

For example, as of 10:30 this morning, I finally have some JUnit unit tests of Hibernate running inside Eclipse on my Windows laptop. There are still a few loose ends—I haven’t figured out how to add “.” to the classpath for Eclipse‘s built-in JUnit runner, for example, so I’m using a launch configuration instead, which means that I don’t get a green bar to show me when everything’s working—but I can create and populate a database, fetch and update rows, and so on.

Problem is, I still can’t make it work on the CDF Linux machines. I know what the problem is—again, getting “.” on the classpath—but the magic spell that works for me on Windows has no effect on Linux. I therefore don’t believe that I really understand yet how all the pieces fit together.

My only consolation is that a lot of other bright people (my co-instructor, the students) are having just as much grief. The fundamental problem is that what I have to specify things that I of as single pieces of information several times in order to make Eclipse happy. For example, I have to add “.” to my classpath once to compile, again for each of my run configurations, and once again for Ant. This is probably a consequence of Eclipse‘s modular architecture, but I don’t care—it’s still bad.

So, while I feel I’m making progress, I won’t really know until the next time I toss Eclipse onto the table in front of a dozen students. That will be when I find out how much I’ve actually learned.

Uncategorized

All work and no play makes a dull team

September 14th, 2004
Comments Off

In the summer of Hippo, we managed to completely drain half a dozen whiteboard markers. Meetings alone wouldn’t have accomplished this: it was the combined use through both meetings and random silly drawings that used them up. Now that the summer is over, I wish that it was possible to chart the time that the whiteboard markers spent between work and play, on the progress graph.

Prima facie it may seem like the amount of time spent coding and the quality of the code would be directly correlated. But I’ve found that one of the most important elements of effective team software development [1] is the time that the team spends together when work isn’t on their minds.

I don’t think that it’s coincidence that we mentioned these extra activities several times during the post mortem. They’re what make a team into a team. They build trust, confidence, communication, recognized specialization, and make a world of difference to morale.

Here are ways in which the Helium team was brought closer together:

  • Common lunches [2]
  • Goofing around on the whiteboard
  • Maintaining enough confidence that we could joke about failure
  • Hippo T-shirts
  • Tuesday lunches
  • Defiling the mascot
  • Our very own coffee maker (mmmmm…)
  • Trips to 7-11
  • Penny tossing
  • Office pranks
  • Singing the same annoying songs over and over again [3]
  • Playing our videogame of choice (You Don’t Know Jack)
  • etc.

Each and every one of these activities contributed to making the team work. It will be interesting to see how the Pyre teams this term find their own ways to become a Real Team. My advice? [4] Find excuses to hang around each other after hours. Your code will benefit, the project will benefit, and — most importantly — you’ll be happier while working on it, and maybe make some new good friends. We did.

[1] Slightly more important than even code comments. (But slightly less important than coffee.)

[2] Even when people brought lunches from home at the start of the summer, we tried to drag them along for anyway. Food consumption was the secondary activity at these lunches compared to an opportunity for conversation.

[3] HippoHippoHippo (to the tune of BadgerBadgerBadger), ‘enry the 8th, I shot the sherif, etc.

[4] …which I’m sure you were all holding your breath to hear ;-)

Uncategorized

Accidental Horizons

September 14th, 2004

A quarter of a century ago, in The Mythical Man Month, Fred Brooks pointed out the difference between intrinsic complexity and accidental complexity. Intrinsic complexity is how hard a problem really is; accidental complexity is how much harder we make it by creating inconsistent APIs, fragile configuration files, or GUIs that don’t accurately reflect the state of the world.

Over the past couple of years, I’ve realized there’s a similar difference between intrinsic horizons and accidental horizons. A “horizon” defines what you can see from where you’re standing; in a technical field, it is the boundary between problems you know how to solve, and ones you don’t. There are therefore two ways a field can make progress: by inventing new ways to solve problems, or by pushing out the horizons of the ways they already have. When we do the latter, we often discover that the horizon was accidental. There was never anything to stop us from solving those problems before—we just didn’t think to try.

Which brings me to Hibernate, the object/relational mapping package we’re using in Hippo. A Hibernate-based application has three parts:

  • the Java classes representing things you want stored in a database;
  • an XML configuration file describing the mapping between those classes and your database tables; and
  • the rest of your program, which works with Java objects, and trusts Hibernate talk to the database on its behalf.

When everything is working as it should, this is an excellent division of labor. The problem is that when things aren’t working, there is no easy way to figure out why not [1]. I have Hibernate‘s log messages, but they don’t tell me why my attempt to create a session object throws an exception. I have Hibernate‘s source, so I could step into the session’s constructor and trace the fault if I wanted to, but I don’t think I should have to. Hibernate is supposed to abstract away the details of working with databases directly; as far as I’m concerned, it should also abstract away the details of debugging my interactions with the database.

Which brings us back to the notion of an accidental horizon. The IDE I’m using, Eclipse, is really just a framework for hosting plugins. Some of these (like the syntax-aware Java editor) come bundled with it, but many others (like the Checkstyle plugin) have been developed by third parties. The Apache web server is built in a similar way: its core only knows how to load plugins, and route message traffic through them. All the stuff we use it for—resolving paths, launching CGI scripts, and so on—is implemented in a plugin that ships with the distribution, but hundreds of others exist as well.

So why aren’t debuggers built this way? When I something as complex as Hibernate, why can’t I also create a debugging plugin to help Eclipse show me what Hibernate is doing? There are no intrinsic technical obstacles [2]; as far as I can see, the only reason it isn’t supported is that, well, no-one else supports it either. It is a purely accidental horizon, and the sooner it’s eliminated, the more productive we will all be [3].

Now, if you’ll excuse me, I have some Hibernate source code to step through…

[1] See also Joel Spolsky’s article on leaky abstractions.

[2] Which isn’t to say that it wouldn’t take a lot of thoughtful design and hard work to create the right hooks in Eclipse for developers to plug into. Master’s thesis, anyone?

[3] See also my article on extensible programming systems.

Uncategorized

Guards! Guards!

September 13th, 2004

I’m a big fan of Terry Pratchet. How can you not be a fan of someone who dedicates a book to “the Palace Guard, the City Guard, or the Patrol… Whatever the name, their purpose…is identical: to rush into the room, attack the hero one at a time, and be slaughtered…”

Eclipse and Subversion made me feel like one of those poor guys today. Here’s what happened:

1. I checked out a copy of Hippo onto my laptop, and created a directory in which to do the training exercise we’ve assigned to the incoming students.

2. I fired up Eclipse to create a Java project in that directory. I put my Java source files in a sub-directory called src, the JAR files my project needed in a sub-directory called lib, and created an empty directory called bin for Eclipse to put compiled class files in. I used svn add to add all three directories to the repository.

3. Reading the Hibernate documentation, I thought I had to put the mapping file that described how to store my Java objects in a database in the same directory as the compiled class files. All right, no problem—I created bin/LoanRecord.hbm.xml, and used svn add to add it to the repository.

At this point, my workspace looked like this:

.project                        # Eclipse project file
.classpath                      # Eclipse classpath file
.svn/                           # Subversion metadata
bin/
    .svn/
    LoanRecord.hbm.xml          # Hibernate metadata
lib/
    .svn/
    hibernate2.jar
    hsqldb.jar
src/
    .svn/
    LoanRecord.java             # my one and only source file

4. I started up Eclipse again, and rebuilt the project, then dropped back to the shell to check the project’s status with Subversion:

$ svn status
?      bin/LoanRecord.class
    S  bin
!      bin/LoanRecord.java

Uh, what? I understand that SVN doesn’t know about the class files in the bin directory, but what’s with the “S”? And why does it think that there ought to be a file called bin/LoanRecord.java?

An hour and a half later, after chatting with Ben Collins-Sussman and others on the Subversion IRC channel, we [1] have an answer. When Eclipse builds your code, it copies the .svn sub-directory from the src directory into the output bin directory. Yup, you heard that right: Eclipse overwrites the .svn sub-directory in bin when it compiles [2].

Now, if I could track down Eclipse‘s developers, they would probably either say, “It’s not our fault—Subversion didn’t even exist when we started work,” or, “Yeah, yeah, we know, our bad, sorry,” but I wouldn’t accept either. I might forgive them if Eclipse popped up a dialog saying, “Hey, you have some files here that I don’t know anything about, do you mind if I crush them?”, but it doesn’t even do that. Trampling on files and directories that aren’t yours is just plain rude; anyone who has been programming for more than a few months ought to know better.

The fix is simple: don’t add the bin directory to the repository [3]. But let’s do some math. Assume there are 10,000 Subversion users out there. Assume that a quarter of them are using Eclipse, and that one in ten of those make the same mistake I did (adding the compile output directory to the repository). If each one of them wastes two hours figuring this out (half the time it took us), that’s 500 hours, or twelve and a half working weeks. You can write a lot of software in twelve and a half weeks…

Which is what we have to do, now that Eclipse isn’t getting in the way. Onward!

[1] David James, Michelle Levesque, and Greg Wilson.

[2] Eclipse doesn’t do this to CVS sub-directories, presumably because its developers use CVS themselves, and fixed the problem the first time it came up. Favoritism, that’s what that is…

[3] We tried using Eclipse‘s inclusin/exclusion filters to prevent it from overwriting the bin/.svn sub-directory, but couldn’t get that to work.

Uncategorized

My Development Environment

September 13th, 2004

After I leave HP, I’ll be doing development on at least four different machines: my lightweight Windows XP laptop, the desktop XP machine at my girlfriend’s, Pyre (a single-processor Linux box), and the CS department’s CDF lab machines. I’ve been keeping a log of the tools I’ve installed; here they all are.

Cygwin
A Linux-like environment for Windows, which brings with it a lot of other tools (like SSH and GNU Make).
Eclipse
The Java IDE we’re using for Hippo. I also have its plugin for Checkstyle (the Ant and JUnit plugins came with Eclipse), and will be installing Spindle, a Tapestry plugin, soon).
Putty
An open source SSH client for Windows and other platforms.
Emacs
Yes, I still use it for quick-and-dirty text editing, particularly when I’m logged into the Linux command line via Putty.
Firefox
My preferred browser, partly because of its tabs, and partly because so few hackers write Mozilla-specific exploits.
Microsoft Messenger
One of the biggest annoyances on the web today is the way different instant messaging systems refuse to talk to each other. I tried using Trillian, which speaks multiple protocols, but (a) it kept locking up on me, and (b) I could only run one protocol at a time, which kind of defeats the purpose. AMSN is an open source multi-platform client for MSN, so using it doesn’t lock me into any particular OS.
WinSCP
An open source SCP and SFTP GUI. Very nice interface; I often leave it running in the background.
OpenOffice
An open source alternative to Microsoft’s Word/PowerPoint/Excel trio. I haven’t been impressed by OpenOffice’s UI or stability yet, but it’s free, and runs on Linux and OS X.
Apache Web Server
Yeah, its configuration files are a pain, but it’s easier to use than IIS, and at least I don’t have to figure everything out twice.
Tomcat
A Java servlet container; we use it for running Hippo.
Subversion
Our version control system of choice. I still use CVS to maintain my personal web site, but expect that I’ll move to Subversion at the end of this term (once I know how to avoid its sandtraps).
Hibernate
An object-relational mapping system for Java; we use it in Hippo.
HSQLDB
A lightweight pure-Java relational database that we sometimes use with Hippo.
Postgres
The “real” database we use for production deployment of Hippo.
Tapestry
A web presentation layer built on top of Java servlets; we use it in Hippo.
Python
My current favorite language; I build a lot of little tools in it, and will be using it in the book I’m writing for the Pragmatic Programmers.
Pine
The old-fashioned text-mode mail reader which I use on the CS machines. Why a text-mode mail client? Because the only way I could access the department from behind HP‘s firewall was via Putty.
SpamBayes
A very cool spam filter which plays well with Microsoft Outlook. Haven’t yet figured out how to hook it up to Pine, but I’m working on it…
GIMP
The GNU Image Manipulation Program, which I use on those rare occasions when I’m feeling artistic.
BlitzIn
A free real-time chess client. My brother and I used to have accounts, so that we could keep track of our games. These days, I log in as “guest” and play unrated lightning games when I should be rewriting Java cryptography code.
SquirrelMail
I don’t actually have this installed on my personal machines, but it runs on the other third-bit.com server, which a few of us use for personal stuff.
WebChess
A rather clunky PHP application for managing on-line chess games. I have five games going with friends right now; I lose more than I win, but I always enjoy playing.
Movable Type
A popular web logging system. Like SquirrelMail, it runs on our personal server; it also runs the Pyre blog.
PDFCreator
Pretends to be a printer driver, but creates PDFs.

Two tools I wish I could keep using after I leave HP are:

Perforce
The best version control system I’ve ever used. Our group at HP has been using it for almost four years, and my boss figures it saves 6-8 developer weeks per year for a team of about a dozen programmers. If Subversion had copied Perforce a little more closely, the world would be a better place today…
Microsoft Visual Studio 6
The only entry in this list without a URL, because Microsoft no longer offers it. I haven’t used Visual Studio .NET on a real project yet, so I don’t know how it measures up, but VS6 was fast, reliable, and had a great debugger. Eclipse has a long way to go to match it…

Uncategorized

Subversion Grief and Usability Testing

September 13th, 2004
Comments Off

I sat down yesterday morning to work through the first half of the warmup exercise we’ve given the Hippo students. My goal was to have Hibernate persisting my book loan records by the end of the day.

Didn’t get there. Instead, at some point I used Subversion‘s “move” command to move files from one directory to another. From what I now know, this actually creates a branch inside the repository. The visible effect is that when I add or modify files in one directory, do an “svn commit”, and then do an “svn status”, it shows my “bin” folder as being branched, and (this is the spooky bit) copies source files from “src” into “bin”. This is a Bad Thing, and I am Unhappy. (I believe the capital letters are merited.) What’s worse, I can’t figure out how to undo it. I have even deleted my working copy of the repository, used “svn rm” to delete my personal sub-directory from the repo, and re-created everything, to no effect.

Michelle Levesque eventually pointed me at this section of the Red Bean book on Subversion. The key phrase for me is this:

At first glance, the answer may seem obvious: just compare the latest trunk tree with your latest branch tree. But beware—this assumption is wrong, and has burned many a new user!

Um, question: if the way you do things burns many new users, then why don’t you change the way you do things? I don’t know the details (yet), but I’m 99% sure that the reason this potential for burns exists is that Subversion‘s designers made one technical decision over here, and another over there, and only later realized that the collision between the two resulted in what Brooks called “accidental complexity”, i.e. made something harder than it needed to be. (I know it doesn’t have to be this hard because it isn’t in Perforce.)

Now, if software had to meet the same standards as children’s toys or automobiles, its designers would be forced at this point to go back and re-think the things that led to the potential burn. “Having the duck’s head pop off is really funny, but a two-year-old might swallow it… Let’s see what else we can come up with.” Not software, though; you can do pretty much anything with software.

The situation is exacerbated by the fact that even systems intended for widespread use, like Subversion, are only usability-tested by their authors in the early stages of their development. By the time users like me get them, their author have internalized and rationalized traps like the one I stumbled into, or say, “Yeah, I know, but it’s too late now.”

And no, more documentation is not a solution. I can’t count how often I’ve heard developers say, “But it’s in the docs—jeez, we spent hours writing the docs, why don’t you read them before you start doing stuff?” The answer is that you have to build things for people as they are, not as you wish they were. As a friend of mine who works in public health says, abstinence is not a practical cure for HIV/AIDS, because in practice, people won’t abstain. Similarly, if you’re billing your version control system as an easy step up from CVS, then you must design it on the assumption that most of the people using it won’t read beyond the first half page of documentation before starting to run commands.

This is the main reason Hippo‘s user interface is so conservative. I’d like to experiment with weblogs for project management instead of mailing lists, and with wikis for bug tracking instead of database systems, but it would take half a dozen iterations over two or three years to come up with interfaces that newcomers in a hurry would be able to use without an unacceptable amount of grief. I don’t like tree displays of threaded mail conversations, but everyone we’re trying to reach is already familiar with them, and there are literally hundreds of systems out there from which we can draw inspiration. In the end, it won’t matter how many cool things Hippo can do: if ten percent of its users lose an afternoon because a seemingly innocuous command has done something unexpected that they can’t immediately figure out how to unwind, we will have failed.

Uncategorized