What’s the best way to deliver and grow systems?
There are several possible approaches.
One approach is pure waterfall: “plan the work and work the plan”, phase by phase, with a big bang delivery at the end. Measure progress by “(estimated) % complete”.
A second approach is used by many Scrum teams: develop a Release Plan with all the planned stories and other work, then build the software incrementally in Sprints. Measure progress with a burndown or burnup chart, showing amount done so far vs. planned. (Teams vary on whether “done” means “shipped” or (blech) “potentially shippable”.)
A third approach is known as evolutionary or iterative-and-incremental: do a little planning and exploration up front, but focus mostly on learning and delivering as you go. Measure progress by value delivered.
|Gather needs and plan up front
|Gather needs and plan as you go
|Months to Years
|Weeks to Months
|Minutes to Days
Why Use an Evolutionary Approach?
Why? Ignorance. As competition has increased and delivery times have shortened, it becomes important to omit less critical things and to look for the capabilities that offer a big edge. When the market changes daily, it’s risky to plan what to deliver months or years from now.
Mockups and user stories can help us explore user needs, but real use is often the only way to reveal the true needs.
Evolutionary approaches create a dynamic of rapid delivery and learning, so we can shape the system as we go.
Thinking in Pictures
The evolutionary approach is less familiar, so it can feel unnatural. To help overcome this, people have devised metaphorical pictures to convey how it works.
While I’ve used the term evolutionary, “evolution” is an imperfect metaphor. We’re not talking about a literal battle for the fittest of competing, living applications (though the market may resemble that).
Wikipedia defines evolution as “change in heritable traits over successive generations”. When we speak of evolutionary approaches, we’re suggesting that there are different versions over time. As with evolution by natural selection, we expect the environment (feedback) to be an important factor in what survives. Finally, we accept the possibility of dramatic change over time.
Look beyond “evolution” to the other pictures that show how we go from a minimal system to a more complete system over time. By exploring, deconstructing, and comparing across them all, we can get a better understanding of this important strategy.
Not Evolutionary Design
Let’s start with an image that is not evolutionary design:
Bag of Parts to Components to Finished System
This is not evolutionary: we have nothing useful until the very end.
The metaphor of growth is better - something starts small and gets more complex as time goes on:
Seed to Seedling to Flowering Plant
Emergence is an idea related to systems theory, suggesting that rather than being fully planned, a structure can arise from the interaction with its environment in a complex, not-fully-predictable way.
Adaptation and Targeted Complexity
These variations focus on the system changing over time. They make it clear that it’s useful from early on.
Scooter to Bike to Car to Plane
By Henrik Kniberg, used with permission.
Henrik Kniberg’s picture captures a system delivering early value, and changing over time to become ever more capable.
Footpath to Gravel Road to Highway
This variation can show the same road at different stages of its life. I used to live near Boston, and the joke was, “Getting around Boston is easy - you just have to think like a 17th-century cow.” That reflects a deep truth: paved roads are usually put where the need is already demonstrated.
Basic Instrument to 6 Strings to Full Guitar
(Design by Joshua Kerievsky, illustration by Chris Peterson.)
Musical Instruments evolve: mountain dulcimers have gone through similar changes to these guitars. Old dulcimers had “staple” frets under only one string, and only had 7 notes. Later, they got frets that went across all the strings. Later still, people added one and then another fret to get notes not in the basic scale. Today, you can get chromatic dulcimers that have all the notes.
Notice that each variant is playable, and you might even be able to evolve the same instrument from stage to stage.
Cupcake to Cake to Wedding Cake
This picture is inspired by the idea of a Minimum Viable Product. If you want to get a sense of what the final cake will be like, make a cupcake with the filling and icing you expect to use. By starting with cupcakes, you can get the whole taste before you commit to the whole thing. This is also a reminder that you not only need key components but also key user experiences. It doesn’t convey the idea that it’s the same thing in all stages, but… cupcakes.
These examples share a few ideas:
- Address the most important need starting from the first version.
- Increase complexity and cost to address more sophisticated needs.
- Each step along the way is a useful thing.
Iterative and Incremental Development
Some metaphors address the idea of iterative and incremental development: iterative because we may repeatedly work in a particular area (improving a capability), and incremental because we may add new capabilities. These two approaches (which can be combined) describe ways to deliver in an evolutionary way.
Iterative and Incremental Painting
Jeff Patton created these variations on the Mona Lisa demonstrate the iterative and incremental strategies.
Iterative and Incremental Flowers
Cecilia Fernandes created this diagram to demonstrate how a purely modular (component-based) strategy delays your ability to get value. The “MVP” is the “Minimum Viable Product”.
Evolution and Architecture
A final set of metaphors hint at the implications of evolutionary design for software architecture. They draw a contrast between delivering parts vs. a functional whole (which may still be incomplete as far as our long-term vision).
This is the most abstract view - if the system is described in layers, we don’t want to deliver horizontally (a layer at a time), but rather as a skinny vertical slice that goes through the layers.
Slice of Cake
(Source: Bill Wake) This picture applies the vertical slice to the analogy of the system as a layer cake. A slice of cake delivers a little bit from each layer.
(Source unknown.) A researcher might take a sample from ice, rocks, etc. It’s a skinny sample going through all the layers. In the same way, we start with a core that goes through the layers of a software system.
Veggies vs. Stir-Fry
An individual vegetable doesn’t make a complete meal, but if you take slices of several vegetables (representing layers or subsystems), you can make a nice stir-fry.
Summary - Pictures for Evolutionary Design
What are the takeaways from all these pictures and analogies?
- Systems constantly change, both the code and the capabilities the code delivers.
- We cannot know everything in advance, so we want to work in a way that lets us change as we need to.
- We deliver minimal capabilities early on and add on to them over time.
The First Version
How do we begin evolving?
This is a major difference from traditional delivery. Rather than ask, “What do we want for version 1?” we ask “What is the least we can do and have an impact on our users or our learning?”
This is a tricky mental shift. One team I was on needed to make a small release to avoid massive government penalties. The project owner insisted that an unrelated spelling change and an unrelated minor feature be included. That created noticeable schedule risk for very little benefit. “It’s easy to add this” is not a good guide for what to put in a release.
Once the first version is in place, you can evolve based on balancing market risk, team risk, technical risk, value, and so on.
Here are some analogies for a first version in an evolutionary approach:
Architecturally Significant: from Rational Unified Process (and may have earlier roots). Often, 20% of the requirements account for 80% of the architecture, and can be implemented first. The difference from Agile approaches generally is that Agile approaches focus more on making a coherent and useful early system, in the interest of getting faster feedback.
From The Pragmatic Programmer. When machine guns try to shoot down a plane, they mix tracer bullets with the regular ammunition. Tracers are designed to flare, so they can be seen day or night, and the gunners can aim based on where the bullets are going.
Tracer code lets you make sure you have the basic components and interactions before you get too far.
Zero-Feature Release (ZFR, “Ziffer”): from Mike Hill. For your first (tiny) release, don’t include real features, just include the bare minimum of each major component, all hooked up but not doing anything. This gets you through the challenges of the first deployment. After that, every release includes more capabilities.
The steel thread is another variation of the layer idea. Imagine driving a needle with a steel thread through layers of cloth representing the system. It goes through all the layers, but it’s steel because it represents a full-quality version, minimal but working.
Minimal Spanning Application: from the Poppendiecks. This is reminiscent of a spanning tree in graph theory: it reaches all the nodes but needn’t include all links. Deliver a first version that reaches all the major components, but does as little as possible.
When you’re installing a new plumbing system, don’t just hook it up and put up the walls right away; test it first. By proving that you can get from the source to each faucet, you show that everything is connected (and can improve from there by double-checking connections, looking for leaks, and pressure-testing.)
(Image by Angelo Gonzalez, CC-BY-2.0.)
Walking Skeleton: from Alistair Cockburn. (My favorite.) This is a bit of a word play - rather than a running, fully-fleshed-out application, start with a walking skeleton (with the essential parts but minimal capabilities). You grow from there, always keeping it working.
Summary - The First Version
What are the important commonalities?
- Start with a basic, end-to-end system, with at least primitive versions of all major components.
- Functionality starts limited and grows from there.
- The most critical parts of the application get the most “burn-in”.
- The system is shippable early on, and stays that way.
This approach has another very helpful property: if the system worked before, but stopped working when you changed something, odds are high that the thing you changed is what caused it to stop working.
Pressure for early value and learning have led Agile methods to favor frequent delivery and tools to support that through evolving software.
No single picture or set of pictures can capture every nuance of this approach, but I hope these have helped your intuition about it as much as they have mine.
Thanks to Henrik Kniberg (scooter to car), Jeff Patton (Mona Lisa), Joshua Kerievsky (guitar and Industrial Logic pictures), Cecilia Fernandes (drawing flowers), and Brandon Schauer (cupcake to cake), for letting me share their images. Thanks to Joshua Kerievsky and Chris Freeman for feedback on earlier drafts.