At Atomic, it is rare to see a project with 4 or more full-time developers on it at a single time. In general, we tend to lean toward smaller teams. However as our projects become more complex, our teams start to grow.
As a member of two of Atomic’s largest projects-to-date, I have noticed a few things we do to keep our big teams working effectively.
1. Parallelize Work
Imagine you and 3 of your family members are tasked with making a delicious Thanksgiving meal, including turkey, mashed potatoes, and apple pie. One approach would be to have everyone work on the same dish at the same time. One person peels the potatoes, the next person chops them, yet another person places them in the boiling water, and the fourth mashes them. If you were preparing the meal alone, this is not a ridiculous approach. However, with 3 additional teammates, it is wasteful to prepare your meal this way.
This is very similar to application development. Small teams rarely work on different parts of an application in unison. Instead, they are focused on one track of development until that track is completely finished, like creating mashed potatoes. Large development teams do not, and should not, have this luxury. It would be wasteful to have 3 out of 4 teammates sitting on the bench while you work to finish peeling those potatoes, or finish implementing that feature. Instead, find different tracks for the team to take on. In other words, have one team cook the apple pie, while the other team prepares the turkey.
Every morning, our team gathers around a whiteboard and maps out the top items in our backlog and their dependencies. If we do not have enough parallel work, we may bring up a few items in the backlog to make sure we have enough work to prevent our teams from waiting for the peeled potatoes.
2. Set Up Development Team Syncs
When you are working on a small development team, it’s easy to know everything that is going on in the code base. You are involved in nearly every project decision. You understand why a certain library was added, or helped develop a pattern for implementing a group of features. However, as your team grows, it becomes increasingly difficult to be a part of every conversation and every decision.
The solution is not to involve every team member in development decisions. If you’ve followed the advice of parallelizing as much work as possible, other members are likely deeply focused on another, unrelated area of the application. Interrupting them would prove costly to their productivity.
Instead, set aside a couple hours every iteration where the development team can discuss the code base. This gives teammates a chance to share their successes and struggles of the current sprint. If a team member was not involved in a prior architecture decision, it gives him or her a chance to ask questions about that decision and to involve that decision in his or her future work. It is also a great time to review testing practices and the overall feel of development.
3. Avoid Creating Experts with ‘Feature Leads’
As an agile team and company, we try to avoid creating silos. This mentality should not be forgotten on the development team. When working in a small team, members have a great understanding of the entire application. When the team grows, it is harder to know everything or be involved in every feature.
One way to organize a large team is to break them into sub-teams and assign a group of features to each sub-team. This approach may be preferred because it gives a sub-team the chance to understand one group of features excellently. But what happens when those members are no longer on the team and an interesting bug is found in that feature? All knowledge of that feature has been lost, and it will be costly to ramp a new team into that area of the code.
One way we have tried to evade “expertism” is to introduce the feature lead role. The feature lead is responsible for seeing a feature through from start to finish. Every team member is capable of being a feature lead. The team members that are not feature leads are considered free agents. Every day, free agents rotate which feature they work on by pairing with a different feature lead. Once a feature lead has delivered his or her feature, they go back into the free agent pool, and one of the existing free agents becomes a feature lead on the next item in the backlog.
So far, this method has worked exceptionally for our teams. Every member has some knowledge of the approaches and patterns in different parts of the application. It allows them to leverage those patterns and approaches in whatever feature they are working on that day.
4. Have Regular Code Reviews
As I’ve mentioned several times above, it is easy to know the entire application architecture and established patterns on a small team. However, even doing all of the above on a large team, it is still possible to have gaps in knowledge.
One final fix for this is to create a process for code reviews. On our team, we create a pull request for every feature we start. That pull request cannot be merged into master until the code has been reviewed by another teammate. In general, we try to find teammates that have the least exposure to the feature in question. He or she is encouraged to add notes to the pull request and also point out places that could leverage an existing pattern or use an existing helper.
As Atomic continues to grow in size and breadth of expertise, it will be important for us to experiment and develop patterns for handling and even thriving with larger teams. What are your large development team best practices? What struggles do your large teams still face?