Every Programmer is Fighting Themselves

First published in 2017

Every programmer brings two selves to each coding problem or even each line of code, and only one of you can win. The sooner you realise you are your own enemy, the better.

This is a general truth in all aspects of life, but as programmers we sometimes forget that we are humans running on a buggy meatOS with competing programs. These two programs are called short_term_interests and long_term_interests. In every decision we make we have to contend with our long term interests versus our short term interests.

Lets see what resources these two programs have at their disposal. Long term interests has intellect, planning, imagination and knowledge at its disposal. On the other hand short term interests has… feelings. Oh dear, this is like having sudo access over your meatOS.

But when does this really matter? Well as programmers we all make the most logical, informed decisions with the knowledge at hand, 100% of the time don’t we? HA! Every time you have skipped a test, lazily named a variable, skipped refactoring that code or neglected to write a detailed commit message you’ve let short term interests win. In other words, all instances of bad code are symptoms of poor emotional control.

So what will you do about it? The way I see it you have two options - keep making horrific mistakes until long term interests gains access to the initFear() method. OR you can use intellect, planning, imagination and knowledge to hack your meatOS now.


Well, we can learn to imagine the long term consequences of our actions more vividly. If you’re avoiding writing a test, spend some time imagining coming back to this function later when its broken, your boss is pissed, the company has lost money because of you, and the a*hole who wrote this function didn’t write any tests so you don’t know what else might break when you fix it, or even what ‘fixed’ means. I bet you feel a lot more like it now.

Another common error is thinking that you will do the hard boring bits tomorrow. Which is like saying I’m going to wake up tomorrow and instantly have my ideal body because today I ate a heap of junk food. Instead, imagine that every decision you make today, you’re committing to making repeatedly for the next 7 days. Didn’t write a commit message? Well now you have 7 days without commit messages. These are the true stakes, because we will do again tomorrow what we did today. Now that one indiscretion feels a lot more serious doesn’t it?

Some people might say “but Anthony, I have too many important, urgent tasks to spend time looking after long term interests!” Guess why you have so many important urgent tasks? Because every time short term interests wins, the long term version of yourself has to pay for it. Eventually all you’re doing is paying debt with more debt and it’s game over. This is where you need habits and processes in place that prevent you from taking shortcuts. Things like setting up Continuous Integration/Delivery so you can’t deploy without all tests passing on master branch. Set it up so that a build automatically fails if test coverage falls below a certain threshold. Sometimes the best thing you can do is limit your influence over the process.

It's often not a matter of avoiding feelings in order to meet long term interests - that's too hard. Instead, it can be a matter of building emotional stakes in favour of making the right choice. This is often what people value about "experience", it isn't so much the knowledge itself but the predisposition to use it sensibly. By being conscious of the process you can build emotions around best practice faster and with fewer mishaps. That way, when it's 4pm on a Friday, your coffee has ran out and Joe ate the last of your favourite snacks, your meatOS is less likely to make a bad choice.

Update 2021: I first wrote this post in 2017. While I still think a lot of it is true, the factor I missed is habits and practice. Kaizen pays big dividends here. If your patterns are muscle memory, you can spend your brain cycles on big picture problems, rather than trying to recall the pattern for read model populators or the docker syntax for multistage builds. Unfortunately that means typing the same thing over and over at somewhat regular intervals.