Sixth Myth of Agile

Welcome to the sixth instalment in my series about the Ten Myths of Agile software development.

In this post, I’m going to explore some fundamental misunderstandings about code.

Code is a complicated and expensive artefact to develop – so much so that we need to employ specialists to write it. Here’s the source statement that is open to a lot of misunderstanding:


Where do things go wrong when we try to be Agile …?

We favour working code over comprehensive documentation


The Code is the Design

This statement usually crops up when someone asks where the design spec is. This question might be asked by a third party client, a tester, a sub-contractor, a project manager, a new member of the team or a quality auditor.

The statement is not untrue. Source code does indeed describe the form and function which is the essence of a solution. We divide the code into files, classes, methods, attributes and so on. It specifies what needs to be done to solve a problem. So code does specify a design – it defines what will happen when it runs.

The code communicates, directly or indirectly, what actions must be performed by some physical or logical processor. The design specified by code is therefore a very low level design. Unfortunately, the statement that “the code is the design” is soaked in misconception, and often dripping with excuses.

Code is just one small artefact within a wider solution. In isolation, a piece of code is useless – like a nail in a draw of other nails. The code does not define the system for which it provides features, like a nail doesn’t define a chair and a wheel doesn’t define a car. So the code is not “the design”.

The Agile manifesto is trying to tell us that we don’t need to duplicate the specification provided by code in other forms. It’s also trying to tell us that we should minimise the amount of effort we spend on creating, maintaining and reviewing specifications. More importantly, we need to realise that it’s inherently inefficient to describe what the code does after we’ve written it. That’s not Agile.

But this does not mean that we should avoid specifying what the code must do. It also doesn’t mean that avoiding a design process is the a way to reduce our documentation overhead.

A code artefact must satisfy some design specification. For example, we need to define the form and function of the wheels that are part of a car. The wheel’s specification allows it to be manufactured and integrated with the car. Once integrated, it supports the movement of the car.

Therefore, some design process must identify the need for a wheel, its size, how it connects to the vehicle, and so on. Likewise, some design process must identify that we needed to write a piece of code – for example, acting upon some message received on an interface.

Code provides part of a solution. Code is the result of design.


Code is Self Documenting

If I read some lines of Python code, I can usually work out what that code does. If the code contains comments, this becomes even clearer. So it is true that the code in a high level language describes what it does.

However, it does not follow that I should need to read hundreds or thousands of lines of code to understand how my product works. Likewise, if I have no code, how do I know what to write? How do I prove that I have added value to the product? It seems unreasonable that I should have to read the dotnet codebase to understand what my PC application does, or read minified Javascript to work out how to test my website.

Code only documents the tiny part of the solution for which it is responsible, and not the feature it supports. In many systems, the code is so abstract that we can’t tell when it runs, let alone how it contributes to our solution. Code might document itself, but it does not describe the solution.

Clever tools exist that can help us navigate and assess our codebase, but the documentation they produce adds little value to the solution. A codebase that has full Doxygen documentation is unlikely to tell us much more than the code, because it is derived from the code. Furthermore, it doesn’t do much more than a good IDE with the right plugins. Therefore, when we use tools like Doxygen or SciTools’ Understand to document our code retrospectively, we actually create the comprehensive documentation that the manifesto suggests adds the least value.

More importantly, the act of documenting the solution does not mean that we have applied any design process. A document by itself doesn’t improve the quality of the solution. If we spend time drawing diagrams and writing words to describe a bad solution, the solution is still bad.

Documentation is not design.


Having said this, automated documentation tools can still add value. Firstly, they can raise the profile of the issues and reveal that improvements are needed (i.e. if the document’s a mess, the code’s a mess too). Secondly, they can provide some reference for a test team to write impartial tests. However, it is clearly more efficient to share a design specification between coders and testers before the code is written, so those tasks can proceed in parallel.

We Don’t Do Documentation, We’re Agile

This is one of the most significant misinterpretations of the Agile manifesto.

