Thursday, December 18, 2008

Snow

It rarely snows in Seattle, but it is snowing today; we've gotten about 4" in the last few hours. I live at the top of a steep hill so this basically means I can't leave home for the next few days. Fortunately or unfortunately, I work from home. Thus, the view from the Seattle offices of Terracotta:

Sunday, December 7, 2008

Through A Glass, Darkly

Although I get paid to write software, most of my time is spent understanding other people's software. I find that difficult: the available information is usually fragmentary, inconsistent, and more than I can hold in my head at one time anyway. It's like trying to read a mural on the side of a building, through the holes in a construction fence, as I drive by. I get little snapshots of partial information and I have to try to piece them together in my head. Sometimes the big picture I develop is entirely wrong, or missing big chunks.

Example: I've been working with Hibernate for more than a month now, but I still don't really understand exactly how it actually works. I only discovered tonight that it creates proxies to camouflage and control all my objects. This is sort of like wondering why your friends are acting a bit odd and then discovering that everyone on the planet except you has been replaced by space aliens.

Java has so dang many layers of obscurity that it is really hard to figure out precisely what code is actually being executed. The application code you write is just the tip of the iceberg. What with Spring, Hibernate, Terracotta, JUnit, the Hotspot compiler, and all the other frameworks and code enhancement tools we use, the program code itself is almost just a hint to the system. Maybe we're getting closer to the holy grail of being able to tell the computer what we want done, rather than how to do it.

Friday, December 5, 2008

Maven Continues to Suck

Maven is supposed to be a tool to support collaborative software development.

Maven is based on the concept of software modules, each of which is versioned, and which have interdependencies. Let's say version 1.0.2 of MyThing depends on version 2.4.1 of YourThing, for instance. Now, what if I want to make some changes to both YourThing and MyThing? Well, there's a special version called "SNAPSHOT" - as in 2.4.1-SNAPSHOT - that means "the latest and greatest up-to-the-minute version of YourThing version 2.4.1". Setting aside the discussion of how the concept of a "version of a version" is inherently flawed, this introduces a big problem: it does not distinguish between changes I make and changes somebody else makes.

Case in point. Another developer at my company, and I, both are working on modifications to a module that our other stuff depends on. My modifications won't ever be shared with the rest of the world, they're just for my temporary purposes, but nonetheless I need them. The other developer, however, made some changes and committed them to version control. When I went to do a build of MyThing, Maven checked dependencies and noticed that there was a new SNAPSHOT of YourThing.

In a sane world, a collaborative software tool would notice the conflict, and perhaps notify me: "a newer version of YourThing is available, but it conflicts with your local changes - do you want to upgrade and lose your changes, or keep the stale but familiar stuff you've got?" The default, of course, would be to keep what I've got; after all, if I made some local changes, it was presumably for a reason.

Not Maven, though. Because I said SNAPSHOT (so that I could make changes locally), Maven silently and transparently discards my local version and updates me to somebody else's changes, at a random time of its deciding (typically, in the first build I do after midnight, of any project that happens to depend on YourThing).

Fortunately, the other developer's changes contained a serious bug. I say fortunately, because otherwise I might not have noticed that my changes had been silently discarded, and I might have spent a lot of time trying to figure out why my code, that used to work, no longer did.

What kind of collaborative software development tool is it that can't gracefully handle the simple case of two people working on a shared module?

Maven is not really a collaborative software development tool, it seems. Maven is a tool for letting one person develop a single module of code, with external dependencies on an otherwise-static world. That does not describe any software project I have ever worked on.

I keep hoping to see the light, and discover that I'm wrong about Maven. But it keeps on sucking.

Wednesday, December 3, 2008

Code Reviews

A spare set of eyes is always useful, so most software teams have some practice of code reviews. There is huge variation from team to team in how code reviews are actually done, and in my experience how any given team does it is an axiom of the corporate culture; suggesting a different approach is met with the same sort of response as if you'd suggested, say, using an abacus instead of a personal computer. (I haven't tried this at my current employer, Terracotta, yet.)

