The Refactoring Catalog: Core Techniques
Clean Code, SOLID & Refactoring
Chapter 8 · The Refactoring Catalog: Core Techniques
Every prior chapter identified a problem. This chapter names the concrete, mechanical moves that fix them — some of which you've already performed without the name attached. Two of the five get their strongest verification yet here; the other three are callbacks to work already done.
Extract Method: One Fix, Every Caller
print_invoice_bad. Afterward: print_invoice_bad correctly returns "Total: $90.00, Tax: $7.20"; print_receipt_bad still returns "You paid: $100.00" — the un-fixed copy, silently out of sync with the fixed one.
calculate_order_total(order), called from both print_invoice_good and print_receipt_good: applying the identical discount to the one shared function makes both correctly return $90.00 — print_invoice_good and print_receipt_good both reflect the fix, with neither one edited directly.
Extract Variable: Naming an Expression Makes It Debuggable
is_eligible_bad reports only False — no way to tell which condition failed without re-evaluating the whole expression by hand. The extracted version shows is_adult = False, is_us_resident = True, is_verified = True — immediately, unambiguously identifying age as the specific cause.
Move Method & Rename — Already Fully Verified
Move Method/Field: Chapter 5's own Feature Envy fix — moving calculate_total off InvoicePrinter and onto Order, verified reducing direct data access to zero — is Move Method, performed before this chapter named it. Rename: Chapter 2's entire verified case for descriptive naming — the distance_fee/fee comparison, the consistent-vocabulary search results — is the case for this technique specifically. Nothing new to verify; the findings already stand.
Replace Conditional with Polymorphism
'international', to calculate_shipping_bad requires rewriting the whole function, inserting a new elif among the existing branches. Adding the equivalent InternationalShipping(ShippingStrategy) class: StandardShipping, ExpressShipping, and OvernightShipping — captured via inspect.getsource() before and after — all confirmed byte-identical, True for all three.
5.0 vs 5.0. Express: 17.0 vs 17.0. Overnight: 40.0 vs 40.0. International: 55.0 vs 55.0. All four match — the refactor changed how the code is organized, not what it computes.
ShippingStrategy example, reused directly rather than reinvented.
Where This Connects
| This chapter's finding | What it connects to |
|---|---|
| One shared function fixing both callers automatically | Chapter 5's own duplicated-code finding — Extract Method is the concrete fix for exactly that smell |
| Extracted variables making a rejection's own cause immediately visible | Chapter 2's own naming findings — a named variable is documentation that stays attached to the exact value it describes |
| Replace Conditional with Polymorphism reproducing Design Patterns' own Strategy | Design Patterns Chapter 7 — the pattern was built there; this chapter shows the mechanical steps that arrive at it from tangled conditional code |
Hands-On Exercises
Add a third function, print_summary_email(order), that also needs the order total, calling this chapter's own shared calculate_order_total. Apply a different real change (a flat $2 handling fee) to the shared function and verify all three callers reflect it correctly.
Add a fourth extracted condition to this chapter's own is_eligible_good — has_valid_payment_method — and a matching check in is_eligible_bad's own compound expression. Verify a user failing only this new condition is immediately identifiable in the extracted version.
Add a second new shipping type to this chapter's own polymorphic hierarchy, EconomyShipping, alongside the existing InternationalShipping from this chapter. Verify all four now-existing classes (including InternationalShipping) stay byte-identical, and verify the new type's own cost matches a hand calculation.
Chapter 8 Quick Reference
- Extract Method, verified: a duplicated calculation left one caller un-fixed after a real change; the extracted version fixed both callers from one shared function
- Extract Variable, verified: both versions computed identically, but only the extracted one made a rejected user's exact failing condition immediately visible
- Move Method & Rename: already fully verified in Chapters 5 and 2 — no new findings needed
- Replace Conditional with Polymorphism, verified: 3 existing classes stayed byte-identical after a real extension; all 4 shipping types agreed on cost between old and new implementations
- Next chapter: Technical Debt — naming it, measuring it, and paying it down deliberately