How to Achieve Flow in Software Development

Intuition and common business practices often hamper our productivity. Here is what you can do about it.

An AI-generated painting in antique Japanese style of a stream flowing through a forest.
A stream flowing through a forest. Image generated with AI by DALL-E.

Many software development pipelines are multi-stage, “phased-gate” processes, in which sprint backlog items are required to go through several stages from “to do” to “done”.

In a recent project that I witnessed, the development pipeline looked like this:

  1. To do
  2. Coding (Developer)
  3. Awaiting code review
  4. Peer review (Developer)
  5. Awaiting corrections
  6. Corrections (Developer)
  7. Awaiting merge to main line
  8. Merging to main line (Senior Developer)
  9. Awaiting deployment
  10. Deploying to production (DevOps)
  11. Done

We can identify value-adding stages (2, 4, 6, 8, 10), in which tasks are actively worked on, whereas others are just waiting stages (1, 3, 5, 7, 9), in which tasks are waiting for a developer to become available.

These stages are defined and bounded by handovers: when one phase is completed, someone else needs to take over. In this case, when a developer was done programming, another developer peer-reviewed their code, who then suggested corrections for the first developer to carry out. Approved code was merged to the main line, and at the end of a sprint, the main line was tested separately, demo-ed to the customer, and deployed to production.

Because handovers create queues, and queues create delays, understanding handovers is critical to improving productivity.

Most people vastly underestimate the waiting times associated with handovers. I encourage you to actually measure the ratio between waiting times and value-added times in your own sprints. The outcome might surprise you. My client was certainly surprised when I measured a 9 : 1 ratio in their sprints! “That can’t be right,” was the first reaction of one of their senior developers. But it was.

Knowing your waiting to value-added time ratio is an essential first step towards improving your productivity. Once you find that waiting times are dominant in your process, you know that it is the waiting stages, not the value-added stages, that you need to worry about. Your productivity during the work stages is probably just fine. You need to work smarter, not harder. In fact, if you manage to reduce delays, you will work less hard, yet move faster.

Unfortunately, most software businesses do not understand this fact, and pay a heavy penalty in team morale and productivity.

Why do we all get this so wrong?

For starters, our intuition tells us, incorrectly, that maximum productivity is reached when everybody is working on value-added tasks at all times.

Peer pressure, hourly billing and timekeeping make things worse. Idling is considered uncollegial, and from the management’s perspective, an hour not worked is an hour not billed.

As a result, we all keep running on the hamsterwheel, and fail to see why we can’t get anything done.

An epiphany

Once I realised how our intuition and hourly billing were leading us astray, I had an epiphany.

In any multi-stage process having more tasks than developers, productivity is always somewhere between the following two extremes:

  1. Tasks waiting for developers (capacity maximisation), or
  2. Developers waiting for tasks (maximum flow).

In other words, you can have tasks moving fast or developers moving fast, but not both. You need to find the sweet spot between the two.

The callcenter example

An example might make this easier to understand.

In a callcenter working at full capacity, incoming calls need to be put on hold until an agent becomes available. The callcenter agents are busy, calls are queued up, and customers need to wait.

In a callcenter with a number of agents equal or greater than the maximum number of simultaneous callers, all calls can be taken without delay. The callcenter agents will be idling most of the time, but customers are helped instantaneously.

In other words, you need a certain amount of spare capacity that strikes a balance between acceptable waiting times for customers and the economic cost of employing callcenter agents.

Importantly, the relationship between capacity and flow is not a linear one:

  1. Delays increase exponentially with capacity utilisation. A team working near full capacity will get almost nothing done.
  2. Reversely, adding even a little extra capacity (developer availability) will dramatically improve flow.

So how can we achieve optimum flow?

Of the many measures that we can take to reduce delays, three are particularly effective:

  1. Limiting work in progress,
  2. Reducing scope,
  3. Reducing handovers.

How to limit work in progress

