Taming the Maintenance Beast
The fix to the maintenance beast is to move toward an ideal state. Ideas like the single responsibility principle tell us that when the code has more than one responsibility, we need to break up the function. The open/closed principle says that code should be extended—not modified—over time. Instead of adding extra if statements to make code more powerful, we should use inheritance or some other method. But if you use inheritance to keep that class "clean," then you need to create the right class somewhere else—which means an if statement that will be extended when you make more classes.
The fix for this problem is the factory pattern—a single object whose purpose is to take in the type (a string or enum) and return the correct object. It's okay to extend the factory along its single responsibility of making objects. If the factory becomes too complex, other patterns, such as the builder pattern, can hide a complex set of parameters behind inheritance.
Take the classic large function that calculates values based on the parameters passed in to it. The data object replaces parameters, and the strategy pattern replaces a jumbled mess of code with a distinct, clean algorithm for each type of object. Here's how the consuming code looks:
//co is an object that exists of type company //.. taxStrategy strat = new taxStrategy(); taxAlgo algo = taxStrategy.create(co.company_type); taxDue taxAmount = algo.calculateTaxDue(co);
In this example, the strategy would "just" hand us the right algorithm; we would create multiple algorithms, but they would be very straightforward.
Martin Fowler's Refactoring: Improving the Design of Existing Code, [3] which came out exactly five years after Design Patterns, gave us tools to break up complex code. Design Patterns told us what to refactor toward. Five years after Fowler's Refactoring, Joshua Kerievsky's Refactoring to Patterns made this target explicit.
Suddenly any programmer willing to read three books could know how to write clean code.