23 April 2007

Use a $%*& SocketAppender

Pretty much everyone uses Log4J, hopefully through a facade layer like Commons-logging or JDK1.4 Logging. However, almost no one I know uses the SocketAppender.

Everyone has to establish a balance between using the debugger and writing log() statements. It's annoying to leave behind logging that was relevant only in the context of fixing a bug, but also bad to have no data on production issues because your debugger was your only source of diagnostics while you coded.

So, assuming you have some log statements, you ought to be able to watch them on one screen (you have several, right?) while you navigate through your app on the other. And, when there's a stack trace, the log entry should still only occupy one line on your log viewer, and you can summon a nicely formatted stack trace for that line when you like.

Too many developers are ignoring logs (how many times do I have to answer your question with "did you check the log?") and about as many are eye-parsing through log files. Use Chainsaw or Lumbermill already!

It's pretty easy to do:
<appender name="lumbermill" class="org.apache.log4j.net.SocketAppender">
<param name="RemoteHost" value="localhost">
<param name="Port" value="4445">
</appender>

Also, why is no one maintaining the log viewers? I tried to take over Lumbermill, which hasn't been active for 1.5 years but I thought I saw Robert Bushman claims he's still working on it.

Workarounds

This morning we are fighting with a bug in the Microsoft MSI installer, that deletes part of the bundled JRE from our app after an upgrade, as described Here. There is a workaround listed on the Microsoft knowledgebase site for this bug.

A workaround is a "temporary" solution to a bug, that is created in lieu of fixing the bug and re-distributing the software. This happens when a manager sees the cost of fixing the problem as higher than the cost of creating the workaround. The problem, as all software engineers know, is that there is an under-appreciated hidden cost - the quotes around the word "temporary". It's not temporary, it will always be there and will always suck, because once the software works, it's too risky to change it.

My last government client was a great case study for how repeated use of workarounds can literally box you into a corner. We used the full Oracle J2EE stack, which is pretty buggy, especially if you're using the off-in-the-weeds use cases that the Oracle QA department didn't get around to. For every bug, another workaround from the on-site consultant. Management didn't see a problem with this, because a workaround appears to offer the same value as a fix, except for that pesky "temporary" bit - but hopefully that will be someone else's problem. In the end, workarounds on top of workarounds left the system fragile and unstable.

In contrast, look at the Mac OSX Save As... dialog. Apple recently posted on their propaganda blog about the keyboard shortcuts you can use in the dialog. It occurred to me that this tip applies to all applications, which makes the user trust that if they learn this behaviour, they'll be able to apply it whenever they encounter this dialog. That consistency is an attribute of quality software, and it's possible because Mac software (generally) uses the system-provided functionality to do lots of stuff.

If this were a Microsoft OS, when a problem was found in the Save As... dialog, rather than fix it, there would be a workaround. Each programmer can just make their own dialog box, that looks the same, but has the extra flag or modified data structure or whatever avoids the bug. And now, each of those developers can introduce differences, like being lazy and leaving out the keyboard shortcuts. Now the user can't trust that anything is consistent, so they avoid learning faster ways to use the "computer" as a whole.

To be fair, it's not realistic to expect workarounds to disappear. As a lead, sometimes you find yourself in a situation where a proper fix pushes out the schedule, and you weigh the costs and benefits, including how bad the workaround will be if it lives forever, and what implications it could have on the design. And you feel dirty.

Some people feel so dirty that they won't go along with it. There's a spectrum of developer reactions, from indignation that leads to an indefinite delay of the release, to an irresponsible lack of concern. But even if they're forced to give up their ideals and do some messy hack, ultimately, developers know that quality software has zero workarounds, period.

SO, I think perhaps the best metric for how bad your software is: how many workarounds it contains. Repeatedly leaving bugs in the software is a bad practice that not many managers really understand. There's a good reason for programmers to get out the resume paper when they see a culture of accepting workarounds on their project.

11 April 2007

Darwinian Evolution of Software?

In high school math class, we learned about gradient descent. The idea is to find the low point on a graph, like finding the lowest elevation in a geographical area. Although it sounds pretty straightforward, there is a problem doing this: we can tell if something is a local minimum, but not if it is globally the lowest. The algorithm for gradient descent can be summed up "go downhill", which will eventually find you to a low point. It's possible that right next door to your low point, however, is a much lower point, but you would have to go uphill to get there so you're never going to.

Lots of things behave like this, which I've always found interesting. Rivers lie where they do because they seek out the lowest point. And evolution acts this way too, because the best it can do is to improve on what's currently available. Each generation can have mutations based on their parents, and if it's an adaptive mutation, the new trait lives on. But, if the improvement is dependent on something else happening first, and that prerequisite is detrimental, then the improvement isn't possible. That's like going uphill to look for a new minimum.


My favorite example of this is that the back our eyes have a hole where the optic nerves bundle together and pass through the eyeball to get to our brain. This is needed because the nerves come out of the front of the receptor cells, instead of the back. If the nerves came out the back, we wouldn't need the hole, but we happened to evolve the receptor cells and optic nerves in this order, where by the time the eye was finished, the pipes were layed wrong. If only the intelligent designer could refactor, right?

From http://www.2think.org/eye.shtml

Ok, now I'll make my point. In software, we should be intelligent designers, and we should be able to refactor. If we made an eye with a hole in it, we could probably fix that in release 2.0. And yet, in a larger and slower scale, software really does "evolve," and critical mistakes aren't corrected if it would mean the technology is temporarily crippled. Instead, we build on them and move on to the next layer of abstraction with those funky things still frozen in that layer.

Around 2002, as the web was turning into a place for applications to live instead of just reference material, a need arose to have appealing and highly functional user-interfaces in a web browser. We wouldn't have chosen to turn a web browser into a rich-client platform if we had a big meeting about it, but they were already deployed on everyone's desktop. It was clearly descending the gradient to just put an application on that platform, since we weren't sure our users would put up with downloading and installing something without their employer making it mandatory. Also, we need it to be cross-platform since we don't want to make any assumptions about what hardware our users have. Java tried to get onto the desktop, which would have made more sense, but it didn't catch on.

So then Web 2.0 came along, and improved the browser's ability to present a decent UI. We deploy rich-client applications in a browser using the XmlHttpRequest javascript feature. Javascript has to be the most abused programming language ever, and at first I was aghast that AJAX would push it to do so much. It felt buggy and unnatural, and again I think this was an evolutionary process - we're writing web applications, we have developers who know CSS and DHTML, lets put them to work.

Bruce Eckel wrote about this in his article on moving to Flex. He gives a nice history of the presentation layer, finally ending up on Adobe Flex. I'm sure many of us are a little annoyed by the frequency of the Bruce Eckel "thinking in Flex" ads that have been all over the place lately - it reminds me of how I wanted to get away from T-Mobile when they had Jamie Lee Curtis everywhere. But Flex does make evolutionary sense - now that we've evolved these capabilities to write web applications, let's improve our toolset and move to ActionScript and have some better graphics and animation capabilites. We don't have to deploy much to clients because again they mostly have flash plugins in their browsers already.

So now here comes Apollo:



Jesse and Gabe were experimenting with it, and from what I could tell, this is a neat way to take the current evolution of Web 2.0 presentation technology and bring it back to the desktop again. This is where I think of the hole in the eye - it's great to have a true desktop app that can interact with peripherals and be responsive and work offline, but some of the technology stack comes from the web. CSS wasn't intended to layout a rich-client desktop app, was it?