“Work in progress” (“WIP”) is a task in any stage between “to do” and “done”.

Work in progress is important because a task that is on someone’s plate makes them unavailable, and prevents others from handing over tasks to them. As we said before, you need availability to prevent queues from appearing around handovers.

To keep developers from creating too much work in progress, you can impose so-called “WIP limits”, which means putting a cap on the number of tasks that are being worked on. Project management tools can help you with this, by showing a flag once a WIP limit is exceeded.

In my view, there should be only one WIP limit across all tasks between “to do” and “done”.

Importantly, once a developer is confronted by a WIP limit, they should ignore their urge to pick up a new task, and instead go idle.

Optimum WIP limits allow you to all but eliminate the waiting stages from our process, so that we get something like this:

  1. To do
  2. Coding
  3. Code review
  4. Corrections
  5. Merging to main line
  6. Deploying to production
  7. Done

Things are starting to look better!

What is the optimum WIP limit?

The optimum WIP limit depends on many factors, including the number, size and complexity of the tasks, as well as the number of people and roles on the team. This could make a mathematical approach impractical.

Fortunately, you can use intuition instead. In my experience, developers are well able to express whether a sprint “flows” or doesn’t flow. In addition, WIP limits are not that critical. As long as you are close, you still get a substantial benefit compared to working at maximum capacity.

How to reduce scope

Reducing scope (the number of tasks in a sprint) is the simplest and the most powerful measure that you can take.

By decreasing the number of tasks per developer, you automatically create more availability during handovers, and drastically reduce waiting times.

If you do one thing, reduce scope. You will see queues melt away and team morale improve.

How to reduce handovers

Handovers are important because they are obstacles in your process, causing queues and waiting times. You can never have too few of them.

Here is what you can do to reduce the number of handovers.

Taking code review out of the process

There are several ways to do this:

Having eliminated waiting stages and code review, our process starts to look even better:

  1. To do
  2. Coding
  3. Merging to main line
  4. Deploying to production
  5. Done

Take front-end coding out of the equation

Front end frameworks such as ReactJS or VueJS add a lot of unnecessary weight and complexity to your codebase. In addition, they often require working with specialist front-end developers, who need to collaborate with designers and back-end developers. This causes more handovers throughout the value-added stages. And we do not like handovers!

Therefore, unless you are developing a product with a lot of functionality in the front end, you do not want people working in dedicated front-end roles on your team.

If you have the liberty to choose a framework, consider using one that renders HTML on the server, like HTMX, Laravel, Phoenix, or Ruby on Rails.

Do not use feature branches

Feature branches are as common as they are wasteful.

A feature branch is a separate branch of the codebase that developers merge their code into. Once the feature is ready, the branch is often even tested separately, then merged as a whole to the main line.

Feature branches create more handovers and more delays, and should never be used. Instead, developers should be merging their code directly to the main line of the codebase.

If you really do need control over releasing a particular feature to a particular group of users or at a particular time, use feature toggles instead.

Let’s see what happens to our process if we get rid of feature branches:

  1. To do
  2. Coding
  3. Deploying to production
  4. Done

Looking even better!

Take deployment out of the equation

Most teams that I have worked with have separate stages for deploying code to a staging or production system.

This is a real concern, because it often causes major delays between the time that code is ready to ship, and actually shipped.

Developers should instead be able to deploy code to a server directly, without any outside help.

Once we can do this, we have reached the Holy Grail of software development process: only three stages!

  1. To do
  2. Doing
  3. Done

Conclusion

Working at maximum capacity is a sure-fire way to hurt team morale and productivity. With some simple (but counter-intuitive) measures, we can achieve drastic improvements.

Reducing scope is the most effective way to improve productivity. If you do only one thing, reduce scope.

Stay informed of new posts?

Sign up below and you will receive a weekly digest of new posts.

If you change your mind, you can unsubscribe at any time. You will not be spammed, and we will keep your email address private.

Article index