Years ago, Bruce Eckel (of the excellent Thinking In Java series, a must read for newcomers to the language) started work on a patterns book. This was about the time that everybody was writing patterns books, and as a result the book never really hit press and is still under development, where it may remain for life. However, the notes are available here, and are worth a glance if you like well stated rehashing of common sense.
I do. And I got quite a lot out of his “Design Principles” section, wherein he rephrased the impetus behind SOLID in a way that I feel transcends that collection of OO software principles in a way that can be applied to any computing task (UI design, DSL design, database design etc). I have a copy of my own rewording of his attempt on my wall.
One of these principles is called “Complexity,” and paraphrasing:
The more random rules you pile onto a developer, rules that having nothing to do with the problem at hand, the slower he can produce. And this effect is exponential, not linear.
In other words, if you take a competent developer, provide him with a set of requirements, and he produces slowly: you’re asking him to do too many random things. And if you were feeling masochistic, you could work backward from the magnitude of this poor performance and take its logarithm to uncover just how many random and “unnecessary” requirements you imposed to create this quagmire.
Of course, in software there really are no random requirements. Everything you ask a developer for, you think you need. And in some cases, you’re quite right: if you’ve got an application handling data more interesting than, say, a blog post about software, you’re probably going to need a boatload of things that aren’t called for in the explicit business case. Things that we architectural nerds like to call “quality attributes.” Things like supportability, flexibility to changing business requirements, scalability, performance, multi-tenancy, auditability, transactionality and so on.
The way I see it, developer velocity is rarely a problem of not typing fast enough. Instead, it’s a function of how many quality attributes they need to address, in addition to their core requirement, to produce an acceptable deployment artifact, and again this is an exponential problem.
There is no silver bullet to this problem — it’s inherent to the task of software development — but there are some ways to reduce it. Using tools that make one or more attributes trivial or “free” is one — for example, a cache framework that scales from in memory to distributed with a minimum of fuss. Building on top of a quality AOP framework, thus allowing the incremental addition of certain attributes that can be described as aspects (transactionality, caching, monitoring, auditing, etc), is another. Baking essential quality attributes into the architecture is a third — think of web frameworks that make SSO, auditing and error logging a function of the web container, leaving applications free to ignore these concerns. Finally, an organization can take a layered approach to development, in which the implementer of the software builds the business function to completion and then adds (and tests!) one quality attribute at a time, working from the most essential to the least essential until you run out of time.
This last one is the tactic taken, often accidentally, by most “high performance” startups, and it is likely the least feasible for more mature organizations. The layered approach owes its performance to attitude summed up in the acronym YAGNI — You Ain’t Gonna Need It [some feature], and the reason it’ll work poorly in a more mature org is due to an opposing acronym YWFW — Yeah We Freakin’ Will. Your sales staff, your operations staff, the gals and guys on the frontline phones, they know: we will need auditability, some day, and we’ll need to manage the business process and force changes to the state machine, and so on. We need all of those things, and if we need them on the day of release we don’t want some smarmy designer apologizing for the tools we asked for in the first-dang-place.
So okay. Maybe you are going to need it. The same rules apply. The attributes that are most essential: bake those into the architecture. The next most essential, build those robustly into your toolset via good APIs injected into or enhancing your business code using a convention over configuration approach. And as a last resort, build them into phases of development that come AFTER you’ve successfully solved the use case.
In theory, this would be the fastest way to develop software, but don’t worry. You’ll still find ways to muck it up. Resisting good-but-wasteful ideas and identifying cross cutting concerns are both really hard during development, and it’s not like you’ve a surplus of architects to help out. But do consider identifying these as a primary output of your retrospectives or, god forbid, post-mortums.