Tragedy of the codebase commons

Tragedy of the commons is a situation in which individuals have access to some shared resource. The individuals act independently to their own self-interest, and contrary to the common good of all, ultimately destroying or depleting the resource.

Classic tragedy of the commons example

The classic example follows cow farmers feeding cows on a shared (common) pasture.

Each farmer wants to make the maximum amount of money, to make more money the farmer needs more cows. There are two rates involved;

  • the cows eat the grass on the common pasture at a certain rate: grass eaten rate
  • the grass grows at a certain rate: grass growing rate.

So long as the grass growing rate is larger than, or the same as, the grass eaten rate then the system will balance. The grass will be renewed at least as fast as it is eaten. The amount (stock) of grass will not go down.

The thing is, the grass growing rate is not linear or even. As more cows are fed on the common pasture, the stock of grass starts to go down. Soon there’s not enough grass blades for the cows to eat, so they start eating the lower stems of the grass. These stems are needed for the grass to regrow quickly.

The grass growing rate decreases as more of the grass stems are eaten. So the degradation of the pasture accelerates; because the same number of cows means the grass is being eaten at the same rate, but it’s now regrowing more slowly.

Eventually, all the grass on the pasture is eaten, and won’t regrow. All the farmers are ruined because they can’t raise cows.

Clearly it’s in the collective interest not to overgraze the pasture, but in the individual interest to have as many cows as possible. This dilemma is called ‘bounded rationality’. The farmers will tend towards individual interest, even though it leads to ruin.

System fixes: “Tragedy of the commons”

There are three ways to solve tragedy of the commons:

  1. Educate and exhort. If the farmers understood that their individual actions would lead to ruin, maybe the would make different decisions. Maybe you can fix the system by appealing to the farmers collective rationality, morals, and fairness. If we all stop adding cows, then we can all avoid ruin. Commonly, it only takes one farmer to ignore this, and all the others slip back into their individual interest.
  2. Privatise the commons. This is an example of ‘internalise the externalities’; to take the external cost, and provide a direct-feedback-loop to the individual. If each farmer owned an private section of the pasture, then only that farmer would be ruined by overgrazing. It’s clearly in the farmers interest to keep only a sustainable number of cows. The farmer will likely start looking at how to increase the size of their pasture, rather than grazing more cows.
  3. Regulate the commons. If we set some rules on how many cows a farmer can keep, then we can control the overall number of cows on the pasture, and keep the pasture sustainable. This is regulation. For regulation to work, we need both: 1) a regulatory authority to set, review, and adjust the rules and 2) policing to ensure the farmers are following the rules. Plus, the regulatory authority and policing need to be strong enough to create a deterrent for the farmers, so they will not overgraze the pasture. This is an indirect feedback loop, via the regulatory authority, policing, and deterrent. It should be clear that the regulation is to protect the common pasture, but it’s less directly-clear to the farmer. The farmer might start arguing against the regulation (regulation that’s ultimately in place to protect the farmer from ruin).

Tragedy of the shared codebase quality

We see the exact same pattern as multiple teams work on a growing shared codebase.

Each team wants to ship as many features in the codebase as possible, but new features can have an negative effect on the overall quality of the codebase. It’s in the individual team’s interest to ship the feature. But the more teams who ship features that are of low quality, the harder it is for any team to ship any feature.

Here all the teams face collective ruin (not being able to deliver features), but their bounded rationality leads them to make locally-optimal individual decisions.

Without a system fix, the quality of the codebase will tend to zero, until no team can deliver any feature.

System fixes: “Tragedy of the shared codebase quality”

The system fixes are exactly the same:

  1. Educate and exhort. Educate the teams, and hope it is enough to change their incentives and behaviours.
  2. Privatise the codebase. Split the code into sections, and hand out responsibility for each section. Only the owners of that part of the code will make the changes to it. So only that team feels the cost of the poor quality code.
  3. Regulate the codebase. Either through automated tools like tests, linters, etc. Or though manual processes like code-review. Regulating the codebase still requires a regulatory authority to set the rules, and policing to enforce them.

If you’re trying to improve the code quality of a shared codebase, you probably need to employ all three of these system fixes. And you’ve probably found yourself doing one-or-two of them already. Most commonly, I see people ‘policing’ and ’educating’. But these two are both indirect mechanisms of feedback, try ‘privatising’ a module in the codebase and see how that affects the system.

The fix
Educate the engineers, regulate the shared code, and privatise parts of the codebase.