Talents en applications - Blogue | Nexapp

Shift-Left in Development: Reduce Lead Times and Improve Code

Written by Alexandre Rivest | Jan 27, 2025 9:30:06 PM

Your team is working on a project, and your manager comes in with a strict delivery schedule. As a team, you like a challenge, so you embrace your manager’s plans. Development is frantic, but you’re making progress. The closer you get to the delivery date, the more you realize you won’t make it. And your manager realizes it, too! So, he asks you to find ways to deliver what you’re developing faster. But at what cost?

The desire to deliver as quickly as possible has a massive impact on the product you develop. Whether it’s the stress accumulated by team members or the sacrifices made on quality work, commonly called technical debt, the benefits of rapid delivery rarely outweigh the damage this practice can cause.

So, how can we rethink our approach to reconciling the need for speed with the requirement for quality without compromising the end product? What strategies can be implemented to balance these objectives and ensure the sustainability of the product and the team? 

Change Your Vocabulary

In my example, I mention the need to “deliver fast.” However, this is the wrong expression. The word “fast” can often be associated with a sense of urgency. A feeling that makes us say: “I’ve got to hurry, or I won’t make it.” This mentality means that quality in a person’s work becomes secondary. This is due to the fear of consequences. “What’ll happen to me if I don’t deliver on time? Will I get yelled at? Will it jeopardize my job?”

What do we tend to see when this happens? You start to see sloppy work! It’s easy for people to cut corners to reach their goals. Although this gives them immediate velocity gains, it’s an illusion. Doing our work badly in IT introduces the concept of technical debt.

“Technical debt (also known as tech debt or code debt) describes what results when development teams take actions to expedite the delivery of a piece of functionality or a project that needs to be refactored later. In other words, it’s the result of prioritizing speedy delivery over perfect code.”

Source

So, do we want to “deliver fast”? Generally speaking, this attitude should be avoided by any development team, as it’s detrimental to the overall development of the application in the short, medium and long term. With these few words, it’s possible to create negative feelings and undesirable reactions. So what would be more appropriate to say when we want to be efficient in our work?

The expression I use is to deliver sooner. Compared to the term “fast,” the concept of “sooner” has a much less negative connotation in the delivery context. The questions shift from “What can I cut to deliver quickly?” to “How can I optimize my process to deliver sooner?” This is the kind of question you need to ask when you want to speed up development without sacrificing quality.

Of course, it’s possible to deliver sooner by turning corners! However, this approach opens the door to other solutions more efficiently than talking about speed. So, how can we, in product development, deliver new features sooner?

Identify Sources of Delay

One of the primary sources of delays in software development is downtime! Some people will say that they’re constantly programming new features, so there’s no downtime in their work. But that’s where they’re wrong! When we talk about downtime, we’re not talking about developers twiddling their thumbs but rather about tasks that remain inactive for long periods without anyone working on them. 

Let’s take an example from a lecture by Dragan Stepanović on the dangers of asynchronous working.

Source: Async Code Reviews Are Killing Your Company’s Throughput, Dragan Stepanović, NDC Copenhagen, 2022.

In this example, Emma works on task 1 and then asks Lucas to do a code review. This is when the downtime starts. After a long time, Lucas finally takes the time to review the task and asks Emma for some changes. While she was waiting, Emma decided to start a second task. Now, three tasks are being developed in parallel: two for Emma and one for Lucas. If we ignore the time that isn’t reserved for development (dinner, time outside working hours, etc.), there will always be at least one task accumulating dead time. In the example of Emma and Lucas, we end up with task 1 spending more time waiting than developing!

Each new parallel task will increase the waiting time for other tasks. One way of achieving our goal of delivering tasks as quickly as possible would be to reduce idle time as much as possible. This would allow us to increase efficiency without sacrificing quality.

Tip: If you have several tasks still in progress at the end of each development iteration (sprint), it’s highly likely that your team members are working in silos and that there’s a lot of dead time on tasks.

Identify Idle Time

During feature development, the lead time of a task can be divided into four main categories:

  1. Programming: This is the time spent by the developer coding the functionality.

  2. Pick-up: When development is complete, this is the time you wait before a code review begins. This stage is considered dead time.

  3. Review: This is the time spent examining the code by another person and the time spent applying changes, if any. This stage ends when the code is merged with the main branch.

  4. Deployment: Once the code has been merged with the main branch, you have to wait until the code can be deployed online.

