Chapter 1. Clean Code

When Martin Fowler defined refactoring in his book Refactoring: Improving the Design of Existing Code, he showed the strengths and benefits as well as the reasons behind refactoring. Fortunately, after more than two decades, most developers know the meaning of refactoring and code smells. Developers deal with tech debt on a daily basis and refactoring has become a core part of software development. In his foundational book, Fowler used refactorings to address code smells. This book walks through some of these in the form of semantic recipes to improve your solutions.

1.1 What Is a Code Smell?

A code smell is a symptom of a problem. People tend to think the presence of code smells is proof that the whole entity needs to be taken apart and rebuilt. This is not the spirit of the original definition. Code smells are simply indicators of improvement opportunities. A code smell doesn’t necessarily tell you what is wrong; it is telling you to pay special attention.

This book’s recipes provide some solutions to those symptoms. Like with any cookbook, recipes are optional and code smells are guidelines and heuristics, not rigid rules. Before applying any recipe blindly, you should understand the problems and evaluate the cost and benefits of your own design and code. Good design involves balancing guidelines with practical and contextual considerations. 

1.2 What Is Refactoring?

Going back to Martin Fowler’s book, he gives two complementary definitions:

Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.

Refactoring (verb): to restructure software by applying a series of refactorings without changing its observable behavior.

Refactorings were invented by William Opdyke in his 1992 PhD thesis, “Refactoring Object-Oriented Frameworks”, and became popular after Fowler’s book. They have evolved since Fowler’s definition. Most modern IDEs support automatic refactorings. These are safe and make structural changes without changing the behavior of the system. This book has many recipes with automatic, safe refactorings and in addition also includes semantic refactors. Semantic refactors are not safe since they might change part of the behavior of the system. You should apply the recipes with semantic refactors carefully since they can break your software. I will indicate whether a recipe has semantic refactoring in the applicable recipes. If you have good behavioral code coverage, you can be confident you won’t break important business scenarios. You should not apply refactoring recipes at the same time you correct a defect or develop a new feature.

Most modern organizations have strong test coverage suites in their continuous integration/continuous delivery pipelines. See Software Engineering at Google by Titus Winters et al. (O’Reilly 2020) to find out if you have these test coverage suites.

1.3 What Is a Recipe?

I use the term recipe lightly. A recipe is a set of instructions to create or change something. The recipes in this book work best if you understand the spirit of the recipe so you can apply it with your own flavors. Other recipe books in this series are more concrete with step-by-step solutions. To utilize the recipes in this book, you will need to translate them into your programming language and design solution. The recipe is a vehicle for teaching you how to understand a problem, identify the consequences, and improve your code.

1.4 Why Clean Code?

Clean code is easy to read, understand, and maintain. It is well-structured, concise, and uses meaningful names for variables, functions, and classes. It also follows best practices and design patterns and favors readability and behavior over performance and implementation details.

Clean code is very important in all evolving systems where you make changes daily. It remains particularly relevant in certain environments where it is not possible to implement updates as quickly as desired. This includes embedded systems, space probes, smart contracts, mobile apps, and many other applications.

Classical refactoring books, websites, and IDEs focus on refactors that don’t change the system’s behavior. This book has some recipes for scenarios like this, like safe renames. But you will also find several recipes related to semantic refactors where you change the way you solve some problems. You will need to understand the code, the problems, and the recipe to make appropriate changes.

1.5 Readability, Performance, or Both

This book is about clean code. Some of its recipes are not the most performant ones. I choose readability over performance when in conflict. For example, I have dedicated a whole chapter (Chapter 16) to premature optimization to address performance problems without enough evidence.

For performance mission-critical solutions the best strategy is to write clean code, cover it with tests, and then improve the bottlenecks using Pareto rules. The Pareto principle applied to software states that by tackling 20% of critical bottlenecks you will improve your software performance by 80%. If you improve 20% of the bad performance, it will likely increase system speed by 80%.