For some products (for example, start-up concepts, prototypes or framework-based solutions), the granularity of a good user story can be enough to meet the business goals. A small set of stories and their related tests can neatly summarise one version of an application. The application is abstracted from all the complex details of its underlying platform.

However, for high integrity systems, we would struggle to describe the solution well in user stories alone, especially if those stories start to conflict over time. If we have no design specifications, then we don’t know which parts of the code are current or legacy.

Let’s walk through the typical anecdote used to justify avoiding design specs …

We let our code evolve through every sprint as we learn more about the solution. We embrace change. When we think the code is doing what we want, we don't waste time documenting it. We want to add more value, so we add more code, because code = value.
We don't need to describe our solution, because we've created working code. If anyone wants to know how it works, then they can go and read the code because the code is self-documenting.
If we really need to document the solution, then we generate it automatically. The tools create something that looks like a document, and it's free. 

Reading between the buzzwords …

evolve ... this word heavily implies nature will take its course. As developers, we are in full control of the solution. We develop the solution to meet shared criteria - it doesn't grow its own arms and legs or mutate into something we did not expect.
embrace change ... this is a very fashionable expression in Agile communities. We will always embrace changes to code because we're paid to do it. However, the business may prefer that we change as little code as possible to add value. The business embraces changes that add value predictably - but not continuous fiddling and buggy releases.
don't waste time ... time is wasted when we don't add value. Time is also wasted when:
  • we write the wrong code, and then debug it and write it again.
  • we reverse engineer the code to understand how it works.
  • we find it hard to add new features or identify the root cause of bugs.
code = value ... code is definitely valuable, and it's also the most expensive part of the system, given the time it takes to get it working. Code solves the problem, and provides the solution. But more code does not necessarily add more value. Often, less code will create more value, which is why the manifesto counter-deploys the mantra:

Simplicity – the art of maximising the amount of work not done – is essential.

working code ... this is is defined by testing. It might work on my machine, but does it work for my customer? Do we read the code to work out what to test? This is a rhetorical question - tests are derived from what the code is intended to do, not what it actually does.
go and read the code ... I have actually been asked (or told) to do this by more than one  developer. It usually means I need access to a repository, a specific IDE (and license) and a number of hours, days or weeks to trace a feature through from some entry point of the code, if I can find it. A diagram is often far more efficient, and does not waste time.
generate it automatically ... automated documentation provides no context for the code. As I described earlier, it rarely provides any more value than the code itself and creates the comprehensive documentation that we're aiming to avoid. It doesn't really matter how little it cost to generate, because we still have to spend the same amount of time understanding it. Documentation that is generated from code is more worrying, though, because it suggests that no design process was applied to create the code and share the understanding with the team. 

So What’s Your Point …?

Documentation that only covers the local view of the code does not reveal how it interacts with other objects to achieve a goal. Without describing the wider interaction, we fail to communicate the design. We can’t see the rationale behind certain decisions; it’s hard to predict performance or discern the distribution of responsibility across the architecture, and ultimately, it’s difficult to prove the solution.

Without a design process, we fail to establish the right solution for a product. Without applying the appropriate patterns, the code will likely be harder and riskier to develop.

A design process affords us the time to think about the right solution for our product, in the short term and the long term:

  • The output from the design process is a specification.
  • The specification shares the understanding of the critical system form and function across the team.
  • The specification helps us write the right (or “righter”) code.
  • The specification allows us to write tests, in advance or in parallel.
  • The specification helps define a plan that can be translated into backlog tasks, much like the drawings for building a house.
  • The tasks in the backlog helps to manage dependencies and organise the integration of features over time.

The cost of the design process is the investment that reduces the risk of issues downstream.

When approached pragmatically, just enough of the right specifications (or “documents”) should save time rather than wasting it. If we do not allocate time to design activity, then it’s likely we will need to allow for more than double that effort in bug fixes, feature development and refactoring. If I try to build a house without creating the blueprints first, then I can’t expect to build a very good house.

Leave a Reply

Your email address will not be published. Required fields are marked *