In Dragan’s example with Emma and Lucas, two categories contain a lot of dead time: pick-up time and code review.

Finding Solutions

Now that we’ve pinpointed a source of delay in completing our tasks, what can we do concretely to deliver them sooner? 

Reviewing code earlier

Performing a code review can take a lot of “brain power.” After all, there’s a lot to consider when reading code: 

  • Is the code readable?
  • Does the architecture make sense?
  • Are acceptance criteria met?
  • Are tests present?
  • Are there any unhandled cases?

Some of these points can cause problems if they aren’t respected. For example, the changes you’ve made to the system may break another feature because they pass through the same code. This type of error requires you to go back and revise the implementation. To avoid this delay, performing a code review earlier in the development process can help prevent the duplication of work. For example, it’s possible to design an architecture plan on how you intend to implement the functionality and have it validated by your peers before implementing it. 

Communication

How do you inform your colleagues that a task is ready for review? The effectiveness of a team’s means of communication has a direct impact on how long it takes to complete code reviews. Depending on how you work as a team, there are several ways of informing your colleagues that a task is ready for review. For example, a highly collaborative team may mention it to the team synchronously using voice channel tools, such as Discord or Teams. For teams that are a little more asynchronous, for example, due to multiple time zones, a robot that automatically sends a message when a new merge request is ready could be a solution. The key to minimizing downtime is to be efficient in communicating task status.

Pair review

During a code review, asynchronous discussions are responsible for the majority of dead time. When you disagree on a review item, the back-and-forth during the discussion can significantly extend the task’s lifespan. One solution to this source of delay is to do a paired review. This allows real-time discussions to occur as and when required and sometimes even leads to points being discussed that would otherwise have been left aside due to their complexity. Reviewing in pairs greatly encourages knowledge sharing between team members and makes it possible to complete a task sooner.

Small merge requests

When I ask developers what demotivates them from doing code reviews, most answers revolve around the size of the review. When a merge request is large, it’s challenging to carry out a quality review. There’s too much information to absorb and understand simultaneously, making it difficult to evaluate the code as a whole.

Teams accustomed to making large merge requests generally have a higher pick-up time, as developers know this will require much time and cognitive effort. There are so many changes that it’s challenging to keep on top of everything to review.

Smaller merge requests are much easier to understand, track and therefore evaluate, as the scope of the review is limited. Moreover, context switching can be challenging in our line of work. So it’s understandable not to want to interrupt your concentration to go and review someone else’s code. However, working in small iterations means switching contexts more frequently but more naturally.

Tip: A smaller code review means more code reviews to review. In effect, this creates more individual reviews. This approach will challenge your code review and continuous integration processes. In exchange, you’ll have code ready to deliver sooner and in smaller increments.

Slice work into smaller pieces

In the previous point, I mentioned the importance of smaller code reviews to make them more efficient. It may seem counter-intuitive to deliver a piece of code that contributes nothing to the product on its own. In this case, one solution is to chop the work into smaller increments to add value constantly to the product. This approach builds on the previous solutions, but from a business point of view, for your customers or users. 

 

Martin Nadeau, Senior Engineering Manager at Nexapp, explains how to slice your work in an article on the subject. 

Adopt pair programming

In the abovementioned conference, Dragan Stepanović explains the impact of small code reviews on a team’s continuous delivery efficiency. He points out that the speed of a code review is inversely proportional to its size. Taking this concept to its limit, what size code review would be the fastest to review? A single-line review! So, the review is done during development.

Pair programming allows code reviews to be carried out simultaneously as development. Moreover, any architectural discussions that might arise during a code review now occur during development. This avoids the situation where someone implements a solution and has to apply significant changes during the review in response to peer feedback—less feedback = less unnecessary work = greater efficiency.

What About “Shift-Left”?

The principle of “shift-left” brings certain stages of the process earlier in development. If we look at an Agile project board with several columns for the different stages, “shift-left” means shifting responsibility from specific columns to those further to the left. For example, for stages focusing more on the programming of a task, “shift-left” might involve moving the code review stage into the programming stage (in progress).

Several solutions mentioned above illustrate the application of “shift-left” in development. Bringing code reviews earlier reduces downtime and eliminates code that would never have made it through the following stages of the process. Whether preparing an architecture plan or using pair programming to have a code review in real-time, these practices let you deliver your work earlier and get feedback from users more quickly. This allows us to be proactive, optimize the development process and transform how team members work together.