From grimoire
Assigns responsibilities to the class with the data needed to fulfill them, following the GRASP Information Expert pattern. Useful for reducing coupling and avoiding anemic domain models.
How this skill is triggered — by the user, by Claude, or both
Slash command
/grimoire:apply-information-expertThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Assign a responsibility to the class that has the information needed to fulfill it.
Assign a responsibility to the class that has the information needed to fulfill it.
Adopted by: GRASP (Larman, 2004) — the most frequently applied of the nine GRASP patterns, and the first principle to consider when assigning any responsibility. Consistent with the OOP encapsulation principle (Bjarne Stroustrup, "The C++ Programming Language") and the "Tell, Don't Ask" design heuristic (Martin Fowler, "Refactoring"). Applied in Google's internal style guides ("avoid anemic domain models"). Impact: When behavior lives where the data is, there is no need to expose data to external callers to perform operations on it. This reduces getter/setter proliferation, lowers coupling (callers don't need to know the internal structure), and raises cohesion (the class has a reason to exist beyond holding data). Anemic domain models — where all behavior is in service classes and domain objects are pure data — are the primary cause of "behavior scattered across the codebase," a pattern Martin Fowler identifies as a maintainability antipattern. Why best: The alternative — placing behavior in a class that lacks the needed data — requires the class to retrieve data from multiple sources, creating unnecessary coupling. Information Expert is the default starting point: try assigning the responsibility to the class with the most relevant data first. Override with Low Coupling or High Cohesion only when the default assignment produces an obvious violation of those principles.
Sources: Larman, "Applying UML and Patterns" (Prentice Hall, 2004); Fowler, "Refactoring" 2nd ed. (Addison-Wesley, 2018); Stroustrup, "The C++ Programming Language" (Addison-Wesley, 2013)
Before assigning a responsibility, enumerate the data it needs. The class that owns the most of that data is the Information Expert.
Example: computing an order total requires line items, quantities, and prices. Order holds all of these → Order is the expert → Order.total() is the correct assignment.
# Bad — OrderController reaches into Order's data to compute the total
class OrderController:
def get_total(self, order):
return sum(item.price * item.quantity for item in order.line_items)
# ^ accessing order's data from outside to do order's job
# Good — Order has the data; Order computes the total
class Order:
def total(self):
return sum(item.price * item.quantity for item in self.line_items)
When the same data is accessed from multiple callers to perform the same computation, that computation belongs on the data owner.
# Bad — discount calculation duplicated across multiple callers
# In OrderController:
discount = order.membership_tier == "gold" and order.total > 100
# In InvoiceService:
discount = order.membership_tier == "gold" and order.total > 100
# In ReportGenerator:
discount = order.membership_tier == "gold" and order.total > 100
# Good — Order knows its own discount eligibility
class Order:
def eligible_for_discount(self):
return self.membership_tier == "gold" and self.total() > 100
Asking an object for its data so you can operate on it violates Information Expert. Telling an object to perform an operation respects it.
| Ask (violates) | Tell (respects) |
|---|---|
if account.get_balance() < 0: account.freeze() | account.freeze_if_overdrawn() |
tax = order.get_subtotal() * tax_rate | tax = order.calculate_tax(tax_rate) |
if user.get_role() == "admin": ... | if user.is_admin(): ... |
Information Expert is the first principle to apply, not the only one. Override it when:
# Override scenario: Order is the expert for payment processing (has amount, currency)
# BUT adding payment logic to Order couples it to PaymentGateway (external service)
# LOW COUPLING overrides INFORMATION EXPERT here → create PaymentService
class PaymentService: # Pure Fabrication — no domain concept, but cohesion/coupling justified
def charge(self, order, gateway):
return gateway.charge(order.total(), order.currency)
An anemic domain model has domain objects (Order, Customer, Product) with only getters/setters and no behavior. All behavior sits in service classes that reach into these objects.
Signs of an anemic model:
get_* and set_* methodsFix: push behavior back to the domain class that owns the data. Start with the most duplicated calculations.
Applying Information Expert to infrastructure concerns. Database access, HTTP calls, and file I/O should not live on domain classes even if those classes have the relevant data. Use the Pure Fabrication pattern for infrastructure — keep domain objects free of external dependencies.
Confusing "has the data" with "knows about the data." If Order knows about Customer and Customer knows the shipping address, Order is not the expert for address formatting — Customer is. Follow the chain to find the true owner.
Over-applying against cohesion. Putting every calculation related to User on the User class produces a 2000-line God Class. Use High Cohesion to constrain Information Expert: the expert assignment is correct until the class becomes incoherent.
npx claudepluginhub jeffreytse/grimoire --plugin grimoireGuides assigning infrastructure responsibilities (DB, email, logging) to artificial classes when domain objects would violate cohesion or coupling. Draws on GRASP Pure Fabrication principle.
Translates domain rules into code using entities, value objects, aggregates, repositories, and domain events with explicit invariants.
Provides Domain-Driven Design tactical patterns for modeling entities, value objects, domain services, repositories, aggregates, and bounded contexts in complex business domains.