Install
openclaw skills install bookforge-data-source-pattern-selectorChoose the right data access pattern — Table Data Gateway, Row Data Gateway, Active Record, or Data Mapper — for a persistence layer. Use when asked "should I use Active Record or Data Mapper?", "which ORM pattern fits my app?", "when does Hibernate-style mapping make sense vs. Rails ActiveRecord?", "how do I structure my database access layer?", "data mapper or active record for my domain model?", "Row Data Gateway vs Active Record", "Table Data Gateway vs Data Mapper", "Fowler data source patterns", "persistence layer design", "ORM pattern selection", "choose ORM pattern", "database access layer architecture", "Hibernate vs Rails persistence style". Applies when designing a new persistence layer or refactoring an existing one. Routes each domain-logic pattern (Table Module, Transaction Script, Domain Model) to its natural data-source counterpart. Identifies the Active Record / Data Mapper mismatch anti-pattern (AR when schema is not isomorphic with objects; DM when AR would suffice). Maps each pattern to modern framework idioms: Rails ActiveRecord → AR pattern; Hibernate / Spring Data JPA / EF Core → DM; Django ORM → AR-leaning; SQLAlchemy Core → TDG-style; SQLAlchemy ORM → DM; Laravel Eloquent → AR. Warns against business logic creeping into Gateway classes. Produces a pattern decision record with rationale, framework notes, and migration path. If the domain-logic pattern has not yet been chosen, invoke `domain-logic-pattern-selector` first.
openclaw skills install bookforge-data-source-pattern-selectorYou are designing or refactoring the persistence layer of an enterprise application and need to choose how objects talk to the database. The four canonical options — Table Data Gateway, Row Data Gateway, Active Record, Data Mapper — differ not just in complexity but in what they assume about domain object structure and business logic placement.
This skill applies when:
If the domain-logic pattern (Table Module, Transaction Script, Domain Model) has not yet been chosen, the data-source pattern cannot be selected reliably. Invoke domain-logic-pattern-selector first, or ask the user to describe their domain-logic approach before proceeding.
Step 1 — Identify the domain-logic pattern.
WHY: The domain-logic pattern is the primary determinant of which data-source pattern fits. Fowler is explicit: Table Module pairs with Table Data Gateway; Domain Model pairs with Active Record or Data Mapper. Choosing a data-source pattern independently from domain-logic pattern creates structural mismatches that compound over time.
domain-logic-pattern-selector or ask the user to describe domain-logic approach.Step 2 — Transaction Script: choose TDG vs RDG.
WHY: Both Gateway patterns separate SQL from application logic, but they differ in their result shape. The choice is about what is more convenient for the Transaction Script to work with — a result set / record set, or a per-row object.
Step 3 — Domain Model: assess schema isomorphism.
WHY: Active Record works well only when the schema is isomorphic with domain objects — one table per class, fields map one-to-one to columns. The moment inheritance hierarchies, embedded value objects, rich collections, or divergent naming appear, Active Record mapping becomes patchwork. Isomorphism is the primary AR/DM split criterion.
Evaluate isomorphism:
Step 4 — Domain Model: assess business logic weight.
WHY: Data Mapper is justified by domain model complexity. If the domain model is simple (validations, derivations, single-record logic), Active Record carries that complexity at low cost with no extra layer. If the domain model has complex policies, multi-object calculations, or needs to be testable without a database, Data Mapper's isolation pays off.
Step 5 — Apply the routing matrix and select pattern.
WHY: Combines Steps 1–4 into a single recommendation. Mixing patterns at the primary persistence level is a known anti-pattern — it creates confusion about where persistence logic lives and where domain logic lives.
| Domain-Logic Pattern | Schema Isomorphism | Business Logic Weight | → Data-Source Pattern |
|---|---|---|---|
| Table Module | — | — | Table Data Gateway |
| Transaction Script | — | — | TDG (result-set style) or RDG (object style) |
| Domain Model | High | Low | Active Record |
| Domain Model | High | Growing / complex | Active Record → plan migration to DM |
| Domain Model | Low | Any | Data Mapper |
| Domain Model | Any | Heavy / test-isolated | Data Mapper |
Step 6 — Map to framework idiom.
WHY: Pattern selection is only useful if it connects to the team's actual tooling. Each major ORM embodies one of the four patterns; choosing the pattern misaligned with the framework requires fighting the framework's defaults.
Session and mapped classes), TypeORM (repository mode), Doctrine ORM (PHP).Step 7 — Check for anti-patterns.
WHY: Even the correct pattern recommendation fails if common misuses are not flagged upfront. These are the most frequent failure modes Fowler identifies.
Check each:
has_many :through, STI workarounds, or manual column overrides. Fix: migrate to Data Mapper.Step 8 — Produce the decision record.
WHY: Pattern selection without documented rationale gets revisited and second-guessed. A one-page decision record captures the reasoning, making future refactoring decisions faster.
Output: See Outputs section below.
Pattern Decision Record (written to a markdown file or returned inline):
# Data Source Pattern Decision Record
## Context
- Domain-logic pattern: [Table Module | Transaction Script | Domain Model]
- Schema isomorphism: [High | Medium | Low]
- Business logic weight: [Low | Moderate | Heavy]
- Language / framework: [e.g., Java / Hibernate]
## Recommended Pattern
**[Table Data Gateway | Row Data Gateway | Active Record | Data Mapper]**
## Rationale
[2-4 sentences connecting domain-logic pattern + isomorphism + logic weight to the recommendation]
## Framework Mapping
- This project uses [framework], which implements the [pattern] style natively.
- [Any idiomatic notes or configuration guidance]
## Migration Path (if applicable)
[e.g., "Currently using RDG; as business logic accumulates on row objects, refactor to AR by
moving Transaction Script logic into the gateway class, renaming to domain classes."]
## Anti-Patterns to Watch
- [AR/DM mismatch warning if applicable]
- [Business-logic-in-gateway warning if applicable]
## Related Patterns Triggered
- Unit of Work: [needed / not needed] — [reason]
- Identity Map: [needed / not needed]
- Lazy Load: [consider / not applicable]
1. Domain-logic pattern is the primary routing axis, not a preference.
The data-source pattern is constrained by domain-logic choice, not independent of it. Table Module cannot work without Table Data Gateway. Domain Model with complex logic cannot sustain Active Record cleanly. This is why domain-logic-pattern-selector must run first.
2. Schema isomorphism is the Active Record / Data Mapper split criterion. Active Record requires one-to-one correspondence between class and table structure. When domain objects diverge from the schema — through inheritance, value objects, or separate evolution — Data Mapper becomes necessary. Trying to force AR onto a non-isomorphic schema produces layered hacks.
3. The four patterns form a progression, not a menu. TDG → RDG → AR → DM is a progression of increasing capability and increasing complexity. The appropriate pattern is the simplest one that handles the domain-logic complexity. Over-engineering (premature DM) is as damaging as under-engineering (AR for complex domain).
4. Business logic in a Gateway class is a smell, not a feature. If logic accumulates in a TDG or RDG, the class is evolving into an Active Record. That evolution is fine if intentional; it is an anti-pattern if unintentional, because it violates the Gateway's contract of pure data access.
5. Data Mapper buys independent evolution, at a cost. DM lets the database schema and object model evolve independently — you can rename a table without touching domain code, or add a collection without altering the schema. The cost is the mapping layer itself: more code, more configuration, more tooling. Only justified when that independence is actually needed.
6. Framework choice reflects pattern choice — fight the framework at your peril. Rails assumes Active Record pattern. Hibernate assumes Data Mapper. Using Hibernate like Active Record (loading everything into rich entities for simple CRUD) is as problematic as using Rails AR for a rich domain with complex inheritance. Choose the framework whose default pattern matches the one this skill recommends.
7. Do not mix primary persistence patterns in the same domain. Mixing AR and DM for different domain classes creates two parallel mental models for how persistence works. Fowler is explicit: pick one primary pattern and apply it consistently. DM can call TDG internally (as a layering technique), but that is a deliberate architectural choice, not mixing.
Trigger: "We're building an online store with Rails. Products, Orders, Users — standard stuff. Should we use ActiveRecord or something like Trailblazer's Data Mapper approach?"
Process:
Output: Recommend Active Record. Use Rails ActiveRecord natively. Add a note: "When Product becomes a polymorphic hierarchy with >3 types and complex pricing rules, reassess toward Data Mapper using a separate service/repository layer."
Trigger: "We have a Java application with a complex insurance policy domain — policies, coverages, endorsements, riders, pricing rules. Legacy Oracle schema from 2003 that doesn't match how we model policies in code. Team of 20, using Spring."
Process:
@Entity with @Column mapping to isolate domain names from schema names. Repository interfaces provide finder behavior.@Service beans.Output: Recommend Data Mapper via Hibernate/JPA. Domain classes in src/domain/, repository interfaces in src/persistence/. Isolate schema column names in @Column(name="POLICY_COVG_AMT") mappings. Plan Unit of Work via JPA EntityManager + transaction boundaries.
Trigger: "We're building an internal reporting tool in C# .NET. Lots of data grids, editable tables, CRUD screens that mirror database tables. Using DataSets and DataGridViews."
Process:
Output: Confirm Table Data Gateway. Use ADO.NET DataAdapter/DataSet pattern or TableAdapter. Return DataSet from gateway methods to bind to DataGridView controls. Keep gateway classes free of business logic.
references/pattern-routing-matrix.md — Complete routing table with all branching conditionsreferences/anti-pattern-catalog.md — Detailed descriptions of each anti-pattern with detection criteria and remediation stepsreferences/framework-pattern-map.md — Extended framework mapping (20+ ORM frameworks) organized by patternreferences/migration-paths.md — Step-by-step migration guides: TDG→RDG, RDG→AR, AR→DMDownstream skills triggered by this skill's output:
unit-of-work-implementer (commit sequencing, dirty tracking)lazy-load-strategy-implementerdata-access-anti-pattern-auditorThis skill is licensed under CC-BY-SA-4.0. Source: BookForge — Patterns of Enterprise Application Architecture by Martin Fowler et al.
Install related skills from ClawhHub:
clawhub install bookforge-patterns-of-enterprise-application-architectureOr install the full book set from GitHub: bookforge-skills