Refactoring to Patterns

by Joshua Kerievsky

Themes Quick Reference

NOTE: The following themes found in "Refactoring to Patterns" are not unique to this book but rather themes common to a larger body of literature--some of which i list in a section below.

Continuous TDD is the foundation for continuous refactoring

  • note: continuous quality test coverage is the main goal (TDD is one way to achieve this)

Continuous, ETC-driven refactoring

  • i.e. continuously refactor with a goal to maintain software that is Easy To Change

Exercise your judgement--this is guidance, not specification

Don't tolerate unnecessary complexity

Often MORE code (not less) is better

  • a highly-common result of refactoring is more code--this is not bad--the goal is ETC, not less code

Introduce complexity--to simplify!

  • this is the essence of KISS being applied as a software design principle
    • KISS is not a write-time principle, it is not encouragement to always seek the simplest set of steps right now as you write code
    • KISS is a read-time principle, it is encouragement to design your code such that it is simple to understand and change

Don't hide too much--prioritize serving the client code's needs

  • i.e. encapsulation is not the goal, encapsulation choices are driven by the abstraction which is driven by the client code's needs

Separate details from policy

  • i.e. separate implementation details from domain concepts

Quality design makes implementing performance improvements EASIER

  • sub-theme: Performance issues must be measured and identified (e.g. w/ profilers)

Globals (e.g. Singleton, public-statics) are problematic--unless truly needed

My goal with this body of notes

i want to gather in one place a condensed set of themes found in the guidance from this book, "Refactoring to Patterns"

Further more, this set of notes intends to express these themes as spanning across a larger collective body of works - "the literature" (a phrase i elaborate on next)

  • this book "Refactoring to Patterns" covers a set of advanced techniques that build upon a lower-level set of refactoring techniques
  • more generally, the contents of this book largely builds upon fundamental principles which are pre-requisite knowledge
  • these lower-level refactoring techniques and fundamental principles are covered extensively in "the literature"

"the literature"

  • in these notes i use this phrase, "the literature", to refer to a well-known and widely recommended collective body of industry-recognized literary works
  • i find this phrase to be very helpful short-hand
  • I'm not the first person to use this phrase in this way--i don't take credit for it, and i'm not sure it's the type of phrase where credit would make sense to be given
    • use of this phrase is similar to the use of others such as, industry best practices, conventional wisdom, etc.
    • best practices and convention wisdom are found in the literature

the guidance in the literature is consistent throughout--of course there are variations, but largely and thematically consistent

referring to a sub-set

  • the list of books below is simply the set of books i kept near by for reference as i studied "Refactoring to Patterns"
  • in this set of notes, i am using "the literature" as short-hand reference to this list
  • by no means am i considering this list to be the entire body of industry-recognized literature, but rather it is a sub-set

a specific note on a few books among the literature

  • Fowler's "Refactoring"
    • "Refactoring to Patterns" heavily references "Refactoring"
      • and recommends keeping "Refactoring" near by for regular reference
    • there are 2 editions of Fowler's Refactoring
  • "Design Patterns" (GoF) is frequently referenced throughout this book, "Refactoring to Patterns"
  • "Domain Driven Design" (DDD Evans) is referenced a number of times in this book, "Refactoring to Patterns"

the literature

this is a list of books i studied and kept near by for frequent cross-reference while studying "Refactoring to Patterns":

  • "Refactoring" first edition by Martin Fowler
  • "Refactoring" second edition by Martin Fowler
  • "Design Patterns" by Gang of Four
  • "Domain Driven Design" (DDD) by Eric Evans
  • "Working Effectively with Legacy Code" by Michael C. Feathers
  • "Clean Architecture" by Robert Martin
  • "Test Driven Development By Example" by Kent Beck
  • "The Pragmatic Programmer" by David Thomas and Andrew Hunt
  • "Adaptive Code" by Gary McLean Hall
  • "Clean Code" by Robert Martin
  • "Code Complete" by Steve McConnell
  • "Patterns of Enterprise Application Architecture" (PEAA) by Martin Fowler
  • "Extreme Programming Explained" by Kent Beck and Cynthia Andres

also a note on the advanced nature of the content in "Refactoring to Patterns"

  • the first time i read through this book, it was helpful but quite a bit of the content was too advanced for my current level, so much of it was lost on me
  • a few years later--after spending significant time of dedicated study of all of the above listed books--i came back to "Refactoring to Patterns" for a thorough study
    • the thorough study of these books made this re-visit to "Refactoring to Patterns" massively valuable

Being Agile and Software that is Easy To Change (ETC)

As "The Pragmatic Programmer" explains, the body of recognized software design guidance can be boiled down to one thematic goal:

