In the article: “To spec or not to spec? That is the question”, I explored the Agile concept that the Product is the Spec. That it doesn’t make sense to attempt to create a complete, fully-detailed specification for a software project, in the way that is common for other industries like architecture and automotive production.
I concluded that a complete specification really doesn’t make sense in the software world. However, the argument said nothing about the logic, or otherwise, of investing time in sketching, designing and planning software. Just in taking that to the extreme and creating a fully-detailed specification.
The problem is that, as humans, we tend to reason in a very simplistic way. We like fixed categories and absolute truths, and we find it difficult to deal with fluid, overlapping categories and sliding scales.
Since a full specification makes no sense, we might jump to the conclusion that the right course of action would be to do no design work at all: Start coding straight away, produce rapid working builds and seek feedback on them. This feedback can then be used to steer the software in the right direction over the course of multiple iterations, with no long-term design at all.
It should be clear that this is an unreasonable leap. However, it is founded on a valid experience amongst developers. As an example, here is a quote from ‘Rebel Code’ by Glyn Moody, a history of Linux and Open Source:
“The way [Linus] codes is similar to Richard Stallman’s method: “I never use paper” Linus explained. “If I have something that’s tricky, and I have to think out exact details, I occasionally write down small figures, stuff like that. But in general, what happens is that I do it straight on the machine; if it’s something major, before I start coding, I just think of all the issues for a few weeks, and try to come up with the right way to do it – there’s completely no paperwork”.
How is it that developers can start to code without design? I don’t think it’s just that Richard Stallman (the man behind GNU) and Linus Torvalds (the originator of Linux) are great developers. Rather, there is something about code itself – the way it works, its basic properties – that allows for this kind of approach.
First, code can be freely iterated with very little cost: it can be reworked and modified as often as necessary. There is no equivalent of metal fatigue, or the loss of quality that comes from putting too many layers of wallpaper on top of each other. (This is not to suggest that code cannot become messy and poorly structured, just that once it is refactored, there is no way to tell that it was ever less than perfect.)
In addition to this, code is highly modular. Sections can be moved around without impacting function. Different people can work on parts of the code and then splice them together. A whole section could be removed and replaced by a different version that provides the same functionality, but with a better overall structure or performance.
In other words, decisions made in one section of a piece of code can be completely independent of those in the rest of the code. Of course, there are limits to this, and unintended interaction between parts is a classic source of bugs. (These challenges tend to lead to a particular kind of ‘design’ activity: governance by rules and expectations, as opposed to planning or sketching up front. This distinction deserves an article of its own.) However the important point to understand is that this degree of modularity is unusual – you can’t simply decide to make all the floors of a building different sizes and shapes, for example, since they rely on each other for support.
Another important property of code is that it is ‘intangible’. What I mean by this is that the structure of code cannot be discerned by simply using the software that it generates. That a piece of software is slow and buggy is usually clear enough from interacting with the user interface. But there is simply no way to guess at the structure of the underlying code without looking.
I believe that this combination – iterability, modularity and intangibility – creates a situation in which design work such as sketching structure up front is not needed. Design is all about mitigating the impacts and costs of later steps in a process, but with code, those costs are low. So long as the code ultimately supports the required functionality, then it makes no difference how it was written (by one person, or several, in one go, or through a series of iterations), or exactly how it is structured.
This valid experience with code can lead us to over-extrapolate that up-front design is simply not needed in software projects.
But wait! I hear you cry, it’s not true that developers don’t design, there’s lots of design going on in software projects – that’s what the architects are doing most of the time. I agree. Software architecture is a design activity. But that is exactly where things get interesting.
Rather than considering software to be a single homogenous entity, it would be better to think of it as being a composite made up of at least three pieces: the code, the system architecture and the user interface. These three elements do not have the same properties.
System architecture is intangible and modular, but it is not easy and cheap to iterate. It involves physical devices and locations; and choices about data storage, bandwidth and other issues that have system-wide and long-term impacts. That is why up-front design is such a feature of the discipline.
The user interface is certainly not intangible – it is the public face of the software. And while it may not be technically expensive to iterate the UI, there are often practical challenges. Whilst elements of the interface may be modular (changing the design of one dialog box doesn’t affect anything else), the overall design is not. Choices made around the general layout and application model impact everywhere (if you decided to put the toolbar at the top, you can’t just move it to the side occasionally). There is also the problem of legacy – once users are accustomed to software working one way, there is a barrier to change.
As a result, it is very important to invest in up-front design for the UI. At least to establish the basic operational model. Details can be added and refined over time, but the basics need to be right to avoid costly rework later on. An iterative process of sketching and design, whilst gathering feedback from users and stakeholders, is far quicker and cheaper than iterating the working code for the UI.