One of the abstract terms we use in software development is business value. It’s one of many. As a industry, we are very good at producing ambiguous terms and acronyms that end in DD (TDD, BDD, DDD and the list continues). But that’s a different matter. I often find myself in conversations on what business value is, and more importantly how do we quantify it. And, most of the times, I end up making a case that there are also other aspects that bring value, apart from the features themselves. Because, let’s be realistic, features provide the first, and most direct, source of value in software development.
But there are other aspects that bring value in a software product, and one of them is software design. While more and more people do acknowledge its importance nowadays, it is at the same time one of the aspects that gets overlooked during the actual implementation. And most often than not, it’s not because we don’t know how or don’t care about it, but there always seems to be a conflict between delivering features and improving the design over time. When in reality there is no conflict at all.
No design vs good design
To better understand this, let’s take a closer look at two different approaches, from the perspective of the cost of building features over time. This is not new. It is based on the “Design stamina hypothesis” by Martin Fowler, which he used to make ca case for refactoring. The y-axis represents the cost of adding features and x-axis is time.
In the first example (blue line), we are focusing on simply getting features out the door. Which feels great when you are starting with a clean slate, but after a while, bad design tends to compound. Working with the code becomes increasingly difficult, but then it also constraints new code to be done in the same wrong way. As you can see, it’s an exponential function, since more effort (and thus higher costs) is required to add new features.
The other approach (red line) is focused on guiding the design over time, while shipping features. This is basically what evolutionary design is all about - growing the system in an iterative and incremental way, by adding the minimum amount of code to satisfy business needs. It already starts with a higher costs, and it is an exponential function as well. Just with a much lower basis.
There is a point in time however when the cost of just shipping features and the cost to deliver features while guiding the design is the same. Let’s call that T0, as shown below. After T0, evolutionary design is pure gold.
JB Reinsberger introduced, more than a decade ago, the concept of accidental complication. In short, every feature or functionality added to an existing project has two cost elements:
cost of feature = f(g(e), h(a))
- Essential complication or g(e): how hard a problem is on its own
- Accidental complication or h(a): the complication that creeps into the work because we are not doing things right. It is irrelevant for this discussion what “not doing things right” means. It can be anything from dealing with organisational complexity, getting requirements or environments on time, to code that needs to be written to accommodate the new functionality.
Taking care of the design allows us to reduce the accidental complication. Otherwise, by ignoring the design, we can even reach a point when the cost of continuing with the existing code base is higher than the cost of starting over. The same JB Reinsberger calls this “Project Heat Death”.
Back to business value
The only problem with T0 is that nobody can predict when that is. If your product will be put to rest before T0, or it is something that is just going to be used once, you could argue that design is not that important. I’ve had this situation with a software built for a new product launch campaign. Everything was supposed to run for a month, up to a certain moment, and then shut down. It was something tailored specifically for that moment and the customer did not want to reuse any parts of it for anything else.
However, these are edge cases, as in the majority of time, we are building software that is used and continuously developed for a much longer time. Whether that is before or after T0, we cannot say for sure. But better safe than sorry, otherwise we just end up putting that prototype in production.
Without defining now what it means to do things right, or what a good design is anyway, we’re reaching the natural conclusion that by constantly spending effort to improve the design of our software, we are actually protecting our capacity to deliver features over time. And coming back to where we started, features were directly linked to business value, weren’t they?
To conclude, there is no conflict between delivering features and improving the design. Both go hand in hand and are meant to help us deliver business value at a steady pace.