Pair Programming, TDD, and Rotation
For about three years, I had the opportunity to work in the most interesting setup I have ever encountered in my professional career. It may sound complicated to maintain at first, but trust me, it is not. The results speak for themselves.
Pair Programming was the default in our development team1, with rare exceptions such as when someone was on sick leave or jury duty2. Some people might think that pair programming is difficult to achieve, and they often ask questions such as "Who drives?", "When is it time to switch?", and "What does one do while the other is coding?" when I mention it to them.
These questions are totally valid, and I would be hesitant to answer them for an environment that does not practice Test Driven Development (TDD). TDD was at the core of our culture, alongside pair programming. When used in combination with pair programming, TDD defines the boundaries for the driver3, making clear when engineers should switch roles. One engineer writes a test that should fail, and the other engineer writes the code that makes the test pass. Once the test passes, the engineer who just implemented the code writes the next test, and the ping-pong continues. At the end of the day, everyone ended up writing the same amount of code.
While TDD helped us to build better and more structured code with clear contracts and interfaces4, pair programming gave us the opportunity to discuss every step of the process, from architectural to code design decisions.
In a team of 10 iOS engineers, pairing indefinitely with the same person was not an option for us. We wanted all the engineers to have the opportunity to work with each other and in different areas of our mobile application (and Backend for Frontend, BFF). So we implemented pair rotation. Two engineers would never pair for more than one consecutive day. For example, if Alice and Bob were pairing today, tomorrow one of them would hand over the position to Carol. If Alice gave her spot to Carol on the second day, Bob would switch with Dave on the third day.
Day 1: Alice + Bob
Day 2: Bob + Carol
Day 3: Carol + Dave
The overlap was essential for knowledge transfer.
Which brings me to another topic: lanes of work. These were similar to Epics, but more focused on implementing complete features. Lanes could last from a few days to a few weeks, and they were typically independent from each other. For example, a lane could be responsible for implementing photo backup, a new settings menu, or mosaics to make a collage of pictures.
Each engineer worked in a lane for two days before moving to a new lane. This overlap in lanes allowed for knowledge transfer between engineers.
The benefits of this setup were clear. Pair programming with TDD ensured that engineers were delivering their best work, while rotation ensured that they had a complete understanding of what they were putting into production, both from an engineering and product perspective.
This setup promoted a feeling of shared ownership, where everyone was an owner and responsible for the product and technical decisions. The constant rotation also gave engineers the opportunity to make adjustments to the technical choices made on previous days. It was always better to correct course sooner rather than later, which reduced technical debt.
Formal code review, such as pull requests, was not necessary in this setup. Code review happened in real time by the pair working on the feature, and commits were merged into the main branch at any time during the day (and multiple times in most cases).
Shared ownership simplified communication in the team. Questions could be addressed by any person or pair at any time. Every engineer had the knowledge and context to answer questions from the product owner, provide feedback to designers, or interact with external teams. This also eliminated the feeling of "this is my code and I don't want anyone to touch it."
The last, but not least, important piece of the puzzle was the Pow Wow. This was a simple ceremony where engineers could stand up and discuss technical decisions for 5-10 minutes. There were no formalities, no meeting rooms, and no need to send out calendar invitations.
Because we were all on the same page about technical topics, it was easy to size user stories during planning meetings. After almost three years of working together, we had the confidence to perfectly size our one-week sprints, which simplified our backlog refinement sessions and plannings. This was extremely valuable for our product owner, who was able to maintain the backlog as relevant and prioritized as possible.
As a result, we had a fast-paced and united team that shared every aspect of the development process. We delivered high-quality code with confidence, released updates every week, and supported the product owner and designers. We eliminated time waste by doing code review in real time and technical debt by addressing bad choices sooner rather than later.
Of course, this is just part of the story. We also had a strong partnership with the product owner and designers, but that's a topic for another post.
That's right, eight hours per day!↩
We had a list of chores in our backlog for when someone had to solo. Simple tickets with lower priority.↩
We didn't use the terms driver and navigator. In fact, we didn't have names for these roles.↩
I don't see TDD as a tool to write tests, but as a framework to help me to write better code.↩