Refactoring to Patterns by Joshua Kerievsky

August 15, 2004
Publisher: Addison-Wesley Professional
ISBN: 978-0321213358

"Refactoring to Patterns" includes:

  • A catalog of twenty-seven pattern-directed refactorings, featuring real-world code examples 
  • General information and new insights about patterns and refactoring 
  • Detailed implementation mechanics: how low-level refactorings are combined to implement high-level patterns 
  • Multiple ways to implement the same pattern—and when to use each 
  • Practical ways to get started even if you have little experience with patterns or refactoring

Notes

Fowler: Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

  • Using patterns to improve an existing design is better than using patterns early in a new design.
  • Patterns are where you want to be. Refactorings are ways to get there from somewhere else.
  • We improve designs with patterns by applying sequences of low-level design transformations, known as refactorings.
  • It's one thing to learn what a pattern is and an altogether different thing to really understand when and how to apply the pattern.
  • Extreme programming (XP) design practices help avoid both over- and under-engineering.
  • When you make your code more flexible or sophisticated than it needs to be, you over-engineer it.
  • We under-engineer when we produce poorly designed software. It may happen when we are made to work on too many projects at once.
  • The book bridges the gap between patterns and refactoring. 

Test-driven development (TDD) and continuous refactoring enable the efficient evolution of working code by turning programming into a dialogue: Ask, Respond, Refine, Repeat.

By using TDD, instead of spending lots of time thinking about a design that would work for every nuance of a system, you may want to spend seconds or minutes making a primitive piece of behavior work correctly before refactoring and evolving it to the next necessary level of sophistication.

TDD process (it's more about continuous analysis and design than it is about testing):

  • Red: Create a test that expresses what you expect your code to do. The test fails because you haven't created code to make the test pass.
  • Green: Program whatever is expedient to make the test pass.
  • Refactor: Improve the design of the code that passed the test.

Motivations to implement refactorings:

  • Reduce or remove duplication.
  • Simplify what is complicated.
  • Make code better at communicating its intention.

A refactoring is a behavior-preserving transformation. In order words (Fowler): "A refactoring is a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior". A process of refactoring involves the removal of duplication, the simplification of complex logic, and the clarification of unclear code.

Refactoring in small steps helps prevent the introduction of defects.

It's best to refactor continuously, rather than in phases. When you see code that needs improvement, improve it. To keep code clean, continuously remove duplication and simplify and clarify code.

Reasons to refactor:

  • Make it easier to add new code.
  • Improve the design of existing code (sniff for coding smells).
  • Gain a better understanding of code.
  • Make coding less annoying.

To get the best refactoring results, you will want the help of many eyes. This is one reason why XP suggests the practices of pair-programming and collective code ownership.

Design debt occurs when you don't consistently do three things:

  • Remove duplication.
  • Simplify your code.
  • Clarify your code's intent.

Evolutionary design suggests that you:

  • Drive the framework from application needs.
  • Continuously improve applications and the framework by refactoring.

Composite refactorings are high-level refactorings composed of low-level refactorings.