A Programmer’s Guide to Revolutions
Programmers know that you have to be careful when making changes to an existing codebase. This is doubly true when working in production, and triply when other production systems depend on it, especially when the codebase is complex.
If you need to make changes, you need to make them gradually. Anything else – replacing the entire codebase with a new one or ripping out pieces – won’t work.
A well-tested code base is much easier to change because the testing phase (or as much of it as possible) is automated, which saves a ton of time and automates much of the error detection that needs to happen.
That’s why test-driven development is a great way to remain flexible throughout the life of your code. It takes a bit more investment in the beginning but usually starts to pay off pretty quickly. (Many programmers still don’t want to make that initial investment.)
If you find yourself needing to make changes to an existing codebase you don’t understand well, a tool like Suture may come in handy.
Reversibility is crucial, too. If you deploy a bug, you want to be able to revert to the last working version quickly. Imagine a bug in production costing you money every minute and not being able to revert! Version control like git is your friend here. If you don’t know which change introduced the bug, use git’s binary search – the
bisect command – to find the first faulty commit. You’ll want to master git reasonably well to become good at versioning your code as well as finding and correcting errors.
I’m not saying that replacing a codebase with something new – a revolution – is never the right thing to do. There could be many reasons doing so would be preferable over fixing an existing codebase. For example, if you just started the project and notice a structural mistake it may be easier to just start over and do it right than fix the mistake. More generally speaking, if an existing codebase is fraught with error and you have a good explanation for why starting over would be safe, go for it. (Although even then, in most cases you’d still do so gradually – replace a part of it, see if things still work, then keep going.) Or it may be the case that some software has come out that replaces your system and would be cheaper to buy than to maintain your system. That could be a working drop-in replacement.
However, the kinds of scenarios I have mentioned – running a complex system in prod, having other systems depend on it, not understanding your system or its dependants well enough, etc. – simply don’t let you do that. It could cost you a lot of money and effort if you mess things up. In addition, if only part of the codebase is broken, there’s no reason to throw out the whole thing.
Understanding this need for piecemeal, gradual, and easily reversible changes is one of the hallmarks of Karl Popper’s philosophy. He applied this insight to political systems, but it applies equally to any complex knowledge-laden system which you want to change, including your code, your projects, your relationships, and your life overall. The reason his philosophy applies to all of these things is that he hit on an important, far-reaching truth.
People don’t make enough gradual, easily reversible changes in their lives. For example, they break up with their significant other. Getting out of relationships gradually is difficult – they’re usually set up in such a way that you can’t go to a previous, slightly less committed stage. It’s either all or nothing. Some people move to another country without checking it out first to see if they like it. Taking a trip there first is low risk and low cost: you can just come back if you don’t like it. But if you quit your job, move out of your home and just move to a different country, the consequences can be disastrous. If you don’t like it, you end up coming back to ~nothing and need to rebuild. People uproot their lives in all sorts of ways, and they can get really hurt as a result.
As I said, Popper’s application of his piecemeal philosophy was to politics. Revolutionaries don’t understand that when they try to replace an existing political system with a new one, or yank out institutions without replacement, that will lead to big trouble. The stakes are much higher than for programming or anyone’s personal life because, as history has shown over and over, political revolutions usually lead to violence, poverty, hunger, and tyranny. Ironically, this is just as true for authoritarian revolutionaries such as communists as it is for anti-authoritarian revolutionaries such as libertarians.
We can’t just get rid of the government overnight. It’s a long-term project, involving much trial and error. We don’t know yet how to live in a society that doesn’t have a government. Learning how, like learning anything, is, as Popper discovered, an evolutionary process, not a revolutionary one. To build a path to a society free of institutionalized coercion, you need to slowly get rid of a couple of laws here and there, for example, see if things go crazy, and either reimplement those laws for a while if they do or keep going if they don’t.
Some laws are so ridiculous that it seems we could surely get rid of them overnight. Twitter account @CrimeADay has posted many such laws. For example:
18 USC §1865 & 36 CFR §2.16(f) make it a federal crime to make an unreasonable noise while a horse is passing by in a national park.— A Crime a Day (@CrimeADay) September 24, 2021
It would seem that society wouldn’t collapse without this law. Or:
7 USC §1622(h) & 7 CFR §51.2950 make it a federal crime to certify walnuts as U.S. grade no. 3 walnuts if the nuts are shriveled.— A Crime a Day (@CrimeADay) September 14, 2021
But there are also really important laws, such as this one:
18 USC §2236 makes it a federal crime for a federal employee to maliciously search property without a warrant.— A Crime a Day (@CrimeADay) September 10, 2021
Crucially, we can be mistaken about which laws are important and which are safe to get rid of. And for many we will need adequate private replacements. Fallibility alone implies that changes to existing systems should be easily reversible. Mistakes are inevitable and you don’t want to be stuck with a mistake. Therefore, revolutionaries always make a claim – sometimes explicit, usually implied – that they’re infallible. That’s always false because every human is fallible. Worse, we find ourselves in the precarious situation that governments themselves often try to institute revolutionary changes – like when they force all ‘non-essential’ businesses to shut down. Governments also tend to grow in size, influence, cost, and power, making it harder to get rid of them in the long term and to correct their errors in the short term.
If you’re a programmer who understands the importance of making piecemeal, reversible changes to code, but who simultaneously has authoritarian political leanings or makes revolutionary changes to his own life, you should think about why you endorse two opposite methodologies for making changes to complex, knowledge-laden systems.