Level Up Coding
Published in

Level Up Coding

Why Don’t They Build Cars in Sprints?

If continuous flow assembly is the preferred way to make cars, then why not software?

Rolling out the latest features for review, with stakeholders waiting for their first look
Rolling out the latest features for review, with stakeholders waiting for their first look | Source

Have you ever seen a car assembly plant that produces cars in discrete Sprints that begin and end? As in, at the start of a two week period, the team commences to build a new batch of cars, and completes only those cars by the end of the Sprint? No new cars are commenced late in the Sprint, as all personnel are purely focused on completing the cars that they commenced at the Sprint’s outset? All the equipment used for the earlier stages of assembly lays idle whilst a batch of cars is finished and delivered at the end of the Sprint. Me neither; it would make no sense to work this way. And it wouldn’t make sense to clear the assembly line of all cars by the end of each Sprint — that would slow down throughput of the plant dramatically.

Instead, modern assembly plants use a pipeline or continuous flow system. Work flows through all stages of the process continuously. There is no Sprint “start” and no Sprint “end” for work commencement or completion; both happen all the time. If you want to deliver work in batches that’s fine — the cars are exported or sent to a dealer that way. But the work of turning raw metal into working cars happens all the time, without start and end cycles.

My view of the Sprint approach is that it represents a naive view of work. It mistakes the finished product for the process that produced it. On the surface, it seems logical to think of a package of functionality that is neatly tied together with a bow by the end of a Sprint, and then we start again for the next Sprint. But actually that package represents the finished product — it represents a single car rolling off the assembly line, not the assembly line itself. While each car rolls off the assembly line, other cars are still under construction.

But in Sprint-based software development, we confuse the finished product with the process that made it. The process to produce a new feature from start to finish (including discovery, design, build, and deploy) will likely take longer than a Sprint. So in an Agile team, why can’t designers commence work on a new feature at the same time that engineers or testers are finishing an older one? Usually they do, by breaking off the discovery and design stages into a separate process. More on that later.

Within just the build stage, it can take longer than a single Sprint to create a feature. The common approach is just to split it into smaller parts, build what we can now, and save the rest for later. Even if that feature is not useful or usable until the rest is finished. Even if the missing parts are not scheduled for some time yet as all the subsequent Sprints are already fully committed to other stuff. It’s the equivalent of rolling a car off the assembly line with two wheels missing and excusing it by saying “sorry those last two wheels wouldn’t fit in the last Sprint, but we’ll put it in the backlog (with all the other missing parts already to committed to) and get to it in a future Sprint.”

Smooth vs Swinging Production

A principle of Lean production is that it should be smooth and even. There should not be large swings or emergencies. It’s also a principle of the Agile Manifesto:

Agile processes promote sustainable development. The sponsors, developers, and users should be able to maintain a constant pace indefinitely.

But consider that at the beginning of a Sprint, it’s likely that few tasks are ready to implement immediately. Many tasks need some type of further clarification, often because the first time the team sees them is during Sprint planning, so this creates a delay.* Time is lost following up missing information. However, by the end of the Sprint, all that lost time catches up with the team. They still have to make good on all the tasks that they agreed to deliver at the beginning of the Sprint… before those delays occurred. It’s often a mad scramble to get every task completed by the deadline. The team’s stress levels follow the same sawtooth pattern as the activity: low at the beginning of the Sprint but frantic by the end. And then we repeat that dysfunctional pattern Sprint after Sprint. In my view it’s madness!

*It is possible to examine tasks beforehand, called refinement. But in practice I find that this rarely occurs because it competes for time with delivery of software, which is already stretched and which the team is measured against. It’s also possible to not accept a task into a Sprint until it is fully specified first, which means that it becomes someone else’s responsibility while the team focuses on the tasks for that current Sprint; a factory pattern ensues. This leads to a “definition of ready”, which is considered to be anti-pattern by many pundits.

Additionally, it’s worth noting that tasks tend not to be completed in a smooth continuous manner during a Sprint. Due to the start and end barriers of the Sprint, and the constraints that places on tasks, most tasks all get completed during its final few days. That would be a like a car factory not completing any cars for seven days, and then finishing an avalanche of them in the following three days, then repeating the cycle. This doesn’t sound like a good pattern for sustained production, because it isn’t one.

The Loss of Cross-Functional Teams

Sprints actually make cross-functional teams less likely to occur. At the end of a Sprint, would we ask designers to switch tools to perform source code reviews to help complete those features? At the start of a Sprint, would we ask engineers to twiddle their thumbs while they wait for the next few designs for the selected Sprint items to be completed?

