In product development, we often think of "value" in large, discrete units: the value of project A vs project B; the value of a feature; the value of a refactor or architecture change. When we're deploying continuously, we have an opportunity to replace this mental model with a more continuous one. Decomposing changes means that each step—each deploy—can be a value add.
When we break down a big change into a series of small, lower-risk steps to deploy over time, we can think about how we can realize value from each step, and how that value accumulates. Broadly speaking, there are three possibilities:
- Value accumulates linearly over time—every step makes things a little better.
- Value accumulates sublinearly over time—the first steps don't add much value, but eventually we reach a tipping point.
- Value accumulates superlinearly over time—the majority of the value comes in the first handful of steps, with a long tail of additional value as we continue.
In reality, we rarely get to complete any big change like this—in my career, I can think of one major technical project that we finished, more or less. That means that the more we can pull value forward, toward a linear or superlinear shape, the more likely we are to see a project as a success.
I'll focus on technical projects here—refactors, new architectures, general sustaining engineering work—but these models can apply to customer-facing work, as well.
Linear Value: Every Step Helps
When a project has linear value over time, every step along the way makes things a little better. These are the lead-bullet problems: there's no way to fix everything in one fell swoop, we just need to make changes one at a time until things are better. But, if we get 90% through the work, we get 90% of the potential value.
Performance improvements typically fall in this category. If a piece of software or a website is slow, most of the time we're going to need to identify and work through each issue separately, but every change usually helps a little bit. An familiar example to many web development teams is hitting Core Web Vitals targets. There are likely to be lots of little issues that contribute—an oversized image here, a blocking resource there—and relatively few big ones.
Another example comes from an effort at my last job to standardize internal APIs on resource-oriented gRPC from various HTTP+JSON implementations. Every RPC we implemented was able to benefit from shared gRPC tooling for things like standardized logging and observability; stronger type guarantees from protocol buffers (protobuf); auto-generated client code; and the consistent—and so easier to understand quickly—API design. The more APIs we added or converted, the more these benefits accrued. We assumed we would never fully replace the bespoke HTTP+JSON APIs, and that was OK.
Adopting new patterns or tools—like switching to React Hooks or a faster test runner—usually falls into this category. There can be an initial small value dip as the team adjusts to the new pattern, but that typically goes away quickly. It's fine for these to be eventually consistent, to start with only new code, and every change benefits from the new version.
Sublinear Value: Reaching a Tipping Point
When a project has sublinear value, it means that the first steps don't provide much direct value. Instead, they set up a future state where we'll start to realize significant value. These types of changes require an investment. If they're worth doing at all, they'll often be described as "strategic investments," since we know the payoff is there
My last engineering team had a goal of decoupling our various applications to simplify local development and coupling in the system. One major piece of this was introducing event-driven architecture as an option. Since many of our business needs fit well into the "execute in response to activity" paradigm, we knew that publishing generic events (in addition to deferred tasks with tools like Sidekiq or Celery) could be a force-multiplier. But when we started, we didn't have any events to listen to!
Having Kafka or RabbitMQ running isn't valuable by itself. The initial steps of this project—selecting and standing up an event broker, publishing small change events, finding common patterns for producers and consumers in various languages—provided only small amounts of value: building tools, revisiting conceptual definitions of our core entities, helping engineers start to learn the paradigm. But we knew, from the experience some of us had working in event-driven systems, how huge the payoff would be.
Eventually, we started to see the value accelerate: teams were able to deliver new value quickly, independently, in isolated, loosely-coupled applications by tapping into the existing event streams. Once we had concrete examples of teams using existing event streams to create novel outcomes, a deeper understanding blossomed among not only the engineers but also cross-functional partners. Soon after, some teams were able to reach delivery cadences that had never been seen in the company. It was good.
But it took a long time! This required selling a vision, making withdrawals from the trust bank, investing in new software tools and education, and more than a few early steps that dragged on longer than we wanted. Projects like this are harder sells, because we have to get far enough for the reward to match the effort. A team or organization can probably only handle one or two of these at a time. Most of the time, no matter how much someone believes in the outcome, these projects are, frankly, not worth it.
Superlinear Value: The Rough Cut is Good Enough
Every once in a while, a project appears that can provide value better than linearly: a silver bullet or a long-tail situation.
Many years ago when I was working on Firefox Help, multiple teams started a move from PHP to Python for various reasons, one of which was the ability to more easily share code as libraries. (This was before Composer came out.) One of our shared needs was the ability to accept a subset of HTML from users (support article editors, add-on authors, etc) safely—i.e. without breaking layout with an unclosed
<div> or introducing XSS vulnerabilities. The task of finding a good way to do this fell to me, and I wrote the very first version of Bleach. Bleach encapsulated the functionality to sanitize HTML input while allowing a set of safe tags and attributes and fixing any nesting or balancing issues—even in v0.1.
Over time, Bleach gained a number of other features (and maintainers!) each of which added more value to the library by making it deeper. Those features were great, and benefited all of the consumers both inside and outside the original Mozilla team. But we didn't need all of them to complete the original "shift to Python" goal. The later features were a long tail, and because we got enough value very quickly, we were able to disconnect most of them from our immediate day-to-day work.
Building a library is a common example of this kind of value: v1 (or even v0.1) is like the rough cut of a film—there may be lots more effort left to put in, but you've got a huge proportion of the value right away. An encapsulated, well-tested library that you can use without knowing or remembering all the details frees up engineers to move on to new problems.
Another example is refactoring code within an application to encapsulate some process. Within TodaysMeet, after the customer-facing subscription management shipped, I wrote code to orchestrate multi-step tasks for canceling subscriptions and prorating refunds. Eventually that code made it easy to add admin UI, and I was able to simplify the customer UI to use it, as well. But right away it meant that I could provide customer service much faster, more safely, more reliably, and more consistently. I've also seen teams take manual processes, encapsulate them in code, and eventually build UI around that code to expose the functionality to non-technical users. Not only did the engineers realize an immense benefit right away from having the encapsulated, repeatable code, but it also made adding the UI significantly easier and faster.
Pull Value Forward
There are a couple of takeaways for engineers:
- You'll usually need to change focus before completing technical projects and refactors.
- Think about how to structure—or take on—projects so that they deliver value linearly or superlinearly.
- If a project is a sublinear investment, ask how realistic it is:
- Are other investment projects happening right now?
- Is the eventual pay-off high enough?
- Can we reorganize the work so that early steps provide more value right away?
- For sublinear projects, plan to spend more time selling, more time finding wins to highlight and celebrate, and more time to educate technical and non-technical team members.