TDD and Peer Programming Benefits

Damien Hanoun
YounitedTech
Published in
7 min readMar 12, 2024

Some months ago, I took the lead in interviewing new talented developers for my team. I wanted to accept only developers with a foundation for producing quality software (clean code, TDD, peer programming, …) or those interested in doing so.

I have encountered candidates who did not initially understand the benefits of such techniques. After the interview, some of them told us they understood how these techniques could help them do better work for the first time.

Since my arguments helped them to understand the benefits of these techniques, this article is a good opportunity to share my vision of them.

TDD benefits

Developers often reduce TDD to writing unit tests first and the red-green-refactor approach. And that’s pretty much it, which is somewhat reductive.

I would feel more comfortable using Specification-Driven Design or Intent-Driven Design to demonstrate what matters, but it may be a little pretentious.

Here are the points I will use to talk about it:

  • The to-do list: Seeing what you achieve and what is left is a powerful tool to stay motivated. It also encourages thinking step by step without knowing everything from the start. The list will generally evolve according to new problems during implementation. Kent Beck's Test-Driven Development book represents it well. On my side, I keep only the following steps as a to-do list, and the previous steps are visible from my commits.
  • Contract first: There is a greater chance you would care about your class contract if the first thing you see and update is what you see from outside. When seeing the internal code of a method, it will make us tend to adapt the contract according to changes done inside, which has a greater chance of leading to poor design decisions and tests being more complex to maintain and understand.
  • More small tests for quicker feedback: Working incrementally with small intents allows us to have feedback sooner than waiting to finish an implementation before testing. If your test fails, whereas you expect it to pass, you lose only seconds or minutes to diagnose what’s wrong. I often face tests done after the implementation, which causes me to lose precious time refactoring tests and implementation and correcting logic errors that could have been done.
  • Double-check: In the finance world, there is a double-check system to prevent errors. Here, it is the same. Moreover, if I work alone, having the test and the production code work the same way is reassuring.
  • Remove coverage percentage goals: Coverage is not an argument of quality. Quality will come from how you design your tests (structure and data), how much they help you detect unexpected change daily, and at which velocity.
  • Commit quality: When facing a pull request linked to a subject I don’t know, I look at commits to understand the developer's reasoning and give better feedback. As for me, you probably face commits like this: «Implementation», «Add unit test», «Correct errors», … These are not very helpful to follow the story of what has been done. TDD will help to commit by intent, resulting in a commit name that would look more like this: «Add trade-in option for the prospect in point of sales».
  • Handle each day with more confidence: It already happens to me to start working on a subject at 18h. Keeping my intents small, I had the time to do two commits and stop working at 18h30. Also, facing a vast subject that implies mental overload allows me to reduce it by evolving the solution step by step until I see a final solution I may not have seen from the start.
  • It is not only about unit tests: It often happens that I will start to define what I want with an end-to-end test or integration test and make it fail first. Then, I will do a second level of TDD with unit tests. To validate integration between my pieces of code, I will sometimes relaunch end-to-end/integration tests to have feedback about my implementation (like checking that dependency injection works with my new classes) to finally come back at the end and check if my first test does what I expect.
  • Prevent over-engineering: By treating problems individually, we avoid overthinking the final solution and allow it to evolve only according to the issues we face.

Even if it is a little off-topic, if you have executable acceptance specifications that execute fast enough to be used in your development workflow, you should consider reducing the number of unit tests to cases with risk.

Anyway, TDD is a tool that could help you go the right way, but remember that it will not make design decisions for you.

Peer programming benefits

When I talk about peer programming to developers, they often think it is just about having two developers behind a computer that work together on the same subject. And that’s pretty much it. Again, this vision is somewhat reductive.

Here are the points I will use to talk about it:

  • Peers have different roles: The one with the keyboard is the session conductor in charge of updating the code, whereas the other is the observer who gives the orientation. This idea of not overlapping responsibilities mainly reduces friction and improves the workflow.
  • Peers often change their roles: You must change roles based on a timer or at each commit on a small amount of time basis.
  • Feedback, sharing, and learning: Coding with colleagues is an excellent knowledge-sharing strategy. You will share what you know by design, get a lot more feedback of better quality on a lot more aspects (like the habit you have in your IDE, the way you treat a problem, or the tools you like to use) than what you could get with pull requests, and learn a lot more quickly. It could reduce the need for presentations or documentation.
  • Continuous non-blocking code review: If you embrace the continuous integration philosophy, you certainly look to make ideas go faster to production without leaving quality aside. If everyone works with everyone in a team, methodologies, tools, and techniques that work best will be used by all team members and will increase trust. If you trust your colleagues, you could start thinking about removing the pull request system (which is a blocking system). On this point, I am strongly influenced by Dave Farley’s videos (like I’ve Found Something BETTER Than Pull Requests…), whom I could consider as my mentor. As he mentions, the idea of slowing down for safety is a mistake; we don’t improve quality by adding more bureaucracy to the process. Not to mention the time I spent explaining why I made some decisions in pull request comments before sharing it with the team.
  • Team capacity stabilization: If you need to forecast (using NoEstimates, for example), one of your goals is to make your team predictive to reduce the forecast range. One way to achieve that is peer programming to improve knowledge-sharing and resilience to arrival, holidays, departure, or sick leave.
  • Improvement of quality: Two heads are better than one. Even if it ends with a slight improvement, we all know how small details can impact production or team productivity in the long run. I often hear the argument that it costs twice as much as a developer working alone, but we are comparing the quickness of delivery and quality. If, like me, you consider that quality is more critical and valuable for quickness in the long term, quickness at day level is irrelevant.
  • Shared energy expenditure and solving problems faster: Working with someone else will help you stay focused, especially if you are tired or the subject requires knowledge and energy. Mob programming could be a better strategy if it is a dangerous update. Listening and talking are other points that change our experience and could help us to envision our subject better and faster.
  • Peer as protector: If you work in your company’s building, the chances are high that someone will come to ask you something. Using your peer as protection against distractions can be helpful.

When I think about it, the only concrete example I have of a team that constantly uses peer programming was at Expedia. It was six years ago during a meetup where Julien Topçu and his team talked about how they handle projects using MVP, DDD, and agile methodologies like NoEstimates, eXtreme Programming, and Kanban—a fascinating way to organize.

Conclusion

If both allow quicker feedback and quality improvement, both also require practice to master and, in an ideal world, work with experienced people on these techniques. I never had this chance, which makes me think I still have much to learn.

I practice TDD every day and rarely face cases where using it would not make sense. I tend not to use it for test code helpers or proof of concept. I know the TCR (Test Commit Rollback) methodology will tend to be the successor of TDD, but I don’t feel comfortable using it yet.

For peer programming, I can’t use it as often as I want, and I have only used it a few times, but I have had some incredible experiences with it, even though I know I could be doing better. For the future, I am waiting for the «Code with Me» tool of JetBrains for Rider to experiment with doing peer programming with both developers coding simultaneously. I feel there is something to do with it.

Combining them feels very powerful, but I stay alert when using tools, techniques, or processes to prevent the “everyone does it” or “it is a good practice” effect. These arguments are invalid and prevent us from considering why we use them. If they don’t fit our context and we have strong arguments, we should not use them.

Think for yourself, experiment, seek to work with talented people, and keep what will make your life better.

--

--