Back

Software development is not like surgery

19 Feb 2024 (collaboration, pair-programming, source-control)

Pair and mob programming are often seen as the gold standard for collaboration. Multiple developers sit around a computer (or on a video call) and combine their efforts to work on a single problem, which reduces the time needed to solve it and allows for immediate feedback—two heads are better than one.

In fact, a previous colleague once told me that he thinks we should be pair or mob programming all the time. He presented his argument as a simple syllogism:

Premise 1:     In surgery, a simple instance of human error could be catastrophic for the patient, so surgeons are expected to work as part of a team to decrease their chances of making a mistake.
Premise 2:    As software takes over more and more of the systems we all rely on, the consequences of a mistake in software development could be similarly catastrophic.
Conclusion: Software developers should always be mob or pair programming to prevent these kinds of mistakes.

I think the argument is a sound one. It’s worth mentioning that each person in an operating theatre has a different role, which isn’t typically the case when mob programming, but reducing errors is certainly another major reason for the approach—I wouldn’t feel nearly as confident going into surgery if I knew the surgeon would be acting alone.

And it’s true that increasingly, a bug in a piece of software can be more than a minor annoyance, and can instead have dire consequences. The recent publicity around the Horizon scandal in the UK has made that clear: a bug in the Post Office’s accounting software led to hundreds of postmasters being wrongfully convicted of serious crimes.

But there is a crucial difference between surgery and software that informs why human error is necessarily so dangerous in the former, but not in the latter. If a surgeon makes a mistake that causes damage, that mistake cannot be taken back. It might be possible to fix the damage, but there is no backtracking—the action is final. In an ideal world, the surgeon would make their changes in an isolated environment, like a draft state, then they would hand their work over to another surgeon for review. When the team has taken their time to search for errors and ensure that everything has gone to plan, they would “commit” their changes and they would be applied to the patient for real (you see where I’m going). In such a world, if a surgeon felt that their best work happened when they worked alone, they would be able to do so without consequence; some surgeons might still work in groups, but only if they felt that it was helpful.

Maybe technology will one day make this kind of workflow a reality, but as things currently are, surgeons live in an imperfect world where their changes are always necessarily final. In software on the other hand, we do live in this ideal world. Because of tools like Git, every developer has their own, isolated environment where no matter how much damage they wreak, users of their software will be completely unaffected. It’s only once their changes are deployed into production that any mistakes bear fruit (hopefully after a period of thorough peer review where they are caught and fixed). For this reason, even if a developer has worked on a feature completely alone, there is still ample opportunity for their changes to be reviewed by their teammates asynchronously.

My point here is not to suggest that we shouldn’t be pairing or mobbing, but that we have the luxury of choosing without putting users of our software at risk. To speak for myself, I am one of those aforementioned people whose best work happens alone. Being surrounded by teammates while trying to reason about a problem creates pressure that distracts me from the task, like someone looking over your shoulder while you type an email. On the other hand, I’m more than happy to pair on a problem with a teammate if they feel it will help them—we should be flexible and consider the differing working styles of our teammates.

This does of course mean that we have a responsibility to perform robust, in-depth peer reviews before our code reaches users. Creating well-structured, intentional commits with meaningful messages is crucial to ensuring that the teammate who reviews your code is able to properly understand it, even when the pull request is large. However, I’d argue that these sorts of practices have benefits beyond enabling flexible styles of teamwork.

During a pairing session, valuable feedback might be given, but it isn’t captured. The solution to a problem might be well-understood by the people who worked on it, but down the line a new team member might revisit that same section of code, and will not have any of that context. Git commits and pull requests are captured and stored, enabling communication with future team members, even after the author of the feedback has left the team.

This kind of communication is invisible until it’s needed, which I suspect is one of the reasons why pair programming is often pushed for by project managers. The latter is the most visible form of collaboration, which assures those in less hands-on roles that teamwork is indeed happening. But I’d suggest that asynchronous collaboration and communication is more important to ensure continued code quality over long periods of time and despite team changes.

As more and more aspects of our lives are influenced by software, it is absolutely the responsibility of dev teams to ensure that good practices are followed to avoid introducing bugs that could have serious consequences for users. But the intangible nature of our work gives us a kind of flexibility of working styles not enjoyed in many other fields, and we should take advantage of this flexibility to enable developers to contribute fully to collaborative practices while working in the way that works best for them.