Software that is easy to change is the foundation of being Agile--ETC software enables adapting to changing business needs over the life of a software product.

  • regardless of methodology, Agile guidance does not include software design guidance
  • ETC is the high-level value that software design guidance aims for
  • and this value--ease of change--is the goal of software design, because adapting to change is what Agile is about
  • without ETC software, a dev shop will move at an increasingly stumbling pace as they attempt to adapt to and keep up with changing business needs
    • and eventually this stumbling pace will drop to a crawling pace requiring large-scale rewrites to get back to the stumbling pace--or resulting in terminating the project
  • with ETC software, a dev shop is setup for success as they strive to maintain a stable pace over the life of a software product
    • and this pace will be sustained in a manor that supports change, maintains quality, and costs the business less

The Themes (of this book and the literature)

The following is the same list of themes summarized in the quick reference list at the beginning.

Here, the list includes more explanation as well as specific references to content in the book such as particular refactorings by name and sometimes page number references.

Continuous TDD is the foundation for continuous refactoring

  • nearly every refactoring specifically recommends this approach
  • and many of them take the time to show some of the tests
  • this enables refactoring with confidence

note: continuous quality test coverage is the main goal (TDD is one way to achieve this)

Continuous, ETC-driven refactoring

  • i.e. continuously refactor with a goal to maintain software that is ETC
  • this is demonstrated by every refactoring in the book--a foundational point of the book

The goals of refactoring are to ...

the goals are to

  • remove duplicate code
  • simplify logic
  • communicate intention
  • increase flexibility

Whether you are ...

  • performing non-pattern-directed, low-level refactorings (e.g. method rename, etc.)
  • specifically refactoring in a direction toward or away from a pattern
  • refactoring to implement a specific pattern

... you should be aiming to achieve these goals.

Exercise your judgement--this is guidance, not specification

  • the literature contains specific steps, diagrams, and code samples
  • this all amounts to guidance, not specification
  • the goal is to improve your design, keeping in mind the goals of refactoring
  • you have to learn how to think about design and apply good judgement

Don't tolerate unnecessary complexity

  • (this goes hand-in-hand with the continuous ETC refactoring theme)
  • be vigilant of unnecessary complexity--be sensitive to it and do not tolerate it
    • (within reason--see above THEME on using your judgement)
  • p.192,193 don't wait too long to take control of growing complexity by refactoring
  • p.259 again, don't wait to long to allow complexity to grow before refactoring
  • Move Accumulation to Visitor
    • p.321,325 "when you need a Visitor, you really need one"

Often MORE code (not less) is better

  • a highly-common result of refactoring is more code--this is not bad--the goal is ETC, not less code
  • p.315-319 the Example for Move Accumulation to Collecting Parameter
    • less code is NOT guaranteed to be easier to read or ETC--well-designed code is easier to read and ETC
    • comparing the code before and after refactoring to a quality result, there may be more code or less code
  • that Example for Move Accumulation to Collecting Parameter is just one specific example
    • this is demonstrated throughout the book
    • almost all of these refactorings result in more code, not less
    • there are numerous of examples that involve removing duplication
      • but the purpose is to remove duplication--not to make the code shorter

Introduce complexity--to simplify!

  • p.31,32 patterns are themselves complex BUT, used with good judgement, patterns simplify code
    • the message of this section:
      • to the untrained eye of a dev lacking knowledge of patterns, this dev will only see the additional complexity of the pattern
      • but once you gain awareness, the benefit is plain to see
        • and you don't even need to recognize a specific pattern to see that it exhibits quality design traits
    • further notes about this message
      • the pattern far-more-than pays for its complexity by:
        • encapsulating that complexity--for client code to have a much easier time working with the code
        • bringing structure and organization to the complexity--making code easier to change
        • bringing a well-known structure into the code in the form of the well-known pattern
      • devs need to gain patterns knowledge
        • we should learn patterns so we can leverage them rather than seeing patterns as burdens of complexity and avoiding them
        • in learning to leverage patterns, we should learn how to view patterns as targets in the context of refactoring and learn how to recognize when it is appropriate to refactor to, toward, or away from them
      • on a team of devs lacking patterns knowledge
        • carefully introduce patterns paired with teaching so the team can digest the complexity and benefit from the improved design
        • foster a culture of learning by frequently engaging in discussions centered around design principles and patterns
  • you must proactively MAKE things simple--this is NOT the easiest, quickest thing
    • e.g. -- p.90 paragraph above gray box
    • e.g. -- p.315-319 refactoring to Composed Method with Collecting Parameter
    • read-time vs. write-time convenience
      • "Code Complete" gives guidance to prioritize read-time convenience over write-time convenience
      • this is the essence of KISS being applied as a software design principle
        • KISS is not a write-time principle, it is not encouragement to always seek the simplest set of steps right now as you write code
        • KISS is a read-time principle, it is encouragement to maintain your code such that it is simple to understand and change
  • p.121 CH 7 Simplification first paragraph
    • a lot more notes on this in my notes on intro to CH 7
  • Replace Conditional Logic with Strategy is one of the book's more complex refactoring sequences and pattern destination
    • and it is in the book's Simplification category
    • same is true for Replace State-Altering Conditionals with State
  • Replace Implicit Tree with Composite
    • "What's the primary motivation for such refactoring? To make the code simpler to work with and less bloated" p.180

  • Replace One/Many Distinctions with Composite
    • p.225,226
  • Move Embellishment to Decorator
    • p.152,155 the straightforward, "quickest/easiest" solution resulted in solution sprawl
      • (my quotes in "quickest/easiest" is quoting the people who always say to prefer the "quickest/easiest" solution as though that is what it means to keep it simple)
      • here, we looked at that "quickest/easiest" solution, and it was not good
  • Move Accumulation to Visitor
    • p.325 use your brain/judgement--Visitor is complex, but if used appropriately it makes code simpler

