2019-03-08
My goal with this post is to maybe put a seed of doubt into how you perceive what is ‘good’ code and what is ‘bad’ code. First though, I’m going to break down what I feel someone means when they say ‘This is good code’ thereby defining ‘bad’ code as the opposite of that.
When I hear someone qualify code as ‘good’ code it generally means that the code meets some checklist of principles that they have internalized over their career or education. These are definitely not the same for every programmer and can vary greatly for programmers who follow different programming paradigms like Object Oriented vs. Functional. Here are some examples that you’ve probably heard and possibly believe yourself:
The list could go on and on. Good code often dogmatically follows these rules and any piece of code that doesn’t is a hack or something that needs to be refactored later. Bad code, being the opposite of good code would be code that doesn’t follow these rules.
I feel this is because of our need to quantify things as engineers. We want a reproducible method of solving all problems, the One True Way so we come up with rules to follow that will always produce ‘good’ code.
What’s the problem with this? The first issue is that you can no longer solve the problem in the most straight forward way. You’ve constructed a maze of restrictions to code around that will ultimately end up in more code being written. It will take longer to write this code as well since you need to think not only about solving the problem you set out to you have to solve it in a way that satisfies the numerous constraints you’ve imposed on yourself. This is tantamount to coding with one hand tied behind your back.
Next, as I said, you end up with more code. Not only more code but code that doesn’t solve your problem. It’s code that solves the fake problem you made for yourself. The more code like this that your project has the harder it becomes to understand what is happening. The signal to noise ratio can quickly deteriorate as more code is added to deal with problems created by code that was never needed in the first place. Some of the worst cases I’ve seen of this happen when trying to follow some architecture or introducing patterns into the code.
It’s also evident to me that these rules of ‘good’ code are so ingrained in people that they can’t see past them. On a Hacker News post a few days ago there was a classic “Look at this architecture in a toy example, it will solve all your problems”. In this case it was about Entity Component System. Jon Blow commented pointing out that ECS is completely unnecessary and this could be better solved by writing code in the most obvious way. This reply which I’ll quote here exemplifies the mental shackles ‘good’ code puts on people:
By the obvious way, I’m guessing you would just have a single type ‘entity’ and put all entities in an array? While that may be obvious to you, it’s not obvious to a lot of programmers (myself included) who grew up learning about object orientation, abstractions and modeling behaviour on the real world. ECS’s for all their added complexity come with the breath of fresh air that is classical imperative programming where all the data is just available. There are scant few sources for learning this, Handmade Hero being a notable exception.
People have been so indoctrinated into the cult of ‘good’ code they can’t even fathom what straight forward code might be. They can’t think about programming without thinking about objects and modeling real world things. The only way they can break free from the shackles of ‘good’ code is to swap their current set of rules for another. You don’t need an ECS to have access to the data you just need to not follow the rules which tell you to hide it in the first place. What’s the obvious way to code the solution? It’s not a trick, he just means write the code that does the thing you need done. Write the code that does the thing. Enties have nothing to do with solving the problem. I can guarantee you that Super Mario Bros. doesn’t have a concept of entities in the code.
Here’s some ‘bad’ code:
void jump() {
.yvel = 10;
mario}
can tell there are alarm bells ringing in your head. “But what if something other that Mario needs to jump?”, “Is mario a global? What if I need more than one mario?”. These things don’t matter. This code solves the problem I’m trying to solve, Mario needs to jump. Not the ones I don’t have, multiple Marios and things other than Mario jumping. Don’t pre-emptively solve problems you don’t have, solve the ones you do. If I do need to have multiple marios then I can change the code later when that comes up, it’s really not that big a deal. Your bad code will probably be shorter and to the point.
Write bad code. Ha-code-a Matata, means no worries for the rest of your code. Forget all the rules and just write code to do the thing. Solve your actual problems not some problems that someone else has told you that you might run into in the future. Sometimes you’ll write a big ol switch statement because that’s the most obvious way to solve the problem. Embrace it, don’t waste your time thinking of a way to make it ‘nicer’ or ‘elegant’. Write abstractions when you face real maintenance hardships, but write small abstractions you probably don’t need an ‘architecture’.
We write software to solve problems. If the code you are writing is not solving the problem you set out to solve but one imposed upon yourself, consider writing bad code. Maybe you’ll become the 10x developer everyone is amazed by.
<< Back