Applying GRASP's Information Expert (assign a responsibility to the class that has the data needed) can grow a class into a God object. How do High Cohesion and Low Coupling act as a check on that, and what do you do instead?
answer
- Expert proposes, cohesion/coupling dispose
- Expert alone → data-rich entity becomes God object
- Pure Fabrication = invented non-domain class (repository, mapper, policy)
- Domain rules stay; storage/transport/display/delivery leave
- Over-correction = anemic model + procedural services
basics
~20 sInformation Expert says 'put it where the data is', which keeps piling work onto data-rich classes. Cohesion is the veto: if the class stops having one clear purpose, move the responsibility to a new invented class — GRASP calls that Pure Fabrication.
solid answer
~50 sInformation Expert is prescriptive: give a responsibility to whoever holds the information needed to fulfil it. Applied mechanically it concentrates behavior on the most data-rich classes — the persistent entity ends up doing business rules, SQL, serialization and email. High Cohesion and Low Coupling are the *evaluative* counterweight: after Expert proposes a home, you ask whether the receiving class still has one describable purpose and whether the assignment drags in a foreign dependency (a database driver, an SMTP client). If either answer is bad, you override Expert with **Pure Fabrication** — an invented class with no domain counterpart, such as a repository, mapper, or policy object — which keeps the entity cohesive and confines the technical dependency. Related outs are **Indirection** (an intermediary breaks a direct dependency) and **Protected Variations** (a stable interface at a predicted change point). The trap on the other side is going too far and producing an anemic domain model where entities are data bags and all logic lives in procedural services.
go deeper
Say that putting logic where the data lives is the default, but a class must not end up doing everything; unrelated jobs like saving to a database belong in their own class.
Name Pure Fabrication explicitly as the GRASP answer, and give the repository/mapper example plus the reasons-to-change argument.
Present it as a dialogue — Expert proposes, cohesion and coupling dispose — cover the encapsulation cost of fabrications and the anemic-model failure on the other side.
Generalize to layering and module boundaries: which concerns are allowed to touch the domain, how dependency inversion keeps fabrications from leaking infrastructure inward, and how ownership and change frequency justify each seam.
## The two principles in tension **Information Expert** (prescriptive): assign a responsibility to the class that has the information required to fulfil it. Rationale — it keeps behavior next to data, avoids exposing internals through getters, and therefore *reduces coupling* and supports encapsulation. It is the default first choice in GRASP. **High Cohesion** and **Low Coupling** (evaluative): once Expert proposes a home, you grade the proposal. Does the class remain focused? Does the assignment create an expensive dependency? ## Why Expert alone drifts toward a God object The most data-rich class in a domain — `Order`, `User`, `Policy` — is by construction the Expert for a huge number of questions. Follow Expert without a check and you get: - `Order.calculateTotal()` — legitimate, business logic over its own line items. - `Order.save()` — Order knows its own fields, so it "has the information"… and now the domain class depends on the database, transactions, and connection handling. - `Order.toJson()`, `Order.renderPdf()`, `Order.emailConfirmation()` — each individually defensible by the same argument. The class now has four unrelated reasons to change (pricing rules, schema, wire format, marketing copy), four sets of technical dependencies, and cannot be unit-tested without infrastructure. That is exactly what High Cohesion is there to prevent. ## The resolution: Pure Fabrication **Pure Fabrication** is the GRASP principle for exactly this situation: invent a class that does *not* represent a concept from the problem domain, purely to achieve high cohesion, low coupling and reuse. Canonical examples: `OrderRepository` (persistence), `OrderJsonMapper` (serialization), `PricingPolicy` (a rule that spans several entities), `PaymentGateway` (an external system adapter). The entity stays a cohesive domain concept; the technical concern is isolated in a class whose single purpose *is* that concern. Note the cost you accept: the fabricated class needs access to the entity's data, which can pull data out through getters and weaken encapsulation — a real trade-off, usually mitigated by keeping the fabrication in the same module, using package-private/internal visibility, or having the entity expose a purpose-built snapshot instead of raw getters. ## Deciding which concerns leave the entity A useful sorting rule: **behavior that is a rule about the domain concept stays; behavior about how the concept is stored, transported, displayed, or delivered leaves.** Ask *who requests a change to this behavior*. Pricing rules change because the business changes; the storage format changes because engineering changes; the PDF layout changes because marketing changes. Different requesters → different classes. That is SRP's actor-based formulation used as the tie-breaker for Expert. ## Additional GRASP tools around the same seam - **Indirection** — insert an intermediary so two classes need not know each other; how the fabrication also lowers coupling rather than merely moving it. - **Protected Variations** — wrap a predicted point of variation (a payment provider, a tax jurisdiction) in a stable interface so change is absorbed at that seam. - **Polymorphism** — when a responsibility varies by type, distribute it across subtypes instead of branching inside one Expert. - **Controller** — the entry point that receives a system operation and delegates; it must stay thin, or it becomes the God object instead of the entity. ## The opposite failure: the anemic domain model Over-applying "push everything out of the entity" yields entities that are pure data bags with getters and setters, and a layer of procedural `*Service` classes manipulating them from outside. That model looks OO but is procedural: behavior is far from data, invariants can be violated by anyone, and services grow their own low-cohesion problem. Information Expert exists precisely to prevent this. So the correct stance is a *dialogue*: Expert proposes, cohesion/coupling dispose, and the seam sits between domain rules (stay) and technical concerns (leave). ## Worked micro-example `Order` holds line items. Should `Order` compute the total? Expert says yes (it owns the data), cohesion agrees (pricing is what an order is about), coupling agrees (no new dependency). Keep it. Should `Order` persist itself? Expert superficially says yes; cohesion says no (persistence is a second reason to change) and coupling says no (a driver dependency in the domain layer). Create `OrderRepository` — Pure Fabrication. Should `Order` decide whether a customer is eligible for a discount that depends on the customer's history *and* current promotions? Neither class owns all the data, so Expert has no clean answer — create a `DiscountPolicy` fabrication that collaborates with both, keeping each entity cohesive.
- Doesn't a Pure Fabrication just move the low cohesion somewhere else?Not if the fabrication is named after a single concern. A repository does storage only, a mapper does translation only — each passes the one-sentence test. It becomes a problem when the fabrication is named `OrderService` and absorbs everything the entity refused, recreating the God object one layer over.
- When does a responsibility involving two entities' data belong to neither of them?When no single class holds all the information — for example a discount depending on customer history and current promotions. Assigning it to either entity forces it to reach into the other, hurting both cohesion and coupling, so a policy or domain-service fabrication that collaborates with both is the cleaner home.
- How do you avoid producing an anemic domain model when you push concerns out?Only push out concerns whose reason to change is technical or presentational. Rules about the concept's own invariants and computations must stay with the data; if your entities end up with nothing but getters and setters, you have moved domain logic out and should pull it back.
A hospital's patient file has all the information, so by 'the data is here' logic the file should also do the billing, the scheduling and the printing. In reality the file stays a medical record and separate departments — billing, records, print shop — each do one job while consulting it.
saying these in an interview costs you the question
- Treating Information Expert as an absolute rule with no evaluative check
- Claiming a class should persist itself because 'it has the data'
- Naming the extracted class `XService` and dumping every leftover concern into it
- Pushing all behavior out of entities and calling the resulting data bags 'clean architecture'
- Confusing Pure Fabrication with 'any helper class' — a fabrication must itself be single-purpose