Although most of you probably heard of this before, today Worse-Is-Better triggered a chain of thoughts in my head that goes way back.
When I entered the Java development community the hot stuff in my side of the aquarium were RUP, UML and Design Patterns. The approach to software engineering that I learned was to foresee as much as I can and put those ideas in the design. As many others I would often use a design pattern where it fitted, without giving thought if it was really necessary there.
As a result of that Aranea was born. From the point of view of software design Aranea was almost perfect. It was based on independent components with few interdependencies, it foresaw situations like AJAX and desktop deployment long before they were implemented.
By the time we started working on JavaRebel I got somewhat disillusioned in those practices. Therefore, although I originally wrote a throwaway prototype, we ended up evolving it without ever rewriting entirely. Although the code was not directly a mess, it definitely preferred simplicity over unnecessary abstraction and not a single design pattern was hurt while hacking at it.
Both projects were large and complex enough to serve as a case study. But like the original author of the “Worse-Is-Better” essay, I still can’t choose between the two. In fact, I’m not even sure that these are separate approaches, it may very well be just the amount of sloppiness the project can take before it collapses.
Now, sloppiness is a good negative word. It is also fitting, since it refers to the character of the development process, rather than its success.
A very good example of sloppiness in today’s Java ecosystem is Hibernate. It is designed with simplicity in mind and it’s code is a tangled mess of just enough design. Nevertheless it’s a hugely successful project which provides a clean enough API to make developers happy. It is designed evolutionary and at some point developers had to give up full backward compatibility for new features.
On the other side of the scale is Spring. It’s code is precise, well organized and object oriented to the point of nausea. It has a layered design with the simple abstract core and never had to sacrifice backwards-compatibility.
In their own way both these projects are about equally complex. And I don’t mean lines of code, but rather how hard is it for a newcomer to start hacking at their code. In the end it’s almost as hard to unravel the layers of abstraction as to jump through the sloppy code. The main difference is perhaps that Spring offers more extension points whereas Hibernate is somewhat harder to debug.
“Wait”, you say, “Does he really suggest that sloppy code can be good? Why just yesterday I had half a heart attack looking at it!”. The trick is that I’m comparing two highly successful open source projects made by some of the best people in the Java community. This makes a whole lot of difference.
In the end it’s unsurprising to come to the thesis propagated by the agile community: in the hands of the right person any approach will work. A talented leader will trade the right things for sloppiness and a clueless newbie will create an overcomplicated abstract mess. My experience tells me that in my next project I will use just as much sloppiness as the project will take without collapsing and make sure the people around me can handle it as well.
What do you think? Can discipline protect a project or will it create even more complications? And what should be the guiding star when designing it?