Feature Envy

Symptom

A method on class A reaches deeply into class B's data via getters, then computes something B should compute. The reader's rises because the logic's location (class A) doesn't match its subject (class B's fields); the of holding both class shapes in mind compounds across every read.

Goal

Methods live with the data they care about — B owns the logic over B's fields, in line with at the class boundary. Readers find the calculation where the data sits; B's public surface shrinks to what callers actually need, and A no longer reaches across to assemble a B-shaped answer.

Smellier version

class Order {
totalWeight() {
return this.items.reduce((s, i) => s + i.unitWeight * i.qty, 0);
}
}

Fresher version

class Item { weight() { return this.unitWeight * this.qty; } }
class Order { totalWeight() { return this.items.reduce((s, i) => s + i.weight(), 0); } }
Example source: Illustrative example written for this site, not a quotation from any source.
Pressure

Domain logic lives where it's least expected; B's internals leak through public surfaces just to support A's method, and any change to B's representation cascades to A. The of a B-side rename or refactor stretches into A's body; reviewers verifying the change inspect two classes instead of one.

Tradeoff

Moving the method may pull collaborators with it — A's other internals that the moved method referenced now travel too, or get passed in as parameters. Sometimes the move uncovers a missing third class. The team's reshapes rather than vanishes; the new home for the logic may surface coupling the old position concealed.

Relief

Encapsulation tightens, getters can shrink or disappear, and the method's name clarifies once it's on the right class. The team's drops because B-side changes now stay inside B; the team's also drops because adding a new B-derived value is one edit on B rather than a coordinated change across A and B.

Trap

Moving every method that reads another class's data — even legitimate cross-class queries — over-tightens encapsulation and forces a fan-out of moves that breaks the original design's intent. The cure adds as classes acquire methods they wouldn't have grown on their own, and the team chases the move across every collaborator.