This method discourages you from making premature optimization changes lacking evidence-based scenarios because that will result in little improvement and will damage clean code.

1.6 Software Types

Most of the recipes in this book are targeted at backend systems with complex business rules. The simulator you are going to build starting in Chapter 2 is perfect for it. Since recipes are domain agnostic, you can also use most of them for frontend development, databases, embedded systems, blockchains, and many other scenarios. There are also specific recipes with code samples for UX, frontend, smart contracts, and other specific domains (see Recipe 22.7, “Hiding Low-Level Errors from End Users”, for example).

1.7 Machine-Generated Code

Do you need clean code now that there are a lot of available tools for computer-generated code? The answer in 2023 is: yes. More than ever. There are a lot of commercial software coding assistants. However, they don’t (yet) have full control; they are the copilots and helpers, and humans are still the ones making design decisions.

At the time of writing this book, most commercial and artificial intelligence tools write anemic solutions and standard algorithms. But they are amazingly helpful when you don’t remember how to make a small function and they are handy to translate between programming languages. I’ve heavily used them while writing this book. I haven’t mastered the 25+ languages I’ve used in the recipes. I’ve translated and tested several code snippets in different languages with many assistant tools. I invite you also to use all the available tools to translate some of this book’s recipes into your favorite language. Tools are here to stay, and future developers will be technological centaurs: half human, half machine.

1.8 Naming Considerations Throughout the Book

Throughout the book, I use the following terms interchangeably:

  • Methods/functions/procedures

  • Attributes/instance variables/properties

  • Protocol/behavior/interface

  • Arguments/collaborators/parameters

  • Anonymous functions/closures/lambdas

The differences among them are subtle and sometimes language dependent. I add a note when it is needed to clarify usage.

1.9 Design Patterns

This book assumes that the reader has a basic understanding of object-oriented design concepts. Some of the recipes in this book are based on popular design patterns, including those described in the “Gang of Four” Design Patterns book. Other recipes feature lesser-known patterns such as null object and method object. Additionally, this book includes explanations and guidance on how to replace patterns that are now considered antipatterns, such as the singleton pattern in Recipe 17.2, “Replacing Singletons”.

1.10 Programming Language Paradigms

According to David Farley:

Our industry’s obsession with languages and tools has been damaging to our profession. This doesn’t mean that there are no advances to be had in language design, but most work in language design seems to concentrate on the wrong kinds of things, such as syntactic advances rather than structural advances.

The clean code concepts presented in this book can be applied to a variety of programming paradigms. Many of these ideas have roots in structured programming and functional programming, while others come from the object-oriented world. These concepts can help you write more elegant and efficient code in any paradigm.

I will use most of the recipes in object-oriented languages and build a simulator (named MAPPER) using objects as metaphors for real-world entities. I reference MAPPER frequently throughout the book. Many recipes will lead you to think of behavioral and declarative code (see Chapter 6, “Declarative Code”) instead of implementation code.

1.11 Objects Versus Classes

Most of this book’s recipes talk about objects and not classes (though there’s an entire chapter about classification: see Chapter 19, “Hierarchies”). For example, Recipe 3.2 is titled “Identifying the Essence of Your Objects” instead of “Identifying the Essence of Your Class.” This book talks about using objects to map real-world objects.

The way you create these objects is accidental; you can use classification, prototyping, factories, cloning, etc. Chapter 2 discusses the importance of mapping your objects and the imperative to model things you can see in the real world. To create objects many languages use classes, which are artifacts and not obvious in the real world. You need them if you are using a classification language. But they are not the main focus of the recipes.

1.12 Changeability

Clean code is not just about ensuring that your software functions correctly, but also about making it easy to maintain and evolve. Again, according to Dave Farley’s Modern Software Engineering, you must be experts at learning and making software ready for change. This is a major challenge for the tech industry, and I hope that this book will assist you in keeping up with these developments.

Get Clean Code Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.