In a perfect world, I believe that all developers strive to write perfect code. However, the real world prevents that from being a reality. With deadlines and external pressures, developers end up taking shortcuts and having to choose between doing things well or getting things done. Sacrifices and bad practices (anti-patterns) start to seep in until one day it just starts to rear its ugly face. The result is what we call code smell.
In this post, I will be going over 7 anti-patterns that I have seen often in the codebases I had worked on. Some of the anti-patterns, I have been guilty of myself.
1. Spaghetti Code
You have probably heard of the term “spaghetti code” before and may even have worked on a codebase that is a representation of it. To simply put it, spaghetti code consists of pieces of code that seem to be disjoint but are connected in some sort of way. For example, A references B which references C and D which sometimes references A or E depending on some conditions. Now, let’s say your task is to update A with a new functionality. The risk of changing A without impacting B, C, D, and E is not very high.
In a perfect world, each piece of code would have a single purpose and identifiable boundaries. However, in the real world, that doesn’t always happen. Spaghetti code starts to creep on you when you are trying to extract a functionality. Everything is so tangled up together that changing one thing just breaks everything else.
2. Repeated Code
You might have heard of the DRY (Don’t Repeat Yourself) coding principal. This anti-pattern is the total opposite of it. A similar code is copy and pasted throughout the codebase instead of one version of it being used. Now if that copy and pasted piece of code has a bug, you have to fix it then go on a scavenger hunt to find each location the piece of code is used. Of course, in such a case, you should take it as an opportunity to refactor the piece of code to a method and use it in the other locations.
3. House of Cards
No, not the TV show, I am referring to an actual house of cards built with playing cards. It’s elegant and beautiful, much like some code that exhibits this same structure. You can’t believe it actually works. And like a house of cards, you don’t want to touch it because you know that if you do it’ll fall apart.
When dealing with code that falls under the house of cards pattern the first step is to create a solid foundation. Without a solid foundation, it will be brittle and can collapse by the touch of anything. As you can imagine that would be just a nightmare to work with.
4. Premature Optimization
Premature optimization is an easy trap to fall into. You see a piece of code and feel the need to write a slightly more complicated version because it would be faster. While your intention is good, it does take up valuable time and it makes the code more complicated, which will likely introduce more bugs.
Now, I am not saying we should intentionally write slow code. For example, using proper data structures for your use cases are important.
In most cases, you should strive for maintainable and readable code as the first step. If performance does become an issue then identify where the slowdown is coming from and refactor as necessary. Often the slowdown is not where you would expect it to be happening. If you would have spent your time optimizing what you thought would cause slowdown it wouldn’t have help in this case.
5. Inconsistent Code Style
I’m sure many of you can agree on consistency is key. While there is no one best code style, it is important to decide on a set of coding styles that your team agrees on. Once you and your team determined the style, actually enforce it. Don’t accept new code unless the code style falls in line. Code that looks the same no matter who wrote it helps with the readability and maintainability of your code.
6. Non-Descriptive Variable Names
Have you ever encountered some piece of code that made you scratch your head because you can’t figure out what is a, b, c and why does e need to be a times b? Now that was an extreme example of non-descriptive variables which I hope you have not ever encountered before. But you probably have encountered abbreviations in variable names which took you some time to figure out what it means.
Code needs to be read by people, so there is no need to avoid spelling out the word instead of using abbreviations — especially since many code editors have autocomplete capability. It makes the code more readable and understandable too so it’s worth it.
7. Meaningless Commit Messages
Most version control systems will have a way for you to write a message for your code’s state at that moment. Take advantage of it and write something meaningful. So, you might be asking yourself why do you need to do that when you know exactly what is going on. It’s actually for other developers to know what you’re doing and maybe your future self.
Now, if you’re convinced that maybe a more detailed message is a good idea here are some ideas on what to say. The message should answer the “why” and sometimes the “how” to what you did. For example, why were you fixing something, why or how something is broken, how does this affect clients or other parts of the system? You don’t need to write a whole essay, but by looking at the commit messages it should give a good idea of what is being worked on.
I hope this post was helpful to you. If you found this post helpful, share it with others so they can benefit too.
How many of these anti-patterns have you seen? What are other anti-patterns you’ve seen that contribute to code smell?
To get in touch, follow me on Twitter, leave a comment, or send me an email at steven@brightdevelopers.com.