Encapsulate what varies
Identify the aspects of your application that vary and separate them from what stays the same.
The goal is damage control. Picture the program as a ship and changes as mines floating under the surface. A single-compartment hull sinks on the first hit. Divide the hull into sealed compartments and a hit costs you one compartment, not the voyage.
Why it exists
Every class mixes parts that are stable for the life of the program with parts that a legislature, a competitor, or a product manager can change on a whim. Leaving both in the same method means every change to the volatile part risks the stable part, and every review of the stable part has to account for logic that has nothing to do with it.
At the method level
Somewhere in an e-commerce codebase, getOrderTotal sums the line items and applies tax. The
summing part is arithmetic and will outlive us all. The tax part depends on country, state,
sometimes city, and on legislatures. Two lifetimes, one method.
At the class level
Methods accumulate. The tax rule that was one if becomes a rate table, then per-product
categories, then exemptions - each with its own helper fields and methods, all of them
blurring what the Order class is supposed to be about. When the volatile part has grown its
own gravity, give it a class.
Order class.Objects of the Order class delegate all tax-related work to an object that does just that.
Try it yourself: shipping cost is the next candidate - it depends on weight, destination,
and a carrier's changing rate card, none of which Order should know about. Sketch the class
you would extract for it, using TaxCalculator above as the template.
The cost of overapplying it
Walling off a part of a class that is not actually going to vary buys nothing but an extra
hop to read through. getTaxRate() earned its extraction because tax law genuinely changes on
its own schedule; extracting a getShippingLabelTextCalculator() for a label format that has
been stable for three years and nobody has proposed changing is indirection paid for with no
matching benefit.
How it relates to its neighbours
Separation of Concerns is this same instinct at a larger grain - Encapsulate What Varies operates inside one class, walling off a volatile part from a stable one; Separation of Concerns operates across an entire program, splitting independent questions into independent objects regardless of whether either one is "volatile." And YAGNI is the principle that decides when this page's advice applies: encapsulate the moment a real axis of variation exists, not the moment you can imagine one.
Where you'll see it in the pattern catalog
This is, almost word for word, the intent line of every creational pattern in this catalog: Factory Method encapsulates which concrete product gets created; Strategy encapsulates which algorithm runs; State encapsulates which behavior applies for the current mode. Once you can name the exact thing that varies in a design, you can usually name the pattern that encapsulates it.
Check yourself
getOrderTotal() computes a line-item sum and applies a tax rate that depends on country and legislature. What is the encapsulate-what-varies move here?