A field on class A whose value is determined by data on class B (`customer.discountRate` set from `customer.plan.kind`) — the field belongs with the data it's derived from.
Each field belongs to the class that owns its lifecycle; cross-class reaching disappears.
Before the refactoring
class Customer {plan;discountRate;}// every customer in a given plan gets the same rate:customers.forEach(c => c.discountRate = c.plan.kind === 'gold' ? 0.15 : 0.05);
After the refactoring
class Plan {kind;discountRate;}class Customer { plan; }customer.plan.discountRate;
Every consumer of A must maintain the cross-class invariant; refactoring B's data shape breaks A in non-obvious ways; the field's true owner is invisible.
Every reader of the original class now reaches across the new class boundary — coupling drops at the field's new home but reappears at each consumer.
Class boundaries align with data ownership; mutations are local; refactoring becomes safer.
Moving fields whose presence on the original class is part of the class's identity — even when the value derives elsewhere, moving the field can break consumer expectations.