blog

Let's talk about coding

Agile Software Design

In Agile development, Big Design Up Front (BDUF) is considered an anti-pattern. As with any pattern and anti-pattern, people — engineers in particular — have a tendency to treat them as rules, as laws that Shall Not Be Broken (TM). The unfortunate side-effect can be that in teams where that mode of thinking prevails, any up front design is eschewed, to the detriment of the team’s project.

This article explores an alternative to this either/or mentality, Rough Design Up Front (RDUF), and contrasts it to the preferred SCRUM method of Emergent Design.

Emergent Design

Let’s start with the simpler concept of Emergent Design (ED). In a nutshell, it refers to the practice that any design — including changes to existing designs — should be an activity like any other, that will be scheduled as part of the SCRUM process. So far, so good.

But the emergent property refers in particular to the fact that any design completed in this way should effectively only go to enough detail to cover the current, or at best a small number of sprints. When the design is implemented in those sprints, it’s time to redesign everything to match the requirements of the subsequent sprint(s).

Rough Design Up front

By contrast, RDUF aims to bring a larger number of incremental changes under the hood, by providing a design framework early on that leaves out a large amount of detail.

The best analogy that comes to mind is a crumple zone/crush space in mechanical engineering. But that analogy also requires some explanation…

Design Goals

Overall, software design of any kind has one main goal: to provide a guideline that allows developers to quickly write program code implementing actual desired features. We need some up-front design, for a number of reasons, and both RDUF and ED acknowledge them:

To coordinate efforts between different developers working on related code.

To validate design. Design by committee may be bad, but every design will improve through constructive criticism.

Incidentally, it’s worth understanding that the main criticism of Big DUF is that it’s devilishly hard to anticipate every contingency that may influence design, so doing it all up front is all but doomed to failure.

Code Quality

What may not be clear for non-developers — and in fact, it may not be clear for every developer — are the benefits of detailed vs. no design:

Pros

Detailed design gives the developer no room for interpretation, and therefore optimally speeds up their feature implementation activities.

No design allows the developer to react to any change in circumstances and requirements immediately. Code stays malleable, i.e. open to change.

Cons

Code becomes brittle, that is resistant to change.

Code invariably starts to rot very fast, as ad-hoc changes typically only reflect the most current change in requirements.

Note that I write invariably here. That’s not entirely the truth, as given enough time, any iteration may result in perfectly clean code. The problem is that enough time is a concept that extremely few development team have the luxury of experiencing.

At the core of this conflict, then, lies the question of technical debt: do you incur debt via code rot, or via code brittleness?

Technical Debt

The viewpoint of technical debt, then, starts to explain how the concept of a crumple zone applies to code. You want to provide some relatively fixed structure in order to prevent code from rotting too fast, whilst at the same time leaving some no-design zones in order to prevent code brittleness to set in.

That’s your crumple zone: some parts need to remain stiff, others need to crush easily. The right balance of both provides for safety, not one alone in exclusion of the other.

Compromise

In the end, neither RDUF nor ED will provide for this avoidance of technical debt on their own; the beauty of the situation is, though, that they’re complementary rather than alternative approaches.

Above, I associated the crumple zone concept firmly with RDUF, and it’s true that RDUF attempts to provide just enough structure up front to allow future iterations to fill in the blanks. But that’s almost precisely the idea behind Emergent Design! Split future iterations into a quick design adjustment session and a code session, and you’ve combined both concepts seamlessly.

Comparison to Test/Behaviour Driven Development

There’s a fairly interesting overlap between the apparent design approach contrast discussed so far, and the differences of Test- and Behaviour Driven Development (TDD and BDD respectively).

In the compromise between RDUF and ED, it’s fair to summarize that the former is more concerned with overall system architecture and code design, whereas the latter is more concerned with the blank spaces in between (note that I say more concerned rather than exclusively concerned).

In much the same way, BDD is more concerned with ensuring overall system behaviour, whilst TDD is more concerned with ensuring local code behaviour. In fact, test cases in BDD deliberately try to avoid defining the how of behaviour, and focus more on the what, unlike TDD test cases.

Conclusion

In practice, a good combination of Rough Design Up Front and Emergent Design lead to the lowest technical debt — though I wish anyone could claim that it abolishes technical debt entirely! As it turns out, each design practice has a counterpoint in development methodologies that helps ensure keeping to their design goals. It may help you to adopt them both!