The range of practices I've been directly involved with includes:

  • No review at all. I haven't seen this in a long time.

  • Self-initiated. If you want a review, you find a peer and beg some of their time. Surprisingly, this has been my experience working on Eclipse, and at a number of other teams; it may reflect resource constraints or perhaps just the fact that I've been in the industry for a long time and people foolishly think I'm less likely to write bad code.

  • Recommended review for major work, especially for new developers. This too is pretty common in my experience, and is the approach taken at Terracotta.

  • Mandatory review of all code before it's committed to version control. This approach was taken by a team I worked on in the '90s at Microsoft, and resulted in some of the best code I've ever written or seen. (The project made it through beta but was then axed by management; it conflicted with corporate strategy.)

  • Pair programming, two sets of eyeballs at all times. I've only tried this a little bit; it did seem like we wrote pretty good code, but boy was it exhausting.


Along with that range is the question of how, exactly, the code gets reviewed. Approaches I've tried include:

  • Over my shoulder. The reviewer looks over my shoulder as I walk through the code on my monitor, explaining it.

  • Over the reviewer's shoulder. Same, except that the reviewer is the one driving.

  • Independent review, meet with feedback. Each reviewer is given the code to review, and given some time (a day, perhaps) to review and come up with comments; we then meet to collect together the feedback. The meeting is typically moderated by someone other than the developer, and there may also be a designated scribe to collect the comments.

  • Collective review. Like "over my shoulder", except that there is more than one reviewer. Having multiple reviewers makes it psychologically harder for any one reviewer to change the flow of the review: if someone wants to go back and look at a previous file, they have to interrupt someone else.


And then, there's the question of media and presentation. If code is being given to reviewers, it may be presented as a set of changes to the existing code, or as a finished document; it may be presented as hard copy or as files. The review may be conducted in person, over a video link (like WebEx or Elluminate), by audio conference, or by email.

The costs and benefits vary a lot depending on approach. I've gotten the best reviews out of the "independent review" approach: it creates a social dynamic where there is some shame for any reviewer who fails to find a particular bug that others do find, so there's incentive for thoroughness, but it also lets each reviewer bring their skills to bear in whatever way and at whatever pace works best for them. The collective feedback (whether in a meeting or in group email) is a good way to learn advanced techniques, subtle errors, and so forth.

But this approach is also expensive - I used to budget half a day to participate in a review like that, between the reviewing and the feedback meeting, and if three or four people have to spend half a day for each developer who wants to check something in, it's easy to spend all your time reviewing. Also, this strategy works poorly for small changes or even large refactorings of existing code, because reviewers tend to get distracted by things that really should be fixed, but that have been that way forever and is not in the scope of the current changes.

The opposite end of the curve is probably the "go borrow someone's eyeballs if you need them" sort of review. This misses a lot of errors, but sometimes you get so deep into a problem that you lose track of the obvious. A second set of eyes can see that you failed to close an open stream, or that you're doing something that a library routine already exists for. A second set of eyes will probably miss subtleties like locking on the wrong object.

Personally, I'm afraid that of all the possibilities, I get the very least out of collective review over video conference. The audio and video quality is generally very poor, so it's hard for me to follow what anyone else is saying; if my attention wanders for a moment, it's socially awkward to ask people to back up, so I tend to lose track of crucial details; and since it's the code owner who drives the review, any assumptions they have about what is and is not important become shared. Often bugs lurk precisely within those assumptions.

Finally there's the question of what sort of comments matter. In the most formal review process I was part of, we prioritized comments exactly the same way we'd have prioritized bugs:

  • pri 1 was a bug that would make the code fail significantly or a design flaw that would prevent the code from working with the rest of the product

  • pri 2 was a more minor bug or design infelicity, or possible performance improvements

  • pri 3 was a bug that wouldn't actually affect the code as it stood but that might cause problems during maintenance or if someone else tried to use it in a different way

  • pri 4 was typographical stuff, like use of whitespace, naming of internal variables, and the like.


Using a structure like that, we went through each module of code, collecting and discussing comments in priority order. Pri 1 bugs had to be fixed before the code could be checked in, and generally another review meeting would be scheduled to review the fix, depending on the developer's track record. Pri 2 bugs were usually fixed depending on the amount of effort required. Pri 3 bugs might be deferred or ignored. Generally priority-4 bugs would be relegated to email, that is, the scribe would just collect them from the individual reviewers and tack them onto the followup email without them ever being discussed in person, to save time and avoid religious wars; the developer would be expected to make a personal decision about whether to implement the sugggested change. Doing it this way also let us directly compare the relative effectiveness of reviewing versus testing.

I'm against any review process that takes a lot of people's time to do a shallow review. Either review thinly and cheaply, or deeply and expensively, but don't fool yourself into thinking that a lightweight review process is finding all the interesting bugs.