What does the GRASP principle "Information Expert" say about where a responsibility should live, and why?
answer
- who has the data does the work
- GRASP = responsibility assignment heuristics
- behavior next to data → low coupling
- underpins Tell-Don't-Ask
- overridden by Pure Fabrication for persistence
basics
~20 sGive a job to the object that already holds the data needed to do it. If an order knows its line items, the order should compute its own total, instead of another class pulling the items out first.
solid answer
~40 sInformation Expert is one of the GRASP principles (General Responsibility Assignment Software Patterns). It answers "which class should do X?" with: the class that has the information needed to do X. If computing an order total requires the line items and Order holds them, then Order.total() is the right home, not an external OrderTotalCalculator that reads every field out of Order first. The payoff: coupling drops, because no other class needs to know Order's internals; cohesion rises, because data and the logic over that data sit together; encapsulation survives, because Order can change how it stores items without breaking callers. It is a default, not a law. When following it would force a domain class to also know about databases, UI, or wire protocols, other GRASP principles (Pure Fabrication, Creator, Controller) deliberately override it.
code
pseudocode · 11 lines// Violates Information Expert: outsider reads other classes' innards
function totalOf(order):
sum = 0
for item in order.getItems():
sum += item.getQuantity() * item.getProduct().getPrice()
return sum
// Information Expert: each class computes what it knows
class Product: price() -> Money
class LineItem: subtotal() = quantity * product.price()
class Order: total() = sum(item.subtotal() for item in items)go deeper
State the rule and give one concrete example (order computes its own total). Mention that it avoids other classes reaching into your data.
Add the reasoning: lower coupling, higher cohesion, encapsulation preserved. Connect it to Tell-Don't-Ask and to the Feature Envy smell cured by Move Method.
Discuss partial experts and delegation chains, and be explicit about when Expert is overridden — persistence, presentation, cross-aggregate policy — naming Pure Fabrication and domain services as the escape hatches.
Frame it as a general information-ownership rule that scales from methods to modules to services: put computation where the authoritative data lives, and treat cases where you cannot as an explicit boundary/consistency decision.
## Vocabulary first - **Responsibility** — an obligation of an object. Two kinds: *doing* (compute a total, validate a booking) and *knowing* (knowing its line items, knowing its price). - **GRASP** — *General Responsibility Assignment Software Patterns*, nine reasoning heuristics popularized by Craig Larman in *Applying UML and Patterns*. Unlike Gang-of-Four design patterns, they are not code shapes; they are answers to "who should be responsible for this?" - **Information Expert** (often just "Expert") — the most basic of them: *assign a responsibility to the class that has the information necessary to fulfill it.* - **Coupling** — how much one class must know about another. **Cohesion** — how strongly one class's members belong together. Good design wants low coupling, high cohesion. ## The method, step by step 1. State the responsibility as a sentence: "compute the grand total of an order". 2. List the information needed to fulfill it: the set of line items; per item a quantity and a unit price. 3. Ask which class *already knows* that information (in a domain model, or in the code as it stands). 4. Assign the responsibility there. If the information is spread over several classes, each becomes a *partial expert* and they collaborate — each computes the part it knows and delegates the rest. ## Worked example Suppose an order holds line items; each line item knows a quantity and points at a product that knows a unit price. - `Product.price()` — the product is the expert on price. - `LineItem.subtotal()` — the line item knows quantity, and asks the product for price. - `Order.total()` — the order knows the collection of line items, so it sums their subtotals. No class reaches past its neighbour. Contrast the anti-pattern: a `TotalCalculator` that calls `order.getItems()`, then `item.getQuantity()`, then `item.getProduct().getPrice()`. That calculator is coupled to three classes' internals; any change to how an order stores items ripples into it. ## Why it works - **Encapsulation is preserved.** Behavior placed on the data owner does not require exposing that data via getters. Fewer getters means fewer callers depending on representation. - **Coupling is minimized.** The class doing the work already has the data, so it needs no new imports, no new references, no new arguments. - **Changes localize.** Switching an order's internal list to a map, or adding a discount to a line item, changes one class. - **It is the mechanism behind Tell-Don't-Ask.** "Don't ask an object for data and act on it; tell the object to act" is exactly what you get when the expert holds the behavior. - **It prevents the anemic domain model** — classes that are bags of getters and setters with all logic in "service" classes, which Martin Fowler calls an anti-pattern precisely because it discards the benefits above. ## Where it is *not* the answer Information Expert is a default that other forces override: - **Persistence.** A `Sale` knows everything about itself, so Expert naively says `sale.save()` — but that couples the domain to SQL/ORM/transactions and destroys cohesion. Use **Pure Fabrication**: invent a `SaleRepository` that exists for design reasons rather than domain reasons. - **Presentation / protocol.** Rendering or serializing is the same story. - **Cross-entity policy.** When a rule needs information from several aggregates and no single one is the natural owner, a domain service is more honest than arbitrarily electing one entity. - **Immutable value objects / DTOs** deliberately carry no behavior in some styles. ## Common failure modes - Treating "has a getter for it" as "is the expert". The expert is who *owns* the information conceptually, not who happens to expose it today. - Applying Expert so literally that domain objects grow database, HTTP, and logging concerns — Expert traded away Single Responsibility. - Forgetting that Expert also applies to *derived* information: whoever knows the inputs owns the derivation. ## The smell it kills **Feature Envy** — a method that is more interested in another class's data than its own. Feature Envy is literally the code-level symptom of an Information Expert violation, and the standard cure (Move Method) is Information Expert applied as a refactoring.
- If the order needs a currency conversion using today's FX rate, does Information Expert still put that on Order?No. Order does not know FX rates, so it is not the expert on conversion. Either pass in a rate/converter as a parameter (keeping Order the expert on which amounts to convert), or let a separate service own the conversion. Expert points at whoever holds the required information — and the FX rate is not Order's.
- Is Information Expert the same as encapsulation?They are related but distinct. Encapsulation is hiding representation behind an interface. Information Expert is a *placement rule* that makes encapsulation achievable: if behavior lives with the data, you never need to expose the data. Follow Expert and encapsulation tends to follow; ignore it and you leak getters to make outsiders work.
You don't ask the pharmacist to hand you the raw ingredients so you can mix your own prescription. The one holding the stock and the formula does the mixing and hands you the result.
saying these in an interview costs you the question
- Saying it means "every class must have all logic about its fields", ignoring that persistence and UI concerns are deliberately moved out via Pure Fabrication
- Confusing it with a Gang-of-Four structural pattern — GRASP principles are responsibility-assignment heuristics, not class diagrams to copy
- Claiming it always reduces the number of classes; it often adds partial experts that each own a slice
- Justifying an anemic model + fat service layer as 'separation of concerns' while calling it Expert-compliant
- Assuming 'the class with the getter' is the expert, rather than the conceptual owner of the information