Originally coined by Kent Beck, according to Martin Fowler “a code smell is a surface indication that usually corresponds to a deeper problem in the system”. They are patterns in code that are quick and easy to spot. Even junior developers and those learning to code can smell bad code.
“You don’t have to be a five star chef to smell that the meat has spoiled.”
From a pragmatic standpoint not all code that smells needs or can be fixed. The idea of code smells is they are patterns or anti-patterns that are easy to identify and show the code needs to be reviewed in that area when refactoring your code.
“It’s like look here for potential problems.”
Depending on who you ask or where you look there are lots of different code smells from general smells, to paradigm specific, to even language and framework specific smells. Code smells can be categorized different ways. Here they are grouped by what they do or the problems they cause. The other major form of categorization is where they are found in the code. For each smell we’ll talk about what it indicates, why that can become a problem, and how to handle it.
Change This At Your Own Peril
If you have to change something in one place in the code it has to be changed in multiple other places. These smells can lead to complications in refactoring and iterative design. Development becomes expensive when a change is made so decisions are made based on the expense of changing code.
13:20 Divergent Change
In order to make a change in a class you have to make that change in several places within that class. This tends to be a sign of poor software architecture. It is more likely to occur earlier in your career. Experience should provide better architectural design.
Extract out the parts that are changing to another class. Reduces duplication and increases organization. Maintain single responsibility for each class.
15:29 Shotgun Surgery
When changes in one area of code requires changes in multiple other areas think of refactoring. This comes about from over use of single responsibility. The responsibility is broken up into several classes.
“This is the opposite of divergent change and can result from over fixing it.”
Bring the classes together into a single class for each responsibility to provide better organization and easier maintenance. Doing so will reduce replication of functionality in the code.
17:33 Parallel Inheritance Hierarchies
Anytime you create a subclass of one class you have to make one of another you have smells in your code. It’s not a big problem with smaller hierarchies but as classes get added it becomes a nightmare.
Remember that not all smells indicate the worst code, this could be a way around something even worse. If by fixing this you make the code worse revert back to the parallel hierarchies.
Remove the duplication by combining the hierarchies. Make instances of one hierarchy refer to the other then remove the hierarchy in the referred class. This reduces the chance of redundancy and may improve organization.
Over Adherence To A Paradigm
For this we are going to talk about object-oriented abusers. Incomplete application of the paradigm and incorrect or inappropriate use of a particular paradigm can lead to these code smells.
20:00 Same Class Different Interface
“This is the bane of my existence right now in one of the projects I’m working on.”
Two or more classes that do the same thing but have different interfaces or method names should be investigated as a code smell. This is duplicating functionality within the code.
It usually happens when developers refactor not knowing what one class does or they don’t finish a refactoring. It may also result from too many cooks in the kitchen
“I like to call these bread heel classes.”
Put the interfaces into common terms between the classes. They can then share the interface. You can also make one class a subclass of the other.
22:34 Refused Bequest
When you inherit from a class but don’t use anything from the parent class you should consider refactoring your code. The child class may only use some of the methods and properties. Unnecessary methods are usually unused or redefined meaning exceptions have to be handled.
“A dog and a stool both have four legs but that’s about it.”
This comes about through overuse of inheritance to reuse code but the classes are too different. Inheritance is misused only to combine common code not because child class is an extension of the parent.
Replace the inheritance with delegation. Put the parent class object into a field then delegate the methods used from the parent. If you must inherit take the methods both are using and make them siblings under a new parent.
25:40 Cherry Picking With Temporary Fields
This occurs when objects have a lot of optional fields that are not necessary. These fields tend to only be needed under certain circumstances. Therefore most of the fields will be empty.
Most of the time you’ll find this when an algorithm has many inputs. Instead of sending a bunch of parameters they are added as fields in the class. The data in the fields is empty most of the time.
Pull out the fields into a separate class and use it when calling the algorithm. This creates better clarity and organization of your code.
Poor Relationship Boundaries
“Beej is looking forward to this one because his inner psychologist has realized that class hierarchies interact badly in the same way that people do.”
This is what happens when coupling is taken to the extreme, either by excessive or too tight coupling or the opposite which is not tight enough coupling or excessive decoupling. We didn’t name these smells but they definitely had a sense of humor in the naming.
29:32 Inappropriate Intimacy
Too much intimacy occurs when one class uses the internal fields and methods of another class. It happens when classes spend too much time together or they interface in inappropriate ways. Classes should only know what is necessary about one another.
“It’s a lack of enforcement of boundaries.”
Several solutions exist to this problem depending on the situation. The simplest is to move the parts from one class to the other. Create a relationship hierarchy or inheritance. If they are interdependent change the dependency to unidirectional.
31:18 Indecent Exposure
“Your parts are showing!”
This happens when methods or classes that should not be public are visible. Parts that do not interface with the public are shown. Doing so shows unimportant or indirectly important code. Code is not hidden or improperly hidden.
>Make private methods private and encapsulate classes. This reduces the complexity of the code and protects methods that should be private.
34:10 Feature Envy
This happens when a method uses another class more than it’s own. It accesses the other object’s data more than it’s own or relies on the other class too much.
“A lot of times it’s specific implementations of a class.”
Typically this occurs after fields are moved into a data class. Most of the time things change at the same time. When data is moved the functions on that data are moved.
Move the method to the class it uses most. If only part of the method uses it extract that part and move it. Less redundancy of code functionality and better organization.
36:13 Message Chains
Message chains are long sequences of method calls to get data. You request an object that requests another and another, etc. Multiple temporary variables is the same thing.
“It’s not just about your dependencies on other classes that make things smell it’s like if you are dependant on how two classes relate to each other.”
This means there is a dependency on navigation through the class structure. Any changes require modification of the entire chain. Watch out for intermediaries as they can hide dependencies.
Create a method in the first class to delegate to the subsequent classes. Hide the delegation from the code calling the method. It will be easier to make changes to the program. Be careful as you risk overdoing it and creating unnecessary go-between.
38:03 Middle Man
A middle man appears when a class delegates all it’s work. Either the class has only one function that is delegated or all functions are delegated. It becomes merely a wrapper for other classes.
Most often this happens when the useful work done by the class has been moved to other classes. Overuse of fixing message chains can lead to this. It is an insidious problem as it can occur gradually though. To resolve it remove the middle man.
40:32 Incomplete Class Library
This comes in several forms. You may need a method that is missing from the library or the library stops meeting the needs of the code. Other times the responsibilities of the code should be in a library.
You may be unable or unwilling to modify the library class. The author of library may have not provided or refused to add features you need so methods get tacked on to other classes.
“You can basically use a mediator type pattern to talk to the library.”
If you do not have access to the library class add a method to a class then pass an object of the library to it or create a new class with extension methods that are either child or wrapper methods for the library
Rube Goldberg STEM Toy Kits
These are different kits or board games to create a Rube Goldberg machine to perform certain tasks. They are designed to teach cause and effect to kids as they play the game. The idea is to set up the machine to ultimately cause a specific response like sending an acrobat flying through a “flaming” loop. The flames are painted plastic.
Tricks of the Trade
The root causes of code smells are pretty similar to the root causes for being ineffective and disorganized in general (having stuff in the wrong place, not having stuff in the right place, and trying to use things for purposes for which they were not intended). It can be really instructive in areas of your personal life to actually build up an interaction diagram for how you accomplish a particular task to look for dumb design patterns. This can be a rather effective way of fixing problems that you don’t even know you have, because you are used to them. As a developer, you have an outsized advantage compared to others in the way that you think about optimizing processes. Don’t forget to use that advantage for yourself in your own life outside the computer.