We’re regularly told to keep things simple; to produce simple designs, to keep your application “globally simple”, to reduce complexity. But it can often seem as if simplicity is itself a goal, regularly quoted as best practice without explanation. So what should it mean in practice and how can the “simplest solution” be achieved?
I believe the origins of this quest for simplicity lie in Extreme Programming’s (XP) suggestion that we produce “The simplest design that could possibly work” (based on the subjective TUBE qualities of simple code design). It’s great but rather vague advice which is regularly used as a justification for pedestrian solutions, never ending “refactorings” and both naive and, ironically, over complicated designs.
There is an excellent chapter in “Extreme Programming Explained” (Ken Auer, Roy Miller) all about this idea, unfortunately I’ve been unable to find it online but you will certainly not regret buying the book. In it Ken Auer explains:
Simple Design Can Be a Business Decision
And it is this focus on involving the customer that is too often ignored. Here’s an example from a recent project:
Customer: We want to be able to perform a batch of searches as other departments often give us long lists in Excel and we’ve got one coming in next month that’s really important
Product Owner: Ok, so we’ll need a new web page for the upload of the list, then it’ll take a long time to do the search so we’ll need to have a way of getting the results back to you asynchronously, maybe when you log in, and you’ll need to know what searches are in progress…
Project Manager: Hold on, this is already sounding like lots of work, what’s the minimum we need to do to get the feature ready for this upcoming list next month?
Customer: I need to search for every item in the list to see it it is a full or partial match of anything currently in our database
Developer: Well, the search isn’t difficult and since the system has access to the file system we could just provide you with a folder to drop the list in and the system could pick it up automatically. It could search through the names in the background then drop a file of results back to the folder when it’s done, whether that takes a few minutes or hours.
Customer: That’s everything I need for next month…
The result of this “simplest possible” design was:
- The scope of the task was kept small
- The complexity of the system increased (this was inevitable as we just added a new feature)
- The customer was able to try out the new “bulk search” quickly as fewer features enabled a faster turnaround
- The customer got to decide whether any more money needed to be spent on this feature after trying it
Stories are feature-boxing
So the simplest design, in this case, had nothing to do with how the code was written, rather it was concerned with how this valuable new feature could be delivered most effectively.
Our single story was effectively a “feature-box” which, like Scrum’s time-boxing, allowed the development effort to focus on what was the minimum necessary to achieve the customer’s initial goal.
Does the simplest solution have the simplest code?
There is a misguided notion that the simplicity of the code’s design, or some idea of architectural simplicity, is what we should be aiming for with every completed story.
Simplicity in code is where the design and the implementation get confused, the code simplicity is always going to be a compromise of developer ability, re-use, timescale and budget with the developer creating the most effective code within those constraints.
The simplest code is no code at all
Minimum Viable Product (MVP) is closely related to this idea of producing the most effective solution to a business problem since there is no benefit in producing anything more than the simplest solution possible so that we can delivery quickly and start learning about the feature we just added and, possibly, remove it if it doesn’t work or isn’t necessary; no code is always simpler than some!
Iteration can reduce code complexity
If code’s simplicity, that is lack of complexity, is your goal then treating simplicity as a business decision will still help. It’s counter-intuitive but adding features iteratively usually leads to “simpler” design – that is code that is cleaner, more cohesive and more manageable.
How? I’ll use the original example of a “bulk search” to explain; consider these 2 scenarios:
- The team builds the entire Web-based solution first suggested by the Product Owner before releasing it. When the customer gets to use the product they find that the search is not accurate enough and the format of the results on screen is unfriendly. The development team fixes the problem by modifying code for the search and display.
- The team builds the “file system” approach – a way to perform the search spending minimum time on ingest and presentation of results. Having released the search, the customer finds it is not accurate so for the next iteration the team rewrite the entire search based on the customer feedback, it’s released and the team moves on to improving the ingest and then eventually the presentation.
The second case will produce more coherent code because each iteration is focussed on releasing an effective solution which inevitably means less code is produced per iteration which in turn means throwing some or all of that code away is easy.
The first case leaves the team saddled with more complex code (since it is for more features) which, at the very least, makes it harder to refactor and at worst causes the team to dabble in minor changes around the existing solution, usually because they spent so much time implementing it seems wasteful to start again. In fact the waste has already occurred.
The second approach gives the customer more control over what is delivered, turning simple design into a business decision, not an architecture decision, product design decision or development decision.