Friday, July 17, 2009

Refactoring @ Scale

In my previous post, Refactoring for Agility, I posted an outline and some thoughts for Part I of an Overview on Refactoring. Now I'm ready to post on Part II which is about refactoring @ scale. By "at scale" I mean in the larger context of other agile practices, as well as for large projects.

PART II - REFACTORING @ SCALE

1. Scaling-Up
  • To scale refactoring for larger projects, some additional techniques & issues must be added to the mix.
  • Note that this is “in addition to” (not “instead of”)
    Refactoring In-the-SmallRefactoring @ Scale
    Small, Fast & Frequent RefactoringsLarger, Periodic & Planned Restructurings
    Emergent DesignIncremental Design & Evolutionary Architecture
    Deferred RefactoringRestructuring & Technical Debt
    Code SmellsArchitecture Smells
    Design Principles & PatternsSoftware Modifiability Tactics
    Simple/Clean CodeSupple/Domain-Driven Design

2. Emergent Design
  • Emergent Design is a fancy name for the resulting design that “emerges” from the synergy of combining Refactoring together with TDD, Continuous Integration and Automated Testing.
  • Emergent Design means that ...
3. Technical Debt [a.k.a. Design Debt]
4. Restructuring Technical Debt
  • If we accrue a non-trivial amount of technical debt, we can’t simply “refactor” it away.
  • Paying it off typically requires restructuring efforts (or even reengineering) that must be planned.
  • Iteration plans must accommodate specific tasks for these restructuring efforts (or even be dedicated to restructuring).
  • Ignoring it, or deferring it for very long is not a viable option!
5. Overview of Restructuring
  • Identifies higher-level issues (“architecture smells”) that typically represent violations of known principles of good software architecture & design.
  • Periodically applies larger-scale “refactorings” and/or many small refactorings that were previously deferred.
  • The goal is to “pay down technical debt” in order to limit the increasing costs of accumulated complexity.
  • Typically requires a concerted effort that must be separately planned.
  • Uses not only design patterns/principles, but also architectural patterns/principles, as well as software modifiability tactics.
6. Refactoring vs. Restructuring
7. Restructure Periodically
  • Restructuring is often associated with absent or neglectful refactoring and/or design.
  • But … Any large software project spanning multiple teams eventually needs restructuring.
    • Even in the presence expert-level architecture, design & continuous refactoring
    • This is just a reality of software evolution/entropy
  • Therefore … Large software projects should assume that periodic restructuring will be necessary, and should plan accordingly to:
    • Clean-up accumulated code-smells and apply numerous refactorings that were deferred but are now sorely needed,
    • Address architecture smells by applying restructurings, patterns and modifiability tactics that have broader impact.
8. Architecture Smells
See Stefan Roock's and Martin Lippert's book Refactoring in Large Software Projects (There was an earlier version of their work entitled Large Refactorings").
  • Smells in Dependency Graphs
  • Smells in Inheritance Hierarchies
  • Smells in Packages
  • Smells in Subsystems
  • Smells in Layers
9. Software Modifiability Tactics
  • Localize Changes (increase cohesion)
  • Prevent Ripple Effects (reduce coupling)
  • Defer Binding-time (defer decision-making)
10. When to Consider/Plan Restructuring?
11. Evolutionary Architecture
  • Software Architecture concerns infrastructure elements that must exist before you can begin execution.
    • Architecture is about things that are hard to change later, it is difficult to allow an architecture to emerge.
    • For large projects, this includes high-level organization of the system into functionality/elements that will be allocated to separate teams.
  • Key techniques of Evolutionary Architecture include:
    • Deferring Irreversible Decisions to the “Last Responsible Moment” (LRM Principle)
    • Architectural “Spike”, Architecture Iteration and/or Spike Iteration
12. Incremental Design
  • Design evolves incrementally, iteration by iteration, based on current business priorities and discovered technical limitations.
  • Incremental Design …
    • Does not prohibit thinking about higher-level design.
    • Does encourage planning in detail only what will be constructed soon.
  • Focus is on “Just Enough, Just-In-Time” :
    • Specifying too much detail too soon causes more rework later.
    • But doing less now and saving the rest for later should not require significantly more work later than it would today.
  • We must do Just Enough Design Initially to attain the right balance of anticipation and adaptation.
13. Just Enough Design Initially (JEDI)
  • Initial design (before coding) is still necessary.
    • This use of “JEDI” was coined by Stephen Palmer as part of Feature-Driven Development (FDD)
  • Basic rule of thumb to tell when “JEDI” is achieved:
    • At iteration-scope, when, after one pass through the iteration backlog, modeling in small groups does not produce any new classes or associations of real significance.
    • At task/TDD scope, when we have defined enough structure & interface(s) to know specifically what code to write/test, precisely where to write it, and exactly how to invoke it.
  • Techniques of “the JEDI way” include:
    • Collaborative Domain Modeling and Color Modeling [from FDD]
    • Supple Design techniques & patterns
    • Domain-Driven Design (a.k.a. DDD -- see domaindrivendesign.org)
    • Design Blitz & other Agile Modeling techniques (see agilemodeling.com)
14. Supple Design & DDD
  • Domain-Driven Design (DDD) approaches modeling the core logic of the software by focusing on the domain.
    • The basic idea is the design should directly reflect the core business domain and domain-logic of the problem to solve
    • This helps understanding the problem as well as the implementation and increases maintainability of the software.
  • DDD uses common principles and patterns as "building blocks" to model & create a "supple design”
    • Supple: pliant, malleable, limber, yielding or changing readily.
    • The design is firm yet flexible, with structure and intent both clearly conveyed and deeply realized by the code.
  • Patterns of Supple Design include: Intention-Revealing Interfaces, Ubiquitous Language, Side-Effect-Free Functions, Assertions, Conceptual Contours, Standalone Classes, Closure of Operations, Declarative Style

15. Resources:

Resources on Emergent Design and Evolutionary Architecture Resources on Restructuring Resources on Technical Debt Resources on Modifiability Tactics Resources on Supple Design & DDD

No comments: