skip to content

Applying the GRASP Information Expert principle (give a responsibility to the class holding the data it needs) sometimes produces a design with heavy dependencies. How do you use GRASP's Low Coupling principle to resolve that conflict, and what does Pure Fabrication contribute?

level: seniorimportance: must knowfreq 46%

answer

  1. Expert proposes, Low Coupling vetoes
  2. Persistence is the canonical clash
  3. Pure Fabrication = invented non-domain class
  4. Over-fabricating → anaemic domain model
  5. Protected Variations = stable interface over volatile thing

basics

~20 s

Information Expert proposes a home for a responsibility; Low Coupling checks the bill. If the expert class would have to depend on infrastructure or many collaborators, move the responsibility to a made-up helper class — a Pure Fabrication — that keeps the domain class clean.

solid answer

~50 s

Information Expert is constructive: assign a responsibility to the class that has the information to fulfil it. Low Coupling and High Cohesion are evaluative: they judge the result. The classic clash is persistence — `Sale` knows its own data, so Information Expert says `Sale.save()`; but that couples a domain class to SQL, connections, transactions, and a schema, wrecking both coupling and cohesion and blocking reuse of `Sale` outside a database context. GRASP's answer is **Pure Fabrication**: invent a class that does not come from the domain vocabulary (`SaleRepository`, `SalePersistenceGateway`) purely to hold that responsibility. The domain stays free of infrastructure, the fabricated class is highly cohesive and independently reusable, and total coupling drops. The same reasoning yields **Indirection** (an intermediary breaks a direct dependency) and **Protected Variations** (wrap an unstable element behind a stable interface). Two GRASP patterns propose; Low Coupling and High Cohesion decide.

code

pseudocode · 10 lines
pseudocode
// Information Expert, unfiltered: domain class dragged into infrastructure
class Sale {
  fun save(connection) { connection.execute("INSERT INTO sales ...") }
}

// Pure Fabrication + Protected Variations: interface owned by the domain,
// implementation lives in infrastructure; Sale knows neither
interface SaleRepository { fun save(sale: Sale) }        // stable abstraction
class SqlSaleRepository : SaleRepository { /* SQL here */ }
class Sale { /* only sales rules */ }

go deeper

for a junior

Know that a domain class should not contain database or network code, and that a separate repository/service class exists to hold it.

for a middle

Name the patterns explicitly — Information Expert proposes, Low Coupling and High Cohesion evaluate, Pure Fabrication supplies the alternative home — and work the persistence example end to end.

for a senior

Add Indirection and Protected Variations, discuss which side owns the abstraction so the dependency arrow points at stability, and name the anaemic-domain-model failure mode of over-fabrication.

for a principal

Generalise to layering and architecture: the same reasoning yields ports-and-adapters, dependency inversion at module boundaries, and an explicit cost model for indirection versus the option value of replaceability.

