Chapter 2 of “Refactoring, Improving the Design of Existing Code” by Martin Fowler, titled “Principles of Refactoring,” continues to set the stage for the rest of the “recipe book” of refactorings by explaining some of the basics of refactoring, including:
- Why you should refactor your code
- When you should refactor your code, and
- Problems that could arise when refactoring your code
Here’s my perspective on the chapter:
Hey what’s up everybody, I’m Andy, the Clean Swifter. Welcome back to the second video episode from my blog cleanswifter.com, where I share tips, tricks, articles, and commentary on how to write cleaner Swift code. In this video, I’ll be providing some commentary on chapter two of Martin Fowler’s book, “Refactoring, Improving the design of existing code.” The second chapter is titled “Principles of Refactoring.” You can buy the book through my Amazon affiliate link in the description for this video. In this chapter, Fowler covers three important topics, first: why you should refactor your code. Second, when you should refactor your code. And third, potential problems to be aware of when refactoring your code.
Before we jump in, let’s just recap as to the definition of refactoring. Paraphrasing how Fowler puts it at the beginning of this chapter, refactoring is the process of improving code while making no observable changes in behavior. In other words, improving your code, while not changing how it behaves to the end user. You can actually use the word refactor as both a noun and a verb, for example “That refactoring really improved my design” or “let’s go refactor that method to clean it up.”
Now that we’re clear on the definition, let’s dig into the first topic, why you should refactor your code. I know to some people this may be kind of obvious, but let’s talk about it just to be clear. You should refactor your code because it helps you improve its design. By helping improve its design, it will become easier to understand, bugs will be easier to find, and you’ll ultimately be able to add functionality faster. All of these reasons relate to eachother. Messy code will have more bugs. Additionally, because it’s messy, you’ll spend more time trying to find and fix the bugs, and thus spend less time adding end user features. If code is hard to understand, you’ll be slow to enhance it, and when you do, chances are you’ll be adding bugs because you don’t know the true impact of your change. Refactoring aims to solve each of these problems.
Let’s move on to the second important topic, when you should refactor your code. Fowler sums it up simply as “the rule of three.” The first time you do something, you just do it. The second time you do something similuar, you duplicate the first time while wincing. The third time you do something similar, you refactor and remove all the duplication. Think of it as: three strikes and you refactor. I think this is a nice metaphor, but I don’t think I’d live with the first duplication. Any duplication smells to me, I’d probably refactor at that point. When else might you refactor, well any other time that you’re modifying code such as when you’re adding funcitonality, or fixing a bug. Both of those are great times when you can get in and improve the internal structure of your code, while also adding or fixing something in the meantime. Fowler goes on to advocate refactoring during code review. I’m not such a big fan of that, and I think this is another area where the book is showing its age. Today, in a world of github pull requests, code reviews are very common, and I put it on the original author to ensure that the code is in good shape prior creating a pull request for it to be merged into the main code base. In my software collaboration, I’ll usually have worked out the design ahead of time so there aren’t any surprises or really opportunity for further improvement when code review happens.
Finally, the third important topic in the chapter 2 of Fowler’s “Refactoring, Improving the design of existing code” is recognition of some problems that can occur when refactoring. One common thing I run into all the time is a constraint put onto my apps by the backend API. Fowler makes the comparison with a “database” but I’ll move the analogy into something a little more real for apps. As app developers, we need a really solid layer of abstraction between our apps and the backends that you may use, and in my case this is commonly remote web APIs. Otherwise, any refactoring you encounter is going to be constrained by that API and potentially limit what you can do. Similarly, another thing you can run into is if the code you are refactoring is part of a library consumed by others, like a cocoapod, you need to be really careful when performing refactorings that will change that public interface. Doing so will impact any consumers of your API. You need a good migration strategy for them. And another case where you simply shouldn’t refactor, is if the code starts off in a bad or buggy state. If this is your starting point, you should correct any errors first, and then once you have passing tests that cover the error cases, move on to your refactoring.
Those were my big takeaways from chapter two, “principles of refactoring.” Depending on where you are with your refactoring adoption, over time and with practice, it will soon become second nature to constantly be looking for places to improve the structure of your code while ensuring that how it behaves doesn’t change. You’ll even start to integrating refactorings into your thought process while designing your code, before you even write a single line.
Looking ahead to chapter 3, it’s title is “bad smells in code.” Fowler puts some definition around things to look for in code that should be refactored. I hope you enjoyed this video from cleanswifter.com. until next time, happy cleaning.