Monday, September 25, 2006

Gnosis of Diagnosis

For a few days, I have been procrastinating writing about the ill distribution of debugging skills among developers, then I have read a letter sent to Computer and published in the September 2006 issue under the evocative title of "Deskilling Software Engineering".

The author states that "diagnosing a problem remains an art and requires skill". I like the fact that he evokes art because there is truly a part of instinct in the difficult task of figuring out why a system fails or refuses to do what it is supposed to. Instinct is hard to define and quantify, so what else a developer would need to be successful when chasing bugs?

From my experience, I have retained what I consider the three topmost traits that helps in the art of diagnosis:

  • Systematic thinking: software being complex systems, they take a lot of various inputs (configuration, data, user entries...) and turn them into various outputs, with usually one being the desired one. Modifying too much inputs at the same time does not allow to figure out the impact of each modification on the output. Programmers without rigor or a varnish of scientific method will often try to modify many parameters at the same time, which will ruin any attempt to empirically figure out what is causing the issue.

  • Pugnacity and thoroughness: some problems are hard to tackle, especially the ones that require a long setup time before being able to test what is happening (think of rebooting a server to release a particular resource before testing). Others require to be able to read through extensive traces without panicking! I have seen many non-rookie developers unable to read a stack trace and I understand why: it is intimidating and requires an effort of will to delve into.

  • Hands-on experience: as the saying goes "once bitten twice shy", nothing replaces years of experience, dub it, the numerous blows and slaps you get creating then solving bug after bug. With the current trend of devaluing hands-on experience in favor of managerial skills, hourly rates for programmers are a clear signal that there is nothing good in keeping writing code. Hence when someone gets good at its job of writing code, he is kindly asked to stop doing it and moved to a more desirable (and rewarded) position, leaving projects with rookies who will have to go through years of blows and slaps to become efficient bug killers.
Off course, these traits can help in other software development activities as well. But their lack always impairs any diagnosis endeavor.

Tuesday, September 19, 2006

The price of common sense

In "Agile Software Development with Scrum", Ken Schwaber stated that:
"Scrum demands the liberal application of common sense".
I think this applies to any agile methodology: common sense is a driving force for any practice that relies on empirical management and self-organizing teams.
Now, I have just read "Unsystematic Engineering", an IEEE Spectrum article where Robert W. Lucky dares saying out loud what everybody knows:
"(...) systems engineering is often based on experience and common sense, and we know where common sense fits in the hierarchy of things that justify a high salary."
Okay, we all work for the beauty and love of our craftsmanship and not for the bottom line, but is not this pattern of under-valuing the qualities we have learnt to be the right ones, something that gets harder and harder to accept?
So, what should be the true price of common sense? Could not it be evaluated by measuring the cost of projects that failed because of a lack of it?

Monday, September 11, 2006

Dependable Dependencies

With the advent of human friendly build platforms like Maven 2 or Buildix, I am expecting to see improvements in the way programmers manage their dependencies. Of course, I might be too candid but proper tools can give enough incentive for developers to consider dealing with their dependencies in a less hip-shooter style and therefore benefit from more predictable, reproducible and automated build sequences.

Classical patterns of classpath quagmire I have noticed include:

  • Deployment of libraries needed only at compile time: this is the usual rookie error, where you typically end up with things like servlet.jar in WEB-INF/lib. A little explanation is usually enough for this to not happen again.

  • Deployment of libraries needed only at unit test time: less harmful than the previous error, it is simply disturbing to have applications deployed with unit test and mock libraries merrily packaged altogether.

  • Deployment of platform libraries in excess or in different versions: this is typically the case for applications that are designed to be deployed on "any" J2EE compliant server. Very often, it will contain libraries that are already present in the server, sometimes in different versions, which will lead to hard to track issues. This is usually done just in case your particular server does not support a particular version of a J2EE sub-component, and, unless you run on the exact same server the vendor is using, you will typically end-up shaving a dozen of useless jar files off the libraries' folder!

To my sense, when it comes to dependencies, a NoClassDefFoundError is much better than a ClassCastException, or, in other words, too little is better than too much. It is indeed easier to figure out what are the missing libraries rather than what are the version conflicting ones.

Anyway, as build tools help us to formalize what is the role of each of the library used by our projects (compile? test? deploy?), we can expect to see better handled and dependable dependencies around us in the near future.

Tuesday, September 05, 2006

A Simple Pattern for Prevayler

While implementing Prevayler in a cool project I will detail in a near future, I of course met the need of doing it in a way that will allow me to unit test my prevalent system independently from the persistence mechanism. This would allow me to exercise all the code implied in the business logic of my domain without actually bootstrapping the prevalence engine.

I came to the simple pattern shown below:

The IDomainManager interface exposes all the domain related methods. The MemoryDomainManager implements this interface and contains all the serializable data: it is the actual root of the prevalent system and the only object to thoroughly unit test.

The PrevalentDomainManager is merely an empty shell that delegates all calls to the MemoryDomainManager, wrapped in Prevayler transactions. It also contains the basic code to bootstrap the persistence engine.

Note that the MemoryDomainManager object does not implement any synchronization mechanism: Prevayler, thanks to its support for transactions, blissfully takes care of this.

Having unified MemoryDomainManager and PrevalentDomainManager behind the IDomainManager interface naturally allows to unit test all the components relying on the domain objects without using actual persistence and to deploy the productive application by designing it to use the prevalent implementation of the said interface.

So, how about dropping your prejudices and jump head first into the jolly world of Prevayler?

* For those of you who wonder, Prevayler is a purely object oriented persistence framework that offers a solid alternative to the now classic "RDBMS+O/R mapping framework" pair. It received a well deserved Productivity Award in 2004.