## The two families of GRASP principles GRASP (General Responsibility Assignment Software Patterns) splits informally into: - **Constructive** patterns that *propose* an assignment: Information Expert, Creator, Controller, Polymorphism, Pure Fabrication, Indirection, Protected Variations. - **Evaluative** principles that *judge* proposals: **Low Coupling** and **High Cohesion**. A design conversation runs: Expert/Creator suggests a home → Low Coupling and High Cohesion audit it → if the audit fails, a different pattern (usually Pure Fabrication or Indirection) supplies an alternative home. ## Restating the two principles precisely **Information Expert**: assign a responsibility to the class that has the information needed to fulfil it. Rationale — it keeps behaviour next to data, avoids exposing internals through getters, and supports encapsulation. It is the default and it is right most of the time. **Low Coupling**: prefer the assignment that produces fewer and weaker dependencies. Evaluative; a tie-breaker and a veto. ## The canonical conflict: persistence Who saves a `Sale`? - **Information Expert says `Sale` itself** — it has all the fields. - **Low Coupling objects loudly**: `Sale` would now depend on a database driver, a connection/session, a transaction manager, SQL or an ORM, and the physical schema. Every one of those is volatile *and* external. `Sale` becomes untestable without a database and unusable in a batch importer, a UI preview, or a domain unit test. - **High Cohesion also objects**: `Sale` would mix sales rules with storage mechanics — two unrelated reasons to change. ## Pure Fabrication: the release valve **Pure Fabrication** means: when no domain class is a good home, *invent* a class that is not drawn from the problem-domain vocabulary, purely to achieve better coupling and cohesion. `SaleRepository`, `TaxCalculator`, `InvoiceRenderer`, `PaymentGateway` are fabrications — a customer would not recognise them as business concepts, and that is fine. Outcomes: - The domain class stays pure and reusable. - The fabrication is highly cohesive (persistence and nothing else) and independently reusable/replaceable. - Coupling *counts* may look similar, but the coupling is **relocated to a place where it is cheap** — one boundary class touches the volatile infrastructure instead of the whole domain. **The danger** is over-fabrication: shifting so much behaviour out of domain classes that they degenerate into field bags with getters and setters, and all logic lives in `*Manager`/`*Service`/`*Helper` classes. That is the *anaemic domain model*, and it is the failure mode of using Low Coupling without High Cohesion and Information Expert as counterweights. The heuristic: fabricate for **technical/infrastructural** responsibilities and for algorithms with no natural owner; keep **business rules about a concept** on the concept. ## Two neighbouring patterns that serve the same goal - **Indirection**: assign the responsibility of mediating between two elements to an intermediate object so they need not couple directly. A `Controller`, an adapter, an event bus, or a mediator. This is literally how Pure Fabrication usually manifests. Cost: another hop of indirection, harder stack traces, more moving parts. - **Protected Variations**: identify points of predicted variation or instability and wrap them behind a **stable interface**. This is the deeper motivation behind low coupling — you do not merely want fewer dependencies, you want the remaining dependencies to point at **stable abstractions**. It is the GRASP-level statement of what OO design later called the Dependency Inversion Principle and the Open/Closed Principle. ## The decision procedure to say out loud in an interview 1. Apply **Information Expert** first — it is the default and produces good encapsulation. 2. Audit the result with **Low Coupling** and **High Cohesion**. 3. If the expert would be dragged into infrastructure, a volatile third party, or an unrelated concern, use **Pure Fabrication** / **Indirection** to relocate that responsibility. 4. Wrap the remaining unavoidable dependency behind a **stable abstraction** (Protected Variations), and let the dependency point from the volatile side to the stable side. 5. Stop. Do not fabricate a class per method, and do not abstract variations you have no evidence will occur — that is speculative generality, which costs indirection with no payoff. ## Edge cases - **The expert is stable and cheap** — e.g. `Sale.total()` reading its own line items. Then Information Expert wins outright; introducing a `TotalCalculator` here is pure ceremony. - **The responsibility spans several experts** — no single class has all the information. Then a fabrication (a domain service) is the honest answer rather than arbitrarily picking one class and having it reach into the others (which would create stamp/content coupling). - **Ownership of the abstraction matters.** Defining the repository *interface* in the domain layer and the implementation in the infrastructure layer means the arrow of dependency points inward toward the stable domain — the same trick as hexagonal/ports-and-adapters architecture.

  • If Pure Fabrication just moves the dependency somewhere else, how has total coupling improved?
    The raw edge count may barely change; what improves is *where* the coupling sits and *what it points at*. One boundary class absorbs the volatile infrastructure dependency instead of the domain model doing so, the domain becomes testable and reusable without that infrastructure, and the fabricated class is individually replaceable. Coupling relocated to a cheap, isolated, replaceable place is a real win.
  • What is the failure mode of applying Pure Fabrication too aggressively?
    The anaemic domain model: domain classes reduced to getter/setter data holders with all behaviour drained into Service/Manager/Helper fabrications. Cohesion of the domain collapses, and business rules for one concept end up scattered across several services. High Cohesion and Information Expert are the counterweights that stop this.
  • Where should the repository interface be defined so the dependency arrow points the right way?
    In the domain/inner layer, with the implementation in the infrastructure/outer layer. Then infrastructure depends on the stable domain rather than the reverse — the Dependency Inversion Principle, and the same arrangement as ports-and-adapters (hexagonal) architecture.

A surgeon has the information needed to bill the patient, but making the surgeon run billing would tie the operating theatre to insurance systems. So the hospital invents a billing office — a role no patient would call medical. Pure Fabrication is the billing office: not part of the domain story, created purely so the specialists stay uncoupled from paperwork.

saying these in an interview costs you the question

  • Applying Information Expert mechanically and putting SQL, HTTP, or file I/O on domain entities.
  • Believing Pure Fabrication is a hack or a violation of object-oriented design — it is an explicit GRASP pattern.
  • Fabricating a service for every method until the domain model is anaemic.
  • Claiming Low Coupling alone decides the design, without invoking High Cohesion as the counterweight.
  • Introducing interfaces for variations with no evidence they will ever vary (speculative generality) and calling it Protected Variations.

context