There’s more potholes than road on the way to scaling a tech organisation. Inside one of the big potholes sits your team structure. As you grow, two forces will pull you apart: parallel priorities (instead of the much loved “everything is a priority” strategy), and teams becoming too large for a single overworked Engineering Manager (EM) to manage.
When you start a new piece of tech, how good does it feel? It’s flow. You get new features daily. Everything’s shiny and new. Easy setup, easy testing. Life is good.
As you grow, this changes. Parts of the codebase are in a certain way because of reasons, teams are created with different maturities and seniority, some parts have different performance or stability requirements, people come and go. Pressures on the team also change. Teams need to think about how to keep bugs and technical debt low and keep iteration on features high. Here, the communication and expectations you share with other teams, as well as how you arrange yourself will be the difference between poor and excellent performance. It’s less about having genius tech and more about how we communicate and share progress with a larger and larger set of people.
Something we found tough has been how to think about balancing work between teams. This manifested itself with work being passed around. We would hear “we’re too busy to help”, “who should handle this?”, or “can we shuffle
This part is hard, and I made a lot of mistakes here that led to frustration, unclear standards, and wasted time.
Solving the issues is collaboration, architecture, documentation, and communication.
Coming in like a motivational poster above a corporate’s coffee machine are the major pieces to get in place. They’re easy to get started, but often hard to maintain as they’re not the natural state for many in engineering teams.
As you work through each of these, check that each EM is happy and comfortable rolling these out to their teams. This can be frustrating and can feel like progress is being suffocated (especially pronounced when another team helped create the standard). Some EM’s might even disagree with the changes, however: if they’re not fully engaged and pushing it, teams begin to fall off the path.
Explicitly setting expectations is important. You can’t expect teams to intuit exactly how you’d like them to engage with each other.
Many teams look to solve collaboration by setting clear owners for different parts of the product. This is a good step, but comes with some nasty surprises. It builds up an us vs them attitude, and ultimately blocks you from shipping while you wait for teams to sync with you. Instead, set the expectation that teams are stewards for their parts of the product. Teams should spend most of their time operating inside their area, and if they need to make modifications to another team’s area - that’s totally OK as long as they follow the standards and structure set by the stewards of that area.
To help ensure standards are met, I am also a huge fan of having teams “rent” team members from other teams. If you want someone to help build tech in a complicated part of the system, have the PMs/EMs get together and figure out if it can be done. If so, have the person step in for a pre-agreed upon project and time limit. This keeps expectations clear.
If you’re someone who’s hired from another team - remember this when the other team is struggling and indirectly (or directly) asks for help ;)
Conway had a great quote worth chewing on:
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization’s communication structure.
Most people look at this and agree. If you look at your system architecture and your team structure, you’ll find that they mirror each other. An alternate quote that illustrates the point:
If you have four groups working on a compiler, you’ll get a 4-pass compiler.
With the information you have on hand: what’s the ideal architecture for your tech? Start here, and build teams around the natural groupings that form.
Many teams start from the wrong end. They split teams based on projects or current priorities and wonder why they end up painted into the corner with microservices being the only way out.
I won’t make any assumptions about your style of architecture (monolith, services, micro-services) - this principle works for all of them. Design your architecture and team boundaries together.
What about one team that is extra busy? Or must operate in the same space?
Make this team larger. Or find part of their workload that you can split off into a smaller team that reports to this team. Not all teams need to be homogenous. Some teams need to be tightly coupled, others can afford to seldom run into one-another. The most important part is that you acknowledge the dependencies by adding higher bandwidth communication between dependent components.
What about models or interfaces that get larger and larger?
Don’t be afraid of duplication. Many engineers are wired to DRY-or-die. The reality is that as your application grows, there’ll be different contexts, different use cases, different pieces of business logic bending your perfect models in different directions. It’s OK to have multiple definitions of the same model. Your goal should be loose coupling. You can solve for consistency with clear and well-tested transformation steps at the borders of the different modules.
When looking to debug team-level issues, documentation is going to always be a point to bring up. If you’re not documenting how you do things, or what you expect of each other - now is a great time to start.
It’s important to make clear (in writing) what you expect of each other, how you should engage for certain issues, and who exactly is stewarding what. This helps you as a tech leader, leaders of your teams, and all of the engineers within your organisation.
A signal here you should watch out for: are people asking who should pick a certain piece of work up? Are they asking who should fix a bug? Are they complaining they need to wait for another team?
Have clear documentation for:
The process for “borrowing” a team member from another team.
What our tech standards are, and what the standards are in different parts of the codebase.
What it means to be a steward, what responsibilities you have.
Which areas of the product are being stewarded by each team.
How to know who should fix an issue and when.
Talking, easy right? This felt so natural when we were small. Surprise: it didn’t work as expected. It’s your role as a leader to ensure that the right communication paths are set up and maintained. You want to keep these paths as few as possible to avoid too many meetings and overload, so getting the right level of bandwidth is important.
Teams that work closely in similar spaces or are dependent on each other need higher bandwidth communications than teams that work in completely different parts of the product organisation. It’s OK that not all teams are involved everywhere.
Teams need to get into the habit of sharing. Sharing changes they’re making, sharing the work they complete. This is a great way to keep teams in sync, but also give different parts of the organisation the opportunity to show off.
Teams need to get into the habit of explaining themselves more and being challenged. This can be tough as you split from one team into multiple. You should expect push back on larger changes. The individuals in teams need to be great at articulating the why and ensuring that it’s as easy as possible for others to adopt their changes.
Teams also need to communicate clearly when blocking events occur, i.e. when a bug hits production and something needs to be rolled back, or DB migrations need to be run (or not run), or when a change can absolutely not go out to production.
Parts of this list felt weird. We didn’t have issues when we could all sit in the same room together, so these muscles never built up. It’s taken several failures to build up the reflex to keep the right people in the loop.
Wanna go fast? It’s not going to happen without a push.
Balancing high quality tech, fast delivery times, and reliable estimates is at the centre of our work. Being conscious about how you design your architecture, teams, and communication channels is one of the few things worth focusing on.
Keep the problems in the back of your mind, listen to feedback in 1:1s. The way you work now might not be as great as you think. It might also be that the structure you have now, will not work 6 months from now. Take time every quarter to re-assess where the team and tech is at.
This stuff is easy to talk about but hard to get right and even harder to maintain over a long period of time. Keep at it. Like many parts of running a tech business, the wheels won’t come off if you don’t get this right in one quarter. Take steady steps. Assess how you’re looking every quarter and make adjustments in the right direction.