Harden Product Quality by Refactoring Code Smells
The Quality Loop between Code Smells, Refactoring and Design Patterns
Before we start, a PSA: You have 5 more days to to join the CTT Book Club. We’ll be reading “The Fearless Organization” to cover the topics: Apply Psychological Safety learnings with your team, learn speed reading, have fun. DM me FEARLESS if you’d like to join.
Today’s Crafting Tech Teams issue is all about Code Smells and Refactoring. 🔒 Also featuring today are excerpts from upcoming book revisions I am adding for the No-nonsense TDD Booklet (rev3). These are limited as a preview for paid subscribers and will go public (free) at later date. We’ll cover the following:
Code Smells—The Benefit of Tracking Them: Explore the five categories of code smells according to the major authoritative books and explore why it’s worth your time to understand them. Learn how to spot them and what their positive and negative impacts are if you find them in your code base.
All Code Smells map to Curative, Named Refactorings: Refactoring is like a cooking recipe. Think of it as an algorithm, like solving a Rubik’s cube corner or T. You will learn how to learn more about them, how they map to code smells and what all this has to do with design patterns.
Reviewing Sandi Metz Talks on Refactoring: Sandi Metz is one of the most experienced trains in the industry. She has spoken about SOLID, object-oriented design, and refactoring at international conferences since 2009. Along with Kevlin Henney, I consider them among the core authorities on modern refactoring and object oriented design— especially for polyglots!
🔒 Successful businesses accumulate codebases they hate: Product code bases, just like babies, aren’t born with all their problems solved and addressed to a high degree of quality. Instead, most business have to validate that their ugly, messy code is useful first, while they gradually refactor. Only when value is proven can quality be ramped up significantly. This is a very delicate balance, a razor’s edge.
🔒 Code Smells that Prevent Reliable, Automated Testing: Some code smells really stink. These prevent good software and business practices to a degree that causes you to accumulate even more of them (the smells, not the good stuff!).
Code Smells—The Benefit of Tracking Them
Code Smells coined by Martin Fowler and Kent Beck are grouped into Five Categories:
Bloaters
They make code bigger than they need to be. I would classify this as the beginner category of smells. Easy to spot, betrays immediate, unattended, low hanging fruit complexity that can trivially be resolved. Bloaters come with an easy symptom: lots of indentation and curly bracers.
Tool Abusers
Language tools are being abused in amateur ways that make the code more complex compared to using the right tool. Often these are paradigm-related: using complex if and switch branching instead of a loop or map. In some cases it highlights copy-pasta programming via inheritance or worse: macro programming.
Change Preventers
These smells make changes to a codebase hard, often due to circular dependencies and duplication. Not to be confused with couplers. Change preventers are examples of a singular concept that fails to be encapsulated and lives throughout your codebase in 6-10 places at a time.
Dispensables
The unneeded, the pointless, the speculative code and abstractions. Removing them would make the code cleaner and easier to understand. These are the easiest to detect by simple heuristics. Most modern IDEs detect them and color them gray.
Couplers
Inappropriately coupled groups of objects that cannot individually be removed and used for something else. They come as a bundle with leaky abstractions. You can easily spot them by following consecutive dot or arrow calls. Specifically, this speaks about being coupled to details of objects, not just them as an interface instance or reference.
“The reason we [software engineers] cost money is the time we spend reading code.” –Sandi Metz, RailsConf 2016
An alternative—in some ways more updated— list you can find on this link from the website Refactoring.guru. I suggest you keep a bookmark handy in your Team’s wiki and learning material.
Sandi Metz’s talk (that we’ll review below) speaks on these categories with more visual detail and charisma.
All Code Smells map to Curative [Named] Refactorings
Refactoring as a methodology is a solved problem. There are strict recipes on how to apply them and when they are appropriate. In order to master good object oriented design, you don’t have to reinvent the wheel.
This isn’t a coincidence. Beginners often think that good OO design is an exclusive consequence of planning and thinking. Thinking merely produces okay design. Great design is emergent from a continuous practice of refactoring.
Just follow the books below as an example: they were published around the 2000’s. Not much has changed since then. Your team runs into the same problems. Same code smells. Same refactoring steps cure them and produce the exact same design patterns.
In my years as a coach and trainer I found a recurring pattern: engineers love design patterns. But they don’t know how to apply them. Or when it’s appropriate. Or inappropriate. The truth is, most design patterns are a result of refactoring. No one in their right mind wakes up one morning and plans the next Amazon by claiming “Okay I need 7 flyweights, two singletons, a facade and three adapters!”
Good software design is like an aged whiskey. Carefully distilled, curated, refactored and then let to age to prove its test of time, only blended when appropriately called for.
Specifically—for you as a leader—this means that your team will only produce well-crafted, easy to change and cheap to maintain code if they have the mental space and training to continuously apply their refactoring capabilities.
All engineers can do it. Everyone. But sadly, way too many think they don’t have the time for it. They give in to pressure and treat quality which is a consequence of refactoring as optional. And that—ladies and gentleman—is how company-consuming tech debt is created. Often before the product even launches.
But there’s hope! Remember, this is a solved problem. You don’t have to solve it. Just learn, copy and apply!
“Make smaller methods, make smaller classes,
and let them know as little about each other as possible.”
–Sandi Metz, RailsConf 2014
Reviewing Sandi Metz Talks on Refactoring
Sandi is great. She was recommended to me as a trainer by Coach Bob, who runs weekly ensemble/mob training worldwide. Here are my notes from here many talks. They are worth watching, many repeat and I have tried to distil my most impactful a-ha moments. What are yours?
When you go add a functionality to a code you don’t know you look for something that looks similar to what you want and try to weasel your way through it by copy-pasting. This usually backfires 😬
The existing code has a pattern. If the pattern is good, we’ll add good things to it. If it’s bad, we’ll make a bigger mess of it very fast!
You get a task—you naturally want to do it fast and quick. But be wary of the previous two points! When in an unknown, badly factored codebase, your team, you—the developer—needs to add a preceding task: Refactor the code. Make it easy to add the new feature first.
If you’re lucky enough to have tests in your codebase—if the tests are red, scramble towards the “lowest-hanging green”. No smart or clever code. Don’t try to re-abstract it or reason about the abstraction. Just get to green fast. Then you do the thinking.
Avoid the temptation to go down a rabbit hole to eliminate duplication. The duplication speaks of potentially useful patterns in the algorithm and code. Don’t eliminate them before you’ve encountered the most complex or highest business value section of your software—the critical path.
“Duplication is far cheaper than the wrong abstraction.” –Sandi Metz, RailsConf 2014
If you have code that you don’t understand and you’re afraid to change, you can keep it forever—if you think that’s a good idea—or you can put some kind of test harness around it so you can refactor. Reshape your code to the point you can safely delete the code you don’t understand.
Small methods are simple.
A measurable reason why novices don’t like refactoring: the intermediate steps make the code temporarily more complex—before the clarity hits and you can simplify (context: the refactoring strategy was shimming using tests as a guideline without modifying the original code)
Inheritance is not evil as long as you follow a few simple rules:
Shallow, and narrow hierarchy. You want your subclasses to be leaf nodes of an object graph.
Keep reading with a 7-day free trial
Subscribe to 🔮 Crafting Tech Teams to keep reading this post and get 7 days of free access to the full post archives.