If you've been programming for even a little while, you've probably come across the term "code smell". You probably have a good idea of what it means. And you've probably used it on numerous occasions. But I'm here to tell you that it doesn't quite mean what you think it means. Or, at the least, what I hear when someone says "code smell" is probably quite different than what you hear when the same words are uttered.
The Formal Definition
As a somewhat colloquial term, there's really no official definition for "code smell". So we're gonna start out with the basics - from Wikipedia:
In computer programming, a code smell is any characteristic in the source code of a program that possibly indicates a deeper problem.
OK. So far so good. This definition is probably as useful as any other. But Wikipedia doesn't stop there. The next sentence says:
Determining what is and is not a code smell is subjective, and varies by language, developer, and development methodology.
Hmm... Interesting. Pay keen attention to that word "subjective", cuz that's what I'm about to dive into.
The Practical Definition
In my experience, "code smell" all-too-often means this:
I can't quantify exactly what I don't like about your code. And I can't be bothered to explain this to a plebian like yourself. But I don't like it. So I'm just gonna dismiss it with the all-encompassing label of "code smell".
Obviously, I don't think this is the "definition" in everyone's mind every time they use the phrase. There are plenty of benign uses of "code smell". I've used the phrase myself. Everyone has. But I've seen too many scenarios where the use of the phrase falls under the definition I've listed just above.
How Did We Get Here?
I don't remember anyone ever talking about "code smells" when I started my career. When I read further on Wikipedia, this makes sense. Wikipedia states:
The term was popularised by Kent Beck on WardsWiki in the late 1990s. Usage of the term increased after it was featured in the 1999 book Refactoring: Improving the Design of Existing Code by Martin Fowler.
That actually tracks quite well with my recollection. There was some point in the mid-to-late 2000s when, seemingly out-of-the-blue, I began hearing colleagues shoot down coding examples as "code smells". It was as if the term suddenly materialized in their brain and they seized upon it as a convenient (read: lazy) way to invalidate broad swaths of legacy code.
It's not that I have a problem with the phrase itself. Nor am I bothered with (what I believe to be) its underlying premise. Rather, I quickly became annoyed at the way in which many of my colleagues suddenly felt empowered by the phrase to dismiss other solutions with no further explanation or consideration.
I'd pull up a code sample - maybe something I'd written, maybe not - and before we could even proceed, someone would chirp up that it was a "code smell". And... that was it. Once someone throws out the "code smell" bomb, good luck getting them to rationally consider anything else that they see in that block of code.
Talk To The Hand
Here is just a sampling of the kinds of code I've seen dismissed as a "code smell":
Older Languages - Look, I understand that many people hate PHP. But code should never qualify as a "code smell" merely because it's written in PHP (or any other language).
Older Frameworks - There are billions of lines of jQuery out there in the wild today. They're not going away any time soon. Get over it. If you wanna label every line of jQuery code as a "code smell", you need to ensure that you never ever work in a shop where legacy jQuery code still exists.
Something Other Than Your Favored Paradigm - Maybe every single one of your React components is written with functions and Hooks. If so, then Yay! for you. Go eat a cookie. And try not to sprain your elbow while you're patting yourself on the back. But your religious adherence to functions doesn't meant that a class-based component is a "code smell". It's just... not. Get over yourself.
Competing Coding Styles - There are a million different ways to write the same set of instructions. Your team has probably settled on their preferred coding styles. But that doesn't mean that other styles are "wrong" or "code smells". For example, if you want the old guy to dump his
function
keywords in favor of all-arrow-functions, all-the-time, then that's fine. Talk to him. Explain the standards on your team. But don't be a jerk by just dismissing any use of thefunction
keyword as a "code smell".
You may be reading this list and thinking that none of these broad examples truly qualify as a "code smell". And you'd be right. I'm just ranting about the fact that I've seen the "code smell" phrase used as a global catch-all for: "code that I don't like and I want to shame my colleagues into abandoning it".
Anti-Patterns
The code smell has an ugly sibling. It's called the anti-pattern. Just like "code smell", there are legitimate times when something should probably be labelled as an "anti-pattern". And just like with "code smell", the phrase is too-often used as a lazy way to discard alternative approaches - without bothering to quantify why those approaches are bad.
I personally find anti-pattern to be particularly affronting. Because a "pattern" is neither right nor wrong. Patterns are "right" when they're used in the "right" scenario. And they're "wrong" when they're used in the "wrong" scenario. But once someone slaps that "anti-pattern" label on your approach, they're basically saying, "This should never be done." The problem with that mindset is that there are very few patterns in programming that should NEVER be used.
What Did We Learn Today?
Look, I'm not claiming that you should never label something as a "code smell" or an "anti-pattern". I've done it. We all do it. And it's not inherently wrong. But you should be careful that you're not lazily slapping it on things that you don't like. You should always be able to quantify why a particular code sample is a "code smell" or an "anti-pattern". If you can't, then it may not be the code that stinks. It may be you.
[AUTHOR'S FOLLOW-UP: Just today I found this excellent article from several years ago. It really hits to the same points I'm trying to illustrate in this article, and I highly recommend it: https://www.cambiaresearch.com/articles/995518/six-reasons-to-ditch-the-term-code-smell]
Top comments (10)
The proliferation of "code smell" or "anti-pattern" has a lot to do with the code quality tools in wide use, for the last 10-15 years - you know, those scanners coded with simplistic rules that would happily slap a Code Smell on every function 1 line over some arbitrarily set limit.
This is a great point. Although I feel personally feel that "code smell" and "anti-pattern" are usually deployed via non-algorithmic means (meaning: by people slapping their opinions on things), I will also confirm that code scanners bear some small bit of "guilt" in this. "Code smell" is an inherently unquantifiable term. So any time we try to attach quantifiable rules to it, it becomes an even more egregious phrase.
Speaking as someone who has written an article that had the phrase anti-pattern in the title, I would consider an anti-pattern as a practice that works initially at a small scale but doesn't scale and has no transition out of into a better pattern. For example, my article was about visual file trees and how there seems to be a low skill ceiling and alternatives that have a higher skill ceiling.
Meanwhile I believe in composition over inheritance, but inheritance is not an anti-pattern as there are some cases where it is the best tool for the job.
GOTO is another classic example of an anti-pattern. It seems to make sense in small cases where you can keep everything in your head, but as soon as you start scaling you are going to be up a creek without a paddle.
I don't think I'd disagree with any of that. The "problem" (IMHO) is that farrrrr too often, people just throw around the (lazy) term "code smell" or "anti-pattern" - without explaining what makes them "code smells" or "anti-patterns".
For example, with the GOTO thing, you could just say, dismissively, "oh... well that's an anti-pattern". Or... you could say, "that approach doesn't scale". Heck, it barely takes any more effort (syllables) to say "it doesn't scale" versus saying, "it's an anti-pattern". But it just "feels" to me like too many of our colleagues lean on the "anti-pattern" label as a way to shut down discussion.
The inheritance example is also excellent. Nearly everyone with sufficient experience has been leaning away from inheritance now for years. But "code smell" or "anti-pattern" sounds very similar to "you should never use this" - and that's just wrong. There are many caveats to using it. And there's a good chance that, given your particular situation, maybe you shouldn't use it. But there is a time-and-a-place for inheritance.
This reminds me of an article I read about banning the words "just" and "easy" from technical discussions.
I would probably also not use "it doesn't scale" because I usually find "scaling" is also used as techno-mumbo-jumbo to try to shut down discussions.
But labeling everything I don't like a CODE SMELL™ or an ANTI-PATTERN™ is a BEST PRACTICE®. 🙃
Hahaha! So true!
Brilliant article Adam!! Thanks for sharing
But what does it smell like?
Peanut butter. And feet.