Happy [development teams] are all alike; every unhappy [development team] is unhappy in its own way. – Tolstoy, if he delivered software1
After a decade as an engineer at companies ranging in size from 6 people to over 1000, I’ve been on many teams. The good teams were very similar, the bad ones were each bad in their own way. This post describes what made the good teams good.
Trust
Trust is the bedrock of any good team. You have to trust that your teammates know what they’re doing, that they hold themselves to the same standard you do, that they care. They don’t have to care care, they don’t have to live and breathe your company’s mission, but they do have to care about delivering quality work.
When there’s a production incident, you need to be able to trust that your teammate who is “on it” is actually on it. They may not be able to personally fix the problem, but they have to be able to handle the situation and get the right people involved quickly.
When there’s a bug, you need to be able to trust that whoever says they fixed it really did fix it. We’ve all encountered people/teams where you hear, “Oh that’s good to go, X fixed it,” and then no more questions are asked. The best team I’ve been on was comprised entirely of people like X.
Along with trusting your teammates’ work, you have to be able to trust them as people. I’ve spent most of my career working in some form of Agile, which means I’ve (mostly) had retrospective meetings after sprints or big projects. The best teams have really aired out their feelings in those meetings, because they trust that the rest of the team will listen to them and, if possible, help resolve the issue that’s bothering them. I’ve devoted entire sprints to work created by these discussions, valuable work, which might not have happened if my teammates didn’t feel comfortable speaking up.
Trust is hard. It has to be earned, and it’s easily lost2. But on every good team I’ve been a part of, it was crucial.
Respect
Respect and trust are tightly related, it’s hard to have one without the other.
Even on an effective team, it’s not always smooth sailing. Every person has their opinions, and we all think we’re right, especially engineers3. That means arguments are bound to happen. What I’ve noticed about good teams is that even if an argument gets heated, it’s always respectful. People may disagree intensely, but they don’t make it personal—they keep it focused on the work. In fact, these disagreements often shine a light on a more widespread misunderstanding, like: “Why exactly are we building this feature? Would our time be better spent elsewhere?” Your team needs to be able to have those conversations, and without respect they can quickly become unproductive.
Communication and Collaboration
In all relationships, communication is key. In the era of remote work, it’s even more important, and harder to do well. Being available to help talk through problems, or to screen share and pair program with someone is huge. The world of software engineering is vast, no one knows everything, but across the engineers on a team there’s a lot of knowledge. You have to be willing to ask, and your team has to be willing to help.
Asking for help is is something that newer engineers can struggle with. Knowing when you’re truly stuck is harder than it seems, but it’s a valuable engineering skill. If the junior people see others asking for (and receiving) help often, they’ll be more inclined to ask themselves. And they should! You can learn a lot more from a quick conversation with a knowledgable teammate than if you spent that same time struggling on your own—it’s how I learned many of the tips I wrote about in Developer workflow tips no one tells you about.
Humility
Above I mentioned being able to ask for help. Implicit in that is having to admit that you don’t know something, and haven’t figured it out, which requires some professional vulnerability. That’s why it’s important that everyone exhibits humility in their interactions.
A question might seem basic, and you might think “that’s kinda dumb, they should know this already”, but if you approach your interaction that way, the help-seeker will never ask you for help again, and the whole team will suffer as a result.
You might know better, but even if you do people aren’t going to want to work with you if they feel like they’re being talked down to.
Ownership and Accountability
Unless your company is quite small, it likely consists of multiple teams. It’s important that each team has concrete and distinct ownership over their respective domains. It needs to be clear who owns what; shared responsibility will always become someone else’s responsibility4.
Hand in hand with ownership is accountability. The people or team who own a domain should also be accountable for it. If my team owns the payments service, it should be our responsibility if something goes wrong. If there’s a payment-related incident, I would expect whoever is on call to reach out to us immediately.
Related: Blame and Post-Mortems
Implicit in accountability is the possibility of blame: “payments had an issue, it’s Justin’s team’s fault.” Now, that may be true, maybe we shipped some bad code. But it also might not be true, maybe a dependency is down. Either way, blaming us isn’t going to fix anything, it will just make us less inclined to ship anything at all in the future. You should always assume good intentions; no one is breaking things on purpose.
Rather than blaming, an effective team might ask questions like:
- What exactly happened?
- Were we notified quickly?
- How did this make it past our testing?
- How was it resolved?
- How can we prevent this from happening again in the future?
The most effective team I’ve been a part of formalized this process into a mandatory blameless post-mortem meeting, held after any production incident. That meeting also had a single owner, and all resulting follow-up work was assigned to individuals before the meeting ended.
Things are going to fail, it’s inevitable. Even if your code is perfect (which it never is), your dependencies will go down. An effective team sees each failure as a chance to improve, not an opportunity to blame someone else.
Recruiting
Without the right people to start, nothing else in this post is possible. You need people with the right technical skills and attitudes, and one bad hire is enough to ruin a team. There’s a reason why Steve Jobs considered recruiting his most important job.
Recruiting is really hard to do well; it’s worth investing a lot of time into your recruiting and interview process. The best recruiting process I’ve seen was extremely well-defined: there were thorough rubrics demarcating performance expectations for each level for each module, interviewers were trained on the modules in advance, scoring was done independently, and then all people involved in the process had a wrap up discussion. This process might seem like table stakes, depending on where you’ve worked before, but trust me, it is not.
Meetings
Engineers are particularly sensitive to meetings. “Maker Time” has been discussed since at least 2009, and it is a very real thing. Writing quality software is deep work which requires long periods of uninterrupted focus. If it takes 30 – 60 minutes to get the full scope of a problem contextualized, but you have a meeting every 90 minutes, you won’t get anything done. If that happens often enough, you won’t even bother trying to get things done, because you know an interruption is coming.
The best teams I’ve been on acknowledged this explicitly, going as far as blocking out entire days of the week where individual contributors would not be added to any meetings. Granted, blocking the entire day might not be realistic everywhere, but at the very least teams should strive to only include people who are truly needed in meetings. Some flavor of the two-pizza rule can probably apply to most businesses.
A brief word on managers
I have never been a manager myself, so I’ll keep this section brief.
A good manager is a bit like your little finger. If everything is going well, you might hardly notice them. But as soon as something is wrong, it’s all you can think about.
People like to blame their managers for problems, but in my experience a bad manager is a symptom of larger problems at least as often as they are the cause, like a lack of trust, or a lack of organizational alignment5. The best manager I’ve ever had mostly left my team alone to do our thing, while protecting us from interruptions behind the scenes. He was always available if we needed him, but we had proven that we could reliably ship quality work, so unless we needed his input he just let us run, which we all really appreciated. The easier you can make your manager’s life, the happier everyone will be.
Conclusion
This isn’t an exhaustive list of criteria by any means, but it’s enough to see why it’s so hard to build effective development teams. If any of the attributes above is lacking, the team will suffer. It’s why people with titles like “Head of Engineering” or “CTO” get paid the big bucks. It’s their job to try and create an organization that does everything above well, and more. If they can do it, they’re worth every penny.
Notes
- The Anna Karenina principle has apparently been studied as it relates to success in science. TIL ↩︎
- There’s an old saying, “Trust arrives on foot but leaves on horseback” which I think captures this sentiment perfectly. ↩︎
- Tabs vs spaces, anyone? Vim vs Emacs? Maybe TS vs JS? ↩︎
- Diffusion of responsibility is a well-studied phenomenon ↩︎
- Organizational alignment could be its own section entirely ↩︎
[…] I am a big believer in Trust and Safety as cornerstones of good teams, so I loved this article on What makes an effective development team. […]