Every entry across the four volumes — refactoring techniques, design patterns, code smells and architectural patterns — grouped by family.
Controlled restructuring of existing code — preserve behavior, improve design.
Problem: A method doesn’t have enough data to perform certain actions. Solution: Create a new parameter to pass the necessary data.
Problem: A method isn’t used by other classes or is used only inside its own class hierarchy. Solution: Make the method private or protected.
Problem: Your methods contain a repeating group of parameters. Solution: Replace these parameters with an object.
Problem: Multiple methods perform similar actions that are different only in their internal values, numbers or operations. Solution: Combine these methods by using a parameter that will pass the necessary special value.
Problem: You get several values from an object and then pass them as parameters to a method. Solution: Instead, try passing the whole object.
Problem: A parameter isn’t used in the body of a method. Solution: Remove the unused parameter.
Problem: The value of a field should be set only when it’s created, and not change at any time after that. Solution: So remove methods that set the field’s value.
Problem: The name of a method doesn’t explain what the method does. Solution: Rename the method.
Problem: You have a complex constructor that does something more than just setting parameter values in object fields. Solution: Create a factory method and use it to replace constructor calls.
Problem: A method returns a special value that indicates an error? Solution: Throw an exception instead.
Problem: You throw an exception in a place where a simple test would do the job? Solution: Replace the exception with a condition test.
Problem: A method is split into parts, each of which is run depending on the value of a parameter. Solution: Extract the individual parts of the method into their own methods and call them instead of the original method.
Problem: Calling a query method and passing its results as the parameters of another method, while that method could call the query directly. Solution: Instead of passing the value through a parameter, try placing a query call inside the method body.
Problem: Do you have a method that returns a value but also changes something inside an object? Solution: Split the method into two separate methods. As you would expect, one of them should return the value and the other one modifies the object.
Problem: You have a bidirectional association between classes, but one of the classes doesn’t use the other’s features. Solution: Remove the unused association.
Problem: You have a reference object that’s too small and infrequently changed to justify managing its life cycle. Solution: Turn it into a value object.
Problem: You have two classes that each need to use the features of the other, but the association between them is only unidirectional. Solution: Add the missing association to the class that needs it.
Problem: So you have many identical instances of a single class that you need to replace with a single object. Solution: Convert the identical objects to a single reference object.
Problem: Is domain data stored in classes responsible for the GUI? Solution: Then it’s a good idea to separate the data into separate classes, ensuring connection and synchronization between the domain class and the GUI.
Problem: A class contains a collection field and a simple getter and setter for working with the collection. Solution: Make the getter-returned value read-only and create methods for adding/deleting elements of the collection.
Problem: You have a public field. Solution: Make the field private and create access methods for it.
Problem: You have an array that contains various types of data. Solution: Replace the array with an object that will have separate fields for each element.
Problem: A class (or group of classes) contains a data field. The field has its own behavior and associated data. Solution: Create a new class, place the old field and its behavior in the class, and store the object of the class in the original class.
Problem: Your code uses a number that has a certain meaning to it. Solution: Replace this number with a constant that has a human-readable name explaining the meaning of the number.
Problem: You have subclasses differing only in their (constant-returning) methods. Solution: Replace the methods with fields in the parent class and delete the subclasses.
Problem: A class has a field that contains type code. The values of this type aren’t used in operator conditions and don’t affect the behavior of the program. Solution: Create a new class and use its objects instead of the type code values.
Problem: You have a coded type that affects behavior but you can’t use subclasses to get rid of it. Solution: Replace type code with a state object. If it’s necessary to replace a field value with type code, another state object is “plugged in”.
Problem: You have a coded type that directly affects program behavior (values of this field trigger various code in conditionals). Solution: Create subclasses for each value of the coded type. Then extract the relevant behaviors from the original class to these subclasses. Replace the control flow code with polymorphism.
Problem: You use direct access to private fields inside a class. Solution: Create a getter and setter for the field, and use only them for accessing the field.
Problem: You have a class hierarchy in which a subclass is practically the same as its superclass. Solution: Merge the subclass and superclass.
Problem: Multiple clients are using the same part of a class interface. Another case: part of the interface in two classes is the same. Solution: Move this identical portion to its own interface.
Problem: A class has features that are used only in certain cases. Solution: Create a subclass and use it in these cases.
Problem: You have two classes with common fields and methods. Solution: Create a shared superclass for them and move all the identical fields and methods to it.
Problem: Your subclasses implement algorithms that contain similar steps in the same order. Solution: Move the algorithm structure and identical steps to a superclass, and leave implementation of the different steps in the subclasses.
Problem: Your subclasses have constructors with code that’s mostly identical. Solution: Create a superclass constructor and move the code that’s the same in the subclasses to it. Call the superclass constructor in the subclass constructors.
Problem: Two classes have the same field. Solution: Remove the field from subclasses and move it to the superclass.
Problem: Your subclasses have methods that perform similar work. Solution: Make the methods identical and then move them to the relevant superclass.
Problem: Is a field used only in a few subclasses? Solution: Move the field to these subclasses.
Problem: Is behavior implemented in a superclass used by only one (or a few) subclasses? Solution: Move this behavior to the subclasses.
Problem: A class contains many simple methods that delegate to all methods of another class. Solution: Make the class a delegate inheritor, which makes the delegating methods unnecessary.
Problem: You have a subclass that uses only a portion of the methods of its superclass (or it’s not possible to inherit superclass data). Solution: Create a field and put a superclass object in it, delegate methods to the superclass object, and get rid of inheritance.
Problem: You have multiple conditionals that lead to the same result or action. Solution: Consolidate all these conditionals in a single expression.
Problem: Identical code can be found in all branches of a conditional. Solution: Move the code outside of the conditional.
Problem: You have a complex conditional (if-then/else or switch). Solution: Decompose the complicated parts of the conditional into separate methods: the condition, then and else.
Problem: For a portion of code to work correctly, certain conditions or values must be true. Solution: Replace these assumptions with specific assertion checks.
Problem: Since some methods return null instead of real objects, you have many checks for null in your code. Solution: Instead of null, return a null object that exhibits the default behavior.
Problem: You have a boolean variable that acts as a control flag for multiple boolean expressions. Solution: Instead of the variable, use break, continue and return.
Problem: You have a conditional that performs various actions depending on object type or properties. Solution: Create subclasses matching the branches of the conditional. In them, create a shared method and move code from the corresponding branch of the conditional to it. Then replace the conditional with the relevant method call. The result is that the proper implementation will be attained via polymorphism depending on the object class.
Problem: You have a group of nested conditionals and it’s hard to determine the normal flow of code execution. Solution: Isolate all special checks and edge cases into separate clauses and place them before the main checks. Ideally, you should have a “flat” list of conditionals, one after the other.
Problem: When one class does the work of two, awkwardness results. Solution: Instead, create a new class and place the fields and methods responsible for the relevant functionality in it.
Problem: The client gets object B from a field or method of object А. Then the client calls a method of object B. Solution: Create a new method in class A that delegates the call to object B. Now the client doesn’t know about, or depend on, class B.
Problem: A class does almost nothing and isn’t responsible for anything, and no additional responsibilities are planned for it. Solution: Move all features from the class to another one.
Problem: A utility class doesn’t contain the method that you need and you can’t add the method to the class. Solution: Add the method to a client class and pass an object of the utility class to it as an argument.
Problem: A utility class doesn’t contain some methods that you need. But you can’t add these methods to the class. Solution: Create a new class containing the methods and make it either the child or wrapper of the utility class.
Problem: A field is used more in another class than in its own class. Solution: Create a field in a new class and redirect all users of the old field to it.
Problem: A method is used more in another class than in its own class. Solution: Create a new method in the class that uses the method the most, then move code from the old method to there. Turn the code of the original method into a reference to the new method in the other class or else remove it entirely.
Problem: A class has too many methods that simply delegate to other objects. Solution: Delete these methods and force the client to call the end methods directly.
Problem: You have a code fragment that can be grouped together. Solution: Move this code to a separate new method (or function) and replace the old code with a call to the method.
Problem: You have an expression that’s hard to understand. Solution: Place the result of the expression or its parts in separate variables that are self-explanatory.
Problem: When a method body is more obvious than the method itself, use this technique. Solution: Replace calls to the method with the method’s content and delete the method itself.
Problem: You have a temporary variable that’s assigned the result of a simple expression and nothing more. Solution: Replace the references to the variable with the expression itself.
Problem: Some value is assigned to a parameter inside method’s body. Solution: Use a local variable instead of a parameter.
Problem: You have a long method in which the local variables are so intertwined that you can’t apply Extract Method. Solution: Transform the method into a separate class so that the local variables become fields of the class. Then you can split the method into several methods within the same class.
Problem: You place the result of an expression in a local variable for later use in your code. Solution: Move the entire expression to a separate method and return the result from it. Query the method instead of using a variable. Incorporate the new method in other methods, if necessary.
Problem: You have a local variable that’s used to store various intermediate values inside a method (except for cycle variables). Solution: Use different variables for different values. Each variable should be responsible for only one particular thing.
Problem: So you want to replace an existing algorithm with a new one? Solution: Replace the body of the method that implements the algorithm with a new algorithm.
Typical solutions to common problems in software design, organized by intent.
Abstract Factory is a creational design pattern that lets you produce families of related objects without specifying their concrete classes.
Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.
Factory Method is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.
Prototype is a creational design pattern that lets you copy existing objects without making your code dependent on their classes.
Singleton is a creational design pattern that lets you ensure that a class has only one instance, while providing a global access point to this instance.
Adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate.
Bridge is a structural design pattern that lets you split a large class or a set of closely related classes into two separate hierarchies—abstraction and implementation—which can be developed independently of each other.
Composite is a structural design pattern that lets you compose objects into tree structures and then work with these structures as if they were individual objects.
Decorator is a structural design pattern that lets you attach new behaviors to objects by placing these objects inside special wrapper objects that contain the behaviors.
Facade is a structural design pattern that provides a simplified interface to a library, a framework, or any other complex set of classes.
Flyweight is a structural design pattern that lets you fit more objects into the available amount of RAM by sharing common parts of state between multiple objects instead of keeping all of the data in each object.
Proxy is a structural design pattern that lets you provide a substitute or placeholder for another object. A proxy controls access to the original object, allowing you to perform something either before or after the request gets through to the original object.
Chain of Responsibility is a behavioral design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.
Command is a behavioral design pattern that turns a request into a stand-alone object that contains all information about the request. This transformation lets you pass requests as a method arguments, delay or queue a request's execution, and support undoable operations.
Iterator is a behavioral design pattern that lets you traverse elements of a collection without exposing its underlying representation (list, stack, tree, etc.).
Mediator is a behavioral design pattern that lets you reduce chaotic dependencies between objects. The pattern restricts direct communications between the objects and forces them to collaborate only via a mediator object.
Memento is a behavioral design pattern that lets you save and restore the previous state of an object without revealing the details of its implementation.
Observer is a behavioral design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they're observing.
State is a behavioral design pattern that lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.
Strategy is a behavioral design pattern that lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.
Template Method is a behavioral design pattern that defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.
Visitor is a behavioral design pattern that lets you separate algorithms from the objects on which they operate.
Indicators of deeper problems — and the refactorings that treat them.
Two classes perform identical functions but have different method names.
If a subclass uses only some of the methods and properties inherited from its parents, the hierarchy is off-kilter. The unneeded methods may simply go unused or be redefined and give off exceptions.
You have a complex switch operator or sequence of if statements.
Temporary fields get their values (and thus are needed by objects) only under certain circumstances. Outside of these circumstances, they’re empty.
A method is filled with explanatory comments.
A data class refers to a class that contains only fields and crude methods for accessing them (getters and setters). These are simply containers for data used by other classes. These classes don’t contain any additional functionality and can’t independently operate on the data that they own.
A variable, parameter, field, method or class is no longer used (usually because it’s obsolete).
Two code fragments look almost identical.
Understanding and maintaining classes always costs time and money. So if a class doesn’t do enough to earn your attention, it should be deleted.
There’s an unused class, method, field or parameter.
Sometimes different parts of the code contain identical groups of variables (such as parameters for connecting to a database). These clumps should be turned into their own classes.
A class contains many fields/methods/lines of code.
A method contains too many lines of code. Generally, any method longer than ten lines should make you start asking questions.
More than three or four parameters for a method.
Use of primitives instead of small objects for simple tasks (such as currency, ranges, special strings for phone numbers, etc.)Use of constants for coding information (such as a constant USER_ADMIN_ROLE = 1 for referring to users with administrator rights.)Use of string constants as field names for use in data arrays.
You find yourself having to change many unrelated methods when you make changes to a class. For example, when adding a new product type you have to change the methods for finding, displaying, and ordering products.
Whenever you create a subclass for a class, you find yourself needing to create a subclass for another class.
Making any modifications requires that you make many small changes to many different classes.
A method accesses the data of another object more than its own data.
One class uses the internal fields and methods of another class.
In code you see a series of calls resembling $a->b()->c()->d()
If a class performs only one action, delegating work to another class, why does it exist at all?
System-level patterns and methodologies — DDD, CQRS, TDD and Spec-Driven Development.
An approach to software development that centers the design on a rich model of the business domain, expressed in a language shared by engineers and domain experts.
Separate the model that changes state (commands) from the model that reads state (queries), so each side can be modeled, scaled and optimized independently.
A development discipline where you write a failing test before the code that makes it pass, then refactor — letting tests drive the design in short, tight cycles.
Write an explicit, authoritative specification first, then drive implementation, tests and generated code from it — keeping the spec as the single source of truth.