How to scale your engineering organization to move fast and build the right things
After growing up a sports fan, but mostly watching football and basketball, I’ve become a big soccer fan as an adult.
After years of watching the game (mostly the English Premier League) and seeing teams tinker with their “formations”, I’ve been struck by how much the arrangement of the different types of players on the pitch affects a team’s ability to win. A new manager will take over a squad, identify a slight change to the responsibilities of each player, including their position on the pitch, and significantly improve (or increase) a team’s play.
During the match, the players must seamlessly interact with one another and constantly make judgments about where to be and what to do. But knowing the overall scheme and the principles behind it, allows the players to hold their shape, achieve the goals of that formation, and outperform a less organized team.
Now, think of the software engineering organization at your company. Does everyone know where to be? What to do on their own, and what to rely on others for? Does the effort to coordinate everyone result in detailed plans that slow everyone down and make the team less responsive to change?
Just like a team of soccer players on the pitch, an engineering organization needs a formation so that everyone knows how to work with each other to get things done. In this article, I’ll discuss what has worked best for me, how it’s aligned with industry best practices, and what to watch out for when implementing it.
- Small teams of highly aligned, complementary people are the best way to build software.
- The way to scale software engineering organizations is to scale these teams.
- Partitioning these teams along domain boundaries is preferable to either technology or product boundaries alone.
Let’s start at the beginning, early in the lifetime of a software engineering organization, probably at a startup. Often, it’s not even an organization per se, just a group of engineers working together to build something. All software organizations start as “one team.” What are some of the characteristics of these single teams in successful early startups?
For one, roles tend to be fluid. People might have their strong suits and areas of deep expertise, but everyone can do everything, as needed.
Because the team is small, everyone talks to each other. It’s easy for the entire team to meet and stay in touch, and it’s not an issue to directly ping any one person to collaborate or unblock you.
Generally, there is very little to no process. Everyone knows what to do, and the group naturally learns how to work with each other efficiently.
And you know what, working on these teams tends to be awesome! You get a lot done, you learn extremely quickly, and you are always on the same page with everyone.
But then what happens? You are successful, you grow in size, and things start to break down. The team natural splits into different sub-teams depending on what they are working on. Team meetings start to drag since not everyone is deeply involved with every topic. You can either struggle to keep to a “single large team” or bite the bullet and split the team up into smaller teams.
What if you could split your team into smaller teams, each rediscovering the magic of the initial team? That would be amazing. Let’s talk a bit more about the characteristics of these teams.
First and foremost, these teams are self-managing. Given high-level objectives, they can figure out on their own how best to execute them. Many decisions can be pushed down into the team, requiring fewer decisions to be made by higher levels of authority. In this way, they have a high level of autonomy. And remembering the great work of Dan Pink (author of Drive), we know how important autonomy is to get the best out of our people.
To have a practical degree of autonomy, these teams are also self-sufficient. They can complete most of their work (let’s say, 80%) inside the team. They have minimal dependencies on other teams. They prefer to own their work for the entire life cycle (ie owning a service all the way to production and customers) as opposed to “handing off” to another team and moving on to their next task.
Finally, now that there are multiple of these teams, it is critical that they are aligned. The high-level goals of each team must all mesh together. In doing their work, a team must not step on the toes of other teams.
Now that we know what we’re shooting for, let’s explore the different ways in which these teams can be partitioned, which will have a dramatic effect on how well the overall organization will perform.
The first approach typically taken is to partition teams along the dimensions of technology or components.
After all, different types of engineers work on different “pieces” of the product. Front-end, back-end, data systems, mobile apps. The thinking is, that those engineers should be together to ensure common practices and also make sure that we can maximize their capacity.
However, this tends to work badly for any rapid, agile product development goals. To fully develop and ship any user-visible piece of functionality, multiple teams must each do their part and then coordinate together to make sure the combination works properly, meets the needs of the user, and is shipped.
The second, alternate approach is to partition teams along the feature or product dimension. This would seem to solve the problems with the first approach; a team can focus on all things needed to deliver a particular feature or a product to the user. The team can have the right mix of skills (front end, back end, …) to do the entire job themselves, without dependencies. Add in a PM and a UX Designer and you’re in business. Autonomous and fast. What’s not to like?
To be sure, this second approach is significantly better than the first for most product development organizations. However, there are caveats. One obvious issue is those given engineers of the same ilk are not all on the same team, they need a way to stay connected, and to keep their technical practices sharp and consistent. This can be done, but it takes a certain type of muscle we’ll discuss a bit later on.
There are more insidious caveats of feature and product-aligned teams: To properly map to the highest product priorities, these teams end up getting shuffled around quite a bit, either by adding or subtracting engineers, or by throwing disparate types of features at the same team. Teams tend to step on each others’ toes quite a bit in their quest to build “their feature”, without a way to figure out who should own what concerns. Last, but not least, certain areas of the code or product can become “orphaned” without a clear owner (or “steward”, which we’ll discuss later), resulting in crufty code and inconsistent UX.
Most software organizations in the industry adopt one of these two models, with some attempts to mitigate the drawbacks, but with the underlying formation being the same. I’ve seen multiple organizations switch back and forth between these models to try and improve.
The best way I have found to balance all of these factors and achieve self-managing, self-sufficient teams is to partition your teams along domain boundaries.
What is a domain boundary, you ask? It is a natural “seam” in the business or product domain in which you are operating. For example, in an e-commerce application, one set of concerns might revolve around users and groups, while another set of concerns might revolve around products and prices, and still another around revenue. One can use Domain Driven Design techniques to identify the domain model for your organization (usually a nice visual diagram), resulting in being able to pick out the pieces that can be decoupled from others. These areas are called subdomains, or “bounded contexts”.
I won’t go deeper into the techniques of Domain Driven Design here … it’s a specialized field that can be taken to an extreme level of detail to help design software systems. However, I have found that even a relatively high level domain model does wonders for the organization, providing common concepts and terms for all to use, hiding complexity from those who do not need it, making it clear which critical relationships go across the domain, and yes, providing a “map” to partition your teams and your systems.
And yes, your teams and your system architecture should be intentionally similar, or they will become unintentionally similar, thanks to Conway’s Law. Teams partitioned along domain boundaries will, over time, build modules and services to match their area of domain responsibility, resulting in an architecture that is loosely coupled and highly resilient.
So let’s assume you have a rough mapping of your domain and you’re thinking of partitioning your teams this way. Each of these areas probably needs to be improved as part of the product roadmap. How will this arrangement be that different from product-aligned teams?
One of the main differences is that a domain-aligned team owns its subdomain, whether it’s legacy code in a monolith, or shiny new code in a new service, or an integration with a 3rd party service. They will own migrating users and customers from one instantiation of the subdomain to another, all within their team if possible.
They own their entire subdomain, even if some parts of it aren’t used that much anymore or are in maintenance mode. Old code still exists, it needs to be worked through and around when implementing other features. Someone needs to decide when it is safe to remove it (which is always a great thing to do when you can). Domain-aligned organizations do not leave behind old code and features; everything has a home.
The notion of self-managed teams in software development is not new. It can be traced back to the early days of Agile and eXtreme Programming (late 1990s and early 2000s), and became popular in the 2010s with the popularity of the “Spotify Model” (published in 2012).
However, many organizations still struggle with how to achieve the goals of self-managing teams. Even the Spotify Model, which appears to be fairly prescriptive, has been widely misapplied by those who don’t understand the cultural underpinnings that made it successful at Spotify back in 2012.
Meanwhile, the concept of domain-aligned teams is not as widespread as you might think. Many organizations will eventually find their way to this pattern, not realizing they can get there directly.
I’d be remiss not to mention a fantastic book on this topic, called Team Topologies. It’s a rare thing to be passionate about a certain practice, wonder why it is not more broadly discussed or written about, and then suddenly come upon an extremely articulate book that has really helped clarify my own thinking on the topic.
The teams we have discussed so far in this article are those that Team Topologies would call “Stream-Aligned Teams”, which the authors define as “aligned to a flow of work from (usually) a segment of the business domain”. These teams are the ones that focus on directly creating business value, and should be the majority of your teams. It turns out that you will need other types of teams to support these teams, especially as you scale.
More broadly, there are a lot of “devils in the details” to make this approach work well. How do you get started? How do you keep these different teams in sync over time? What changes as you scale up? All that and much more in Part II.