Shotgun Surgery


Shotgun Surgery

Symptoms

  • Making a simple change requires you to change several classes.

Causes

One responsibility is split among several classes. There may be a missing class that would understand the whole responsibility (and which would get a cluster of changes). Or, this can happen through an overzealous attempt to eliminate Divergent Change.

What to Do

  • Identify the class that should own the group of changes. It may be an existing class, or you may need to Extract Class to create a new one.

  • Use Move Field and Move Method to put the functionality onto the chosen class. Once the class not chosen is simple enough, you may be able to use Inline Class to eliminate that class.

Payoff

Reduces duplication. Improves communication. Improves maintainability (as future changes will be more localized).

Contraindications

None identified.

Exercise 41 Shotgun Surgery.

In code you have access to, find examples of this problem. Some frequent candidates:

  • Configuration information.

  • Logging.

  • Persistence.

  • Sometimes it takes two calls on an object to get something common done, and this two-step process is used in several places.



Parallel Inheritance Hierarchies

Symptoms

  • You make a new subclass in one hierarchy, and find yourself required to create a related subclass in another hierarchy.

  • You find two hierarchies where the subclasses have the same prefix. (The naming reflects the requirement to coordinate hierarchies.)

This is a special case of Shotgun Surgery, discussed earlier.

Causes

The hierarchies probably grew in parallel, a class and its pair being needed at the same time. As usual, it probably wasn't bad at first, but after two or more pairs get introduced, it becomes too complicated to change one thing. (Often both classes embody different aspects of the same decision.)

What to Do

  • Use Move Field and Move Method to redistribute the features in such a way that you can eliminate one of the hierarchies.

Payoff

Reduces duplication. May improve communication. May reduce size.

Contraindications

None identified. (This smell may happen along the way from improving a particularly tangled situation.)

Exercise 42 Duplicate Observed Data.

Duplicate Observed Data splits a class in two ”one part model, the other part view. (For example, it might turn Card into CardModel and CardView.) It is often natural for the model classes to form a hierarchy (they have similar notification needs), and it's natural for the views to form a hierarchy (they all display). This sounds like a Parallel Inheritance Hierarchy. Is it a problem?

See Appendix A for solutions.



Combinatorial Explosion

This is a relative of Parallel Inheritance Hierarchies, but everything has been folded into one hierarchy.

Symptoms

  • You want to introduce a single new class, but it turns out that you have to introduce multiple classes at various points of the hierarchy.

  • You notice that each layer of the hierarchy uses a common set of words (e.g., one level adds style information, and the next adds mutability).

Causes

What should be independent decisions instead get implemented via a hierarchy.

What to Do

  • If things aren't too far gone, you may be able to Replace Inheritance with Delegation. (By keeping the same interface for the variants, you can create an example of the Decorator design pattern.)

  • If the situation has grown too complex, you're in big refactoring territory and can Tease Apart Inheritance (see Fowler's Refactoring for the details).

Payoff

Reduces duplication. Reduces size.

Contraindications

None identified.

Exercise 43 Documents.

Consider this hierarchy:

 Document
   AsciiDocument
      ZippedAsciiDocument
      RawAsciiDocument
         BriefAsciiDocument
   HtmlDocument
      RawHtmlDocument
      ZippedHtmlDocument
   MarcDocument
      BriefMarcDocument
      FullMarcDocument 
  1. What's the impact of adding a new compression type that all document types will support?

  2. Rearrange the hierarchy so it's based first on compression (or none), then brief/full, then document type. Is this an improvement?

  3. Describe a different approach, using the Decorator pattern.

See Appendix A for solutions.