The Beauty of Bad Code

Marlon Rodrigues
Vanila Blog
Published in
9 min readJan 29, 2018

--

Community of digital makers — Join now

How many of you have written bad code? I know, it’s hard to admit, but we all have been there, at least once. Unfortunately, bad code is a common thing in a developer’s life. We have either come across it or we have helped create it. Since it’s so common, why is it so hard for us to actually admit and embrace the fact that at some point we created code that is not, let’s say, our best piece of art? Well, I guess it all boils down to the fact that bad code is always associated with negative outcomes. And although for the most part that is true, we should always try to look at things from a different perspective. Thus, the title of this post: The beauty of bad code.

Before I dive into why bad code should not be considered such a bad thing, we have to understand what bad code is and how we can identify it and get rid of it. When we think about bad code, the first thing we might think about is what I like to call the super-villain code. This it the morally ethically bad code. Most of us are good citizens and we work towards innovations that will be beneficial for our society. However, there are developers out there with the sole purpose of creating chaos — the so called hackers. Hackers take advantage of system vulnerabilities and leverage that to take advantage of people and/or companies. This is morally bad and it’s what I call evil code — viruses and password sniffers are a good example of what an evil code is. In theory that could be considered bad code, but that’s not what I will be talking about today.

We have written a lot of code and in fact, we have rewritten our code several times. We are constantly rewriting code because the state of things are constantly changing. That means we know bad code — we have seen it, we have played with it and we got rid of it. But, the big question is: what exactly is bad code? Well, bad code can be related to 3 major categories:

  • Functionality
  • Maintainability
  • Readability

Those are the basic 3 tenets of good code. If your code is missing one of those, then most likely your code is not that great.

Functionality

Functional code is code that always does what it’s supposed to do. So basically, functional bad code is code that doesn’t do what it’s supposed to do. One good example of non functional code is the classic happy path approach, where code is written only taking into consideration a perfect scenario. That means that if something out of ordinary happens — a run-time error for example — you will have no idea how your code will behave and what kind of output it might give to the user. Another example is the famous “never trust the user”. Whenever our code relies on any sort of user input, we need to make sure we have proper code in place to handle all sorts of inputs a user might use in our application. In the example below, we have a function that simply formats an URL and fetches data from that formatted URL. The problem is that the name variable is a user input. Since we have no checks to make sure the name variable will have a valid value, there is no way to tell how this function will behave if the user doesn’t input what we are expecting.

function getPage(type) {
return (name, next) => {
var url = fmt('https://sampleurl/' + type + 'master/%s.md', name);
request(url, (err, resp, content) => {
return next(err, marked.parse(content));
});
}
}

Maintainability

When we write code we need to always keep in mind that our code should be able to scale and evolve if needed. Code that is not maintainable is extremely hard to scale and evolve. We need to spend countless hours just trying to figure out what is the purpose of the code, and a lot of the times a complete rewrite or refactor is needed in order to achieve the scalability we require. A good example of non maintainable code is the classic spaghetti code. Spaghetti code is code which flagrantly violates the principles of structured, procedural programming. Usually this means using lots of GOTO statements, hence the term, which suggests the tangled and arbitrary nature of the program flow.

Readability

Now, for everyone’s favorite section, readability. What’s important about readability? We want to make sure that anyone, whether that’s you or a teammate, understands what is happening in the code. So, it’s important that your code is readable so that other people, or you, can look at it and continue to work on it. The most classic example of unreadable code for me is clever code. When something is too clever, it makes it really difficult for anybody to get it on it. For example, let’s look at the code below. It’s a great example of how to reduce a function to just a few lines, but can you tell me without spending too much time what the heck is going on?

function transform(type, arg, data, skip, limit) {
if (!arg && transformKeyArg[type]) {
data = data.sort((a, b) => {
return a.value === b.value ? (
a.name === b.name ? 0 : a.name < b.name ? -1 : 1
) : a.value > b.value ? -1 : 1
}).slice(skip, skip + limit)
}
return data;
}

I know what you might be thinking: “Really? This is a ternary inside a ternary inside a ternary, what the heck?”. This is a perfect example of clever code — in this case, too clever. The rule of thumb is that if you — or someone else — needs more than 30 secs and a pen and a paper to figure it out what is happening, your code is probably not that readable.

So, how do we avoid bad code?

Before we jump into how to fix code poorly written, we have to first be able to identify it. So, what are the signs we see that might tell us that our code is not that great — also known as code smells?

Lots of branching paths

If your code has lots of if-then-else trees or a lot of ternary operations, it might be a good indication that your code is too smelly. Of course, we need to guarantee that we cover all possible scenarios, but having lots of paths doesn’t mean you have that coverage in place.

Context-dependent Understanding

Honestly, if someone needs a PhD to understand how your code works, that’s not particularly helpful. Yes, there might be some inherit knowledge, but think about a new developer: if they need to spend 6 months just to understand what is up in your code before they can contribute to it, that’s a bad code smell.

Long variable names

We all know how important it is to name our variables with meaningful and easy, self explanatory names. However, weird, long slash variable names are not good. The key point here is to have a balance between short and meaningful names.

It works on my machine

This is a classic one. How many times we have come across the case where the code might work locally, but it burns as soon as we deploy it to a different environment? It’s awesome if your code works on your machine, but if it doesn’t work on anybody else’s, that’s a code smell.

Reinventing the wheel

We love to write and create our own stuff, that’s part of the fun of our work, however, we should not reinvent the wheel. For instance, if you are a JavaScript developer, there is no need to write a new logger, you have the console.log for that. So, if you see code that is trying to recreate something that already exists, that’s a big code smell.

OK, now that we know to identify some of the code smells, how can we clean them?

Pair programming

Short sessions where you have someone else working with you — if you have been working in a set of code for days or weeks, you most likely will miss stuff. Having a fresh set of eyes helps you catch some of the code smells because that person will have questions, such as why you followed certain path on your implementation or because they might have a different perspective of the problem. Plus, discussing your ideas before implementation is a great way to validate them — better design means less refactoring.

Commit early and often

Every time you commit your code you are comparing your changes to what it is in the repo. That can be very helpful as you will be constantly checking to make sure you didn’t introduce anything unnecessary. For example, if you updated a function and you added 100 new lines to it, maybe you should review it to make sure all that new code is actually necessary.

Write tests

Unit and integration tests can be a pain, but they are a really good way to verify that your code is at least functional. Also, tests are a good way to actually check if your code is maintainable. If it is too hard to write tests for your code, it might be a good indication that your code is too complex.

Code reviews

That’s a very good practice to ensure accountability across the team. If you are the only one that knows how the code works and that code breaks while you are out on vacation, then everyone else is kind of stuck. So make sure that you have at least another developer reviewing your code. That will guarantee that, first, someone else is able to understand your code — maintainability/readability checks — and also that someone else in your team has a full knowledge of how things were implemented.

So, how bad code can be good?

When we write bad code, a lot of us don’t know it is bad code at that time. We don’t know it’s bad until later when we go back to it and find a bug and we need to refactor it. That’s a great opportunity because it’s a learning opportunity. Bad code is a learning opportunity for us to improve ourselves. It’s an opportunity for your code to give you feedback so you can be better. So, when you go back and refactor, now you learned and you will ensure that you don’t write that kind of bad code again in the future.

And what is wrong with bad code?

We all like to mock bad code and that’s OK, as long as it’s your own code. If we make fun of other people’s code, then things start to get a bit weird. It’s like a passage thing, where if someone makes fun of our code we will find someone’s else code to make fun of it. That’s not good, because new people that come in are afraid to publish anything because they are afraid that they will get mocked too. That’s not a fun environment.

People also tend to get too attached to their code. Always remember that code it’s just… code. We shouldn’t be too attached to it. Detach yourself from your code and understand that if someone comes up with suggestions for improvements, that person is not talking about you or your personality, they are talking about your code. Code is ultimately zeros and ones, it’s a thing for computers and it’s not about us at all.

Writing good code is hard. I have been writing code for almost 10 years now and I’m still learning new things and trying to improve. So, the takeaway here is to accept the bad code so you can become great a developer.

If you have any comments or suggestions on how we can turn bad good into good code, or if you have any fun stories from a time where you have written some terrible code, leave it on the comments below. And remember, stays curious and keep coding.

Community of digital makers — Join now

--

--

AI Software Engineer. AI & Machine Learning enthusiastic with an eye on Front End Engineering. Deep Learning practitioner. Life long learner.