Market Street, San Francisco. End of day.

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 team, with rare exceptions such as when someone was on sick leave or jury duty1. 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 driver2, 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 test-driven development (TDD) helps to build better and more structured code with clear contracts and interfaces3, pair programming gives the opportunity to discuss every step of the process, from architectural to code design decisions.

In a team of 10 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 are pairing today, tomorrow one of them will hand over the position to Carol. If Alice gives her spot to Carol on the second day, Bob will switch with Dave on the third day.

Day 1:   Alice + Bob
Day 2:           Bob + Carol
Day 3:                 Carol + Dave

The overlap is essential for knowledge transfer.

Which brings me to another topic: lanes of work. These are similar to epics, but more focused on implementing complete features. Lanes can last from a few days to a few weeks, and they are 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 are clear. Pair programming with TDD ensures that engineers are delivering their best work, while rotation ensures that they have a complete understanding of what they are putting into production, both from an engineering and product perspective.

This setup promotes a feeling of shared ownership, where everyone is responsible for the product and technical decisions. The constant rotation also gives engineers the opportunity to make adjustments to the technical choices made on previous days. It is always better to correct course sooner rather than later, which reduces technical debt.

Formal code review, such as pull requests, is not necessary in this setup. Code review happens in real time by the pair working on the feature, and commits can be merged into the main branch at any time during the day (and multiple times in most cases).

Shared ownership simplifies communication in the team. Questions can be addressed by any person or pair at any time. Every engineer has the knowledge and context to answer questions from the product owner, provide feedback to designers, or interact with external teams. This also eliminates 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 is the Pow Wow. This is a simple ceremony where engineers can stand up and discuss technical decisions for 5-10 minutes. There are 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 article.

  1. We had a list of chores in our backlog for when someone had to solo. Simple tickets with lower priority. ↩︎

  2. We didn’t use the terms driver and navigator. In fact, we didn’t have names for these roles. ↩︎

  3. I don’t see TDD as a tool to write tests, but as a framework to help me to write better code. ↩︎