From grimoire
Guides assigning infrastructure responsibilities (DB, email, logging) to artificial classes when domain objects would violate cohesion or coupling. Draws on GRASP Pure Fabrication principle.
How this skill is triggered — by the user, by Claude, or both
Slash command
/grimoire:apply-pure-fabricationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
When assigning a responsibility to a domain class would violate High Cohesion or Low Coupling, create an artificial class — one with no domain counterpart — solely to achieve a good design.
When assigning a responsibility to a domain class would violate High Cohesion or Low Coupling, create an artificial class — one with no domain counterpart — solely to achieve a good design.
Adopted by: GRASP (Larman, 2004); the design justification behind Service classes in Domain-Driven Design (Evans, 2003), Repository classes, and all infrastructure-layer objects. The Repository pattern (Fowler, "Patterns of Enterprise Application Architecture", 2002) is a canonical Pure Fabrication: no business domain has a "repository" — it is an invented construct to separate persistence from domain logic.
Impact: Without Pure Fabrication, the Information Expert principle leads to domain objects absorbing infrastructure responsibilities: Order would handle its own database persistence, Customer would send its own emails, Invoice would generate its own PDFs. Domain objects become coupled to databases, email servers, and file systems — impossible to test without infrastructure setup. Pure Fabrication is the escape valve that keeps domain objects clean.
Why best: The tension in GRASP is between Information Expert (put behavior with data) and Low Coupling/High Cohesion (keep classes focused and dependency-light). Pure Fabrication resolves this tension by creating a class specifically designed to hold the infrastructure responsibility. The domain class stays clean; the Pure Fabrication absorbs the infrastructure coupling. This is intentional design, not a workaround.
Sources: Larman, "Applying UML and Patterns" (Prentice Hall, 2004); Evans, "Domain-Driven Design" (Addison-Wesley, 2003); Fowler, "Patterns of Enterprise Application Architecture" (Addison-Wesley, 2002)
The trigger for Pure Fabrication is a conflict between Information Expert (put the responsibility with the data) and High Cohesion / Low Coupling.
# Information Expert says: Order has the data for persistence → Order should persist itself
class Order:
def save(self):
db.execute("INSERT INTO orders ...", self.id, self.total, ...) # Infrastructure in domain
# Problem: Order now depends on DB driver; can't test without database
# Problem: Order is responsible for both business rules AND persistence
# Pure Fabrication resolves the conflict
class OrderRepository: # Invented class — no "repository" in business domain
def save(self, order: Order) -> None:
db.execute("INSERT INTO orders ...", order.id, order.total, ...)
A Pure Fabrication has no domain counterpart, so its name describes its technical role, not a business concept. This is one of the exceptions to apply-domain-based-naming.
Common Pure Fabrication names and their responsibilities:
| Name | Responsibility |
|---|---|
XRepository | Persistence operations for domain type X |
XService | Domain operations that span multiple types |
XFactory | Complex creation of domain objects |
XMapper / XAssembler | Translation between layers (domain ↔ DTO) |
XValidator | Validation logic separated from domain object |
XNotifier / XEmailer | Notification / messaging concerns |
XAdapter | Wrapping an external API in a domain interface |
The rule of thumb: domain objects should not import or instantiate infrastructure classes (databases, email clients, HTTP clients, file systems).
# Bad — Customer knows about email; couples domain to email infrastructure
class Customer:
def send_welcome_email(self):
smtp = smtplib.SMTP("mail.example.com") # infrastructure in domain
smtp.sendmail(...)
# Good — WelcomeEmailer is a Pure Fabrication; Customer knows nothing about email
class WelcomeEmailer:
def __init__(self, smtp_client):
self.smtp = smtp_client
def send(self, customer: Customer) -> None:
self.smtp.sendmail(
to=customer.email,
subject="Welcome!",
body=f"Hello {customer.name}..."
)
When an algorithm spans multiple domain objects but doesn't belong on any one of them, a Pure Fabrication holds it.
# Algorithm: calculate shipping cost — depends on Order, Customer, and external rate API
# Not cohesive on Order (knows too much about Customer and rates)
# Not cohesive on Customer (has nothing to do with Customer's core concerns)
class ShippingCalculator: # Pure Fabrication — no domain concept, but cohesion justified
def __init__(self, rate_api: ShippingRateAPI):
self.rate_api = rate_api
def calculate(self, order: Order, customer: Customer) -> Money:
zone = self.rate_api.get_zone(customer.shipping_address)
return self.rate_api.get_rate(zone, order.weight)
A Pure Fabrication that absorbs too many responsibilities becomes a service layer God Object — the same problem it was meant to prevent. Apply High Cohesion to Pure Fabrications as strictly as to domain objects.
# Bad — OrderService is a dumping ground
class OrderService:
def place_order(self): ...
def cancel_order(self): ...
def generate_invoice(self): ... # different concern
def send_confirmation_email(self): ... # different concern
def calculate_shipping(self): ... # different concern
# Good — each Pure Fabrication has one clear responsibility
class OrderPlacementService: ...
class InvoiceGenerator: ...
class OrderNotifier: ...
class ShippingCalculator: ...
Pure Fabrication as a wastebasket. A class named OrderUtils, OrderHelper, or OrderManager with no clear purpose is not a Pure Fabrication — it is a junk drawer. Pure Fabrications have a single, named technical responsibility.
Abusing Pure Fabrication to justify anemic domain models. If ALL behavior is in Pure Fabrications and domain objects have only getters/setters, the balance is wrong. Information Expert should be the first choice; Pure Fabrication is the override when cohesion or coupling is genuinely violated.
Confusing Pure Fabrication with Domain Service. A Domain Service (DDD terminology) handles domain logic that doesn't naturally fit on one entity. A Pure Fabrication handles infrastructure concerns. Both are invented classes, but they serve different purposes and belong in different layers.
npx claudepluginhub jeffreytse/grimoire --plugin grimoireAssigns 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.
Provides Domain-Driven Design tactical patterns for modeling entities, value objects, domain services, repositories, aggregates, and bounded contexts in complex business domains.
Translates domain rules into code using entities, value objects, aggregates, repositories, and domain events with explicit invariants.