There's an engineering philosophy that I've developed over the last few years. One that takes a great deal of confidence to internalize.
I'm a bad programmer.
The idea acknowledges that I'm human and am prone to making several mistakes. This acknowledgment is magnified further in programming because it is an activity that is unnatural for humans. Instead of building solutions in three-dimensional space with our hands, we have to map our thoughts onto a two-dimensional file and pray that everything compiles correctly.
By embracing the mentality that I'm a bad programmer, I am constantly in pursuit of tools that compensate for my faults. These faults include but are not limited to typos, logical mistakes, and forgetting steps in common workflows.
Here are some examples of tools that have helped me create software in the face of being a bad programmer.
Formatting with Prettier
Programming is a communication medium. Building software is challenging because it requires us to use this communication medium to make the product's desired behaviors clear to authors, their teammates, and the computer that will inevitably run it. This requires numerous standards so that code is readable to our future selves and teammates, while still compiling into a format readable to machines.
It sucks to spend time thinking about these standards. It takes a toll on me mentally and a lot of my time to ensure things code is spaced properly so that people who aren't me could read it. In the ideal world, I could just chicken scratch my thoughts onto an editor as fast as possible and worry about making readable later.
Enter Prettier. Prettier provides developers the freedom to write their software however they want in a way that still works. They have integrations with most development environments such that when you hit save, all of your changes will automatically format to an agreed-upon standard! With just one click of Control+S you could turn a file that looks like this:
into this:
This allows me to make as many formatting mistakes as my human mind wants to make, while still sharing a version with others that meets a higher standard of quality.
Catching Bugs with ESLint
I write so many bugs. Left to my own devices, it would take me hours to finally get to a working feature without falling victim to a crash or null pointer exception.
This first resulted in me spending more time in the tedious feedback loop of building code, running code, and then debugging what went wrong. Ideally, the mistakes are made extremely evident to me before running the code, in a way that is really obvious what should be fixed.
Enter compilation tools like ESLint. ESLint scans the source code at build time for common patterns that usually result in bugs being thrown. This gives developers the forewarning they need to fix these issues ahead of time instead of having to discover them for themselves while running the code. When combined with TypeScript, the two could act as a spell checker in any of the popular IDEs to catch mistakes as you write code.
Here's ESLint prompting me to use consts which are generally more error proof:
Here's TypeScript warning me that I'm about to pass in an unexpected type into a function:
While these examples are pretty straightforward, each of these tools support hundreds of rules and patterns that they are constantly checking for. They make sure that I don't fall victim to the bad programmer in me pushing those mistakes to users.
Automations with GitHub Actions
Pushing new updates to users usually comprises of the following steps:
Installing dependencies
Building the code
Sending the built code to AWS
Missing a step in this process could result in a half baked product live with users or confusion surrounding why users are on an older version.
These steps also only represent a minimal use case. Many companies have deploy processes that could take weeks or even months. Retrospectives are often written after each one detailing what steps were forgotten and how could they improve going forward.
Enter GitHub Actions. GitHub actions are automated workflows that run as soon as some event is triggered on GitHub. Instead of having humans manually run all of those steps that I detailed above, actions allow us to just tell the robots to do it.
The automation removes the responsibility of running these steps from the bad programmer in me. It also performs them much faster, allowing me to run larger and more complex workflows.
Collaborating with Others
Each of these tools have helped me embrace the fact that I'm a bad programmer. But, more importantly, they've shaped how I view working with other engineers.
I cringe whenever I hear someone says some person they've worked with or interviewed is bad at programming. The perspective is short sighted. What's far more important than whether someone is good at programming is whether they are good at implementing systems that compensate for their shortcomings.
This is the approach I've come to enjoy most when working with others. I appreciate those who are honest but impatient with the flaws they have as a programmer. Instead of solutions of the form "people just need to be better", I want solutions of the form "what could we build given this behavior about us?"
So I don't want to be a good programmer. I don't want to work with good programmers. I want to find and build systems that could scale up what we could achieve faster than we could improve ourselves.