Don't hide too much--prioritize serving the client code's needs

another way of stating this theme:

  • information hiding is not the goal--neither is encapsulation--useful abstractions is the goal
    • encapsulation applies information hiding to enforce an abstraction
    • abstractions are core--encapsulation plays a supporting role
    • abstractions should be driven by client code's needs so they are useful

theme seen in:

  • Replace Constructors with creation Methods - p.65,66
  • Encapsulate Classes with Factory p.81
  • Refactor Conditional Logic to Strategy p.137,138
  • Replace Conditional Dispatcher with Command p.198
  • Extract Adapter p.259,260
    • the Liability of this refactoring is that the Adapter might hide behavior of the Adaptee that the client needs
    • it was made very clear that YOU FIX THIS by updating the Adapter to expose what the client needs
  • p.149,150 MoveEmbellishment to Decorator
  • p.324 Move Accumulation to Visitor

Separate details from policy

  • i.e. separate implementation details from domain concepts
  • Three refactoring sequences discuss and illustrate the value of this separation
    • the three refactoring sequences
      • p.184 (in Replace Implicit Tree with Composite)
        • designs a Composite structure separate from the domain object structure
      • p.108 (in Encapsulate Composite with Builder)
        • encapsulates building that separate Composite structure
      • p.322 (in Move Accumulation to Visitor)
        • transforms heterogeneous domain object structures into various XML structures
    • they all make these points about transforming the domain objects to XML:
      • don't bloat domain objects with details (e.g. XML representation)
        • aim for high cohesion and low coupling
      • the inappropriate coupling makes it harder to support multiple variations of XML representation
  • "Design Patterns" p. 333 in Visitor makes the same point not to pollute objects with unrelated behavior
  • making a couple connections
    • considering the other theme--use your judgement on how far to refactor
    • you don't have to implement Composite, Builder, Visitor
    • the refactoring sequences were applied due to the scenario's needs calling for it
    • you can stop short of refactoring to a pattern and still achieve this goal of separating details from policy
      • this book repeatedly makes the point that you want to refactor in a direction and not always all the way to a well-known pattern
        • a pattern would give a target providing a direction, and you can stop any time you find it appropriate from a cost/benefit perspective on the design

Quality design makes implementing performance improvements EASIER

  • some claim design principles are at odds with focusing on performance
  • however, the following are important to remember:
    1. there is no performance problem until it is measured, isolated, and identified
    2. a quality design helps identify root causes
    3. the quality design makes solving the cause of a performance issue easier
      • examples from the book
        • p.109-111 THEME - Performance improvements EASIER thanks to quality design
        • also p.155,156 Move Embellishment to Decorator

sub-theme: Performance issues must be measured and identified (e.g. w/ profilers)

  • there are numerous places throughout the book that repeat this point
    • for some reason it just didn't occur to me to begin collecting these until study session 15 of 21
    • but by now i must have seen this theme repeated a handful of times so far throughout these refactoring sequences
  • here are a couple places
    • p.305 suggesting Singleton to limit instantiation of Null Object instances if profiler shows it's needed
    • p.155,156 Move Embellishment to Decorator

Globals (e.g. Singleton, public-statics) are problematic--unless truly needed

  • Study Session 16
    • Inline Singleton
    • Limit Instantiation with Singleton (cautions against Singleton, but helps by pointing out a situation that calls for it too)
  • both of these Singleton related refactoring sequences discuss the problems with globals
  • the author collects guidance from Ward Cunningham, Kent Beck, Martin Fowler
    • i also added in my notes some references to "Working Effectively with Legacy Code" by Michael C. Feathers
      • this was off the top of my head--i know there are plenty other agreeing resources in the literature
  • boils down to a key issue
    • when you access behavior via public static access, you sacrifice polymorphism
    • the desire for ubiquitous leverage of polymorphism drove the creation of OO languages
      • OO languages and frameworks build in reliable mechanisms
        • (manually writing v-tables, function pointers, etc. is not needed, the language/framework/tooling handles this)
    • so if you design software with OOD, there is not much sense in ubiquitous use of public statics and Singletons
      • (and of course there can be situations where it makes sense--remember the earlier theme that this is guidance, not specification!)
Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.
egnomerator