No, of course not — that would make no sense! Just like the early stage equipment on the car assembly line laying idle, it makes the most sense for those operators to commence on the next batch of work. Product managers commence the next round of discovery, and designers commence the next round of design. But how do you juggle that mix of tasks within a team and within a Sprint? How do you plan such a Sprint? All those heterogeneous tasks mess up Sprint planning. How do you estimate the number of story points for a discovery task vs a design task vs a code task? Where is the advice and guidance on how to do this? Many design and discovery tasks don’t result in realized value for the stakeholder… yet. And they may likely have a different goal to the Sprint goal stated for the engineers. It seems likes a planning mess.

So instead what typically happens is that we move design, and product discovery, and anything that doesn’t directly produce working software, outside of the Sprint. Product managers and designers and other roles work outside of the Sprint (or perhaps in their own Sprint arrangement) which in turn means the Sprint is limited to engineering tasks being done by engineering people only.

Consequently, the cross-functional team is broken up into separate teams — or more likely separate departments. The product managers work in their own team, the designers work in their own team, and the engineers work in their own team. Each team has a separate line of reporting. Calculating Sprint metrics for each team is easy, as the type of work within the team is uniform: engineers just count code points, and designers just count design points. But it’s not cross-functional anymore; the benefits of end-to-end visibility that cross-functionality was supposed to deliver is lost.

I suppose you could say that such a multi-team situation that includes different teams for product discovery, design, and engineering represents a gated pipeline approach. Each Sprint is a gate between teams.* What is the point of the Sprint gates? It just impedes the work from freely flowing from one stage to the next.

*One common example is “dual track” agile. This interpretation is wrong. Discovery work is supposed to happen concurrently and continuously with development work.

Variable Sized Tasks

One way in which a car assembly plant differs from software is that in a car factory thousands of copies of the same car are produced each week. Sure, a single assembly line may be shared to make multiple models, but each instance of a particular model is largely identical to the other instances of the same model (there will some variation for options and colors, but these too keep repeating). The time and work involved to make a specific model is known; there is no mystery as to whether a component will require three bolts or five, and there is no mystery how long it will take to insert those bolts into each car.

In contrast, in software, each task is different to the others. Sure, there may be some similarities, but each task is unique in some way, which might be just a little bit, or it might be a lot. So we cannot know the cycle time with absolute certainty; there will always tend to be some error. And most of the time, the team tends to underestimate the time required.

So if a car plant, which produces multiple copies of an identical product, whose manufacture time is well-known, does not use Sprints, then would software delivery, which is subject to much more variability, benefit from the imposition of such a regular, rhythmic delivery cadence? It doesn’t make sense to me.

A Sprint is essentially a fixed capacity box of time; each Sprint is identical in size. But the work that we’re inserting is not identical — each task is different. And the size of each task is not completely known: the estimate is subject to error, most often underestimation as stated above. So we’ve got a situation in which variable sized tasks, each of whose real size is very likely larger than its estimate, is being packed into fixed sized delivery cadences called Sprints. And then the team is required to deliver all those by the end of the Sprint. It seems more like a recipe for a Mentos soda geyser than a reliable way to deliver software to me!

Continuous Flow to the Rescue

Continuous flow is the method used by car assembly plants. There is always a new car starting, and always one finishing. There are no Sprints. When work on one stage of a car is complete, it is smoothly handed over to the next stage. This pipeline consists of teams that are actually very cross-functional: Toyota calls it a cell.

Yes, it’s fine to release a product in discrete batched increments. No, it’s not fine to run your creation process that same way. Instead, your team should be working in a continuous flow — this turns out to be smoother and causes far fewer headaches for the team. Continuous flow means there are no artificial start-stop barriers to work.

“Why don’t they build cars in Sprints?” seems like an absurd question. Decades of manufacturing experience has shown that a continuous flow assembly line based on just-in-time principles is the optimal arrangement. So why don’t we apply the same thinking to software? Is software less complex? No. Does it require less skill or specialization? No. Is an optimized production process not a potential source of competitive advantage? No.

As you may have gathered, I don’t especially like Sprints. I feel they represent a naive view of work and I find that the additional measures needed to get a Sprint to work just adds to my problems. Instead I use a continuous flow Kanban system. That doesn’t mean I don’t have planning meetings, reviews and so on. It just means that they’re scheduled by coherent blocks of value (i.e. per feature), rather than by a ticking clock.

Further Reading