Install
openclaw skills install bookforge-enterprise-architecture-pattern-stack-selectorSelect the right enterprise application architecture patterns for every layer of your system using Fowler's PEAA decision framework. Use this skill when designing or refactoring an enterprise app and asking: which domain-logic pattern should I use (Transaction Script, Domain Model, Table Module)? Which persistence pattern fits my stack (Active Record, Data Mapper, Table Data Gateway, Row Data Gateway)? Which web-presentation pattern applies (Front Controller, Page Controller, Template View)? How do I combine these into a coherent full-stack architecture? Triggers include: 'help me choose architecture patterns', 'which Fowler pattern for my app', 'enterprise application architecture', 'PEAA pattern selection', 'layer pattern selection', 'domain logic pattern vs persistence pattern', 'refactor enterprise app to patterns', 'how to structure a Spring/Django/Rails/ASP.NET app', 'what persistence pattern should I use', 'enterprise architecture decision', 'full-stack pattern stack', 'patterns of enterprise application architecture'. This is the hub skill — it maps your subsystem context to per-layer family selector skills and produces a consolidated Pattern Stack Decision Record.
openclaw skills install bookforge-enterprise-architecture-pattern-stack-selectorUse this skill at the start of enterprise application design or major refactoring, when a team needs to select consistent patterns across the domain-logic, data-source, web-presentation, concurrency, and session-state layers of an OO enterprise application backed by a relational database.
This is a router skill: it collects your context, routes each architectural layer to the appropriate pattern family, and produces a consolidated Pattern Stack Decision Record. If you have a specific layer question (e.g., only data-source patterns), use the targeted family selector skill instead.
Prerequisite check before starting:
Scan the codebase for:
pom.xml, Gemfile, requirements.txt, package.json, *.csproj — detect stack and ORM.src/domain/ or src/models/ — are there rich entity classes with behavior, or thin data-holder classes?src/persistence/ or src/repositories/ — hand-rolled SQL vs ORM-mapped classes.src/web/ or src/controllers/ — one class per route vs a single dispatcher.schema.sql, migrations/) — how closely does the schema match the domain model?If domain-logic complexity is unclear, ask: "If I describe two business rules — are they mostly independent procedural steps, or do they interact through shared domain objects with their own behavior?" This distinguishes Transaction Script from Domain Model territory.
List which layers the user's question touches: domain logic, data source (persistence), web presentation, concurrency, session state, distribution. If the user said "full stack" or "design my enterprise app", all layers are in scope.
WHY: The hub-and-spoke routing only produces value if it's scoped correctly. Selecting data-source patterns without knowing the domain-logic pattern already chosen leads to mismatched recommendations.
Fowler's "Putting It All Together" (Ch 8) is explicit: the domain-logic choice shapes every downstream layer decision. The three candidates are:
| Pattern | When to choose |
|---|---|
| Transaction Script (procedural service per use-case) | Simple domain logic; team comfortable with procedural style; scripts don't grow complex; low rule-variation count |
| Domain Model (rich OO entity graph / DDD-style) | Complex business logic; many domain variations; team has OO modeling skill; willing to invest in O/R mapping |
| Table Module (one class per table, record-set oriented) | Moderate complexity; environment with strong record-set tooling (e.g., .NET DataSet, COM+); good middle ground for .NET stacks |
Signals pointing toward Domain Model: duplicate logic spreading across Transaction Scripts; rules that depend on object state (not just database state); complex inheritance in the domain.
If the user's question covers domain logic in detail → invoke domain-logic-pattern-selector for deeper decision analysis. If unavailable → ask: "Are your business rules mostly independent per-use-case scripts, or do they involve domain objects with shared state and behavior?"
WHY: Getting the domain-logic choice wrong is the most expensive mistake. Choosing Transaction Script when domain complexity demands Domain Model leads to exponential duplication. Choosing Domain Model prematurely for CRUD-only systems adds O/R mapping overhead with no benefit.
The data-source pattern is not an independent choice; it follows from Step 2:
If Transaction Script was chosen:
If Table Module was chosen:
If Domain Model was chosen:
If the user's question is primarily about persistence pattern selection → invoke data-source-pattern-selector for full analysis including structural mapping (inheritance, associations). If unavailable → ask: "What is the domain-logic pattern already chosen, and how closely does your class model match your database schema?"
WHY: Pairing incompatible domain-logic and data-source patterns is the most common enterprise architecture mistake. Using Data Mapper overhead on a Transaction Script system wastes complexity. Using Active Record on a complex Domain Model creates tight coupling between the domain and the schema.
Web-presentation pattern selection is relatively independent of domain-logic and data-source choices, but depends on UI complexity and tooling.
Controller pattern:
View pattern:
Recommendation for most stacks: Front Controller + Template View is the safe default (and what most modern web frameworks implement by default).
If the user's question is primarily about web-presentation → invoke web-presentation-pattern-selector for deeper analysis. If unavailable → ask about navigation complexity and whether the application is document-oriented or workflow-oriented.
WHY: Choosing Page Controller for a complex, workflow-heavy application creates duplicated pre/post-processing logic across every controller. Choosing Transform View for a team with no XSLT experience creates a skills mismatch.
First Law: Do not distribute. Run everything in a single process unless you have a hard requirement to separate processes (different security boundary, different deployment cadence, separate team ownership, hardware constraint).
If distribution is required:
For session state across requests:
If the user's question focuses on distribution or session state → invoke distribution-boundary-designer or session-state-location-selector respectively.
WHY: Premature distribution is Fowler's most-cited enterprise architecture anti-pattern. Distributing by domain object class (one process per entity type) makes every business operation a cascade of slow remote calls. The First Law exists because this mistake is pervasive and expensive.
For long business transactions that span multiple HTTP requests:
If the user's question focuses on concurrency → invoke offline-concurrency-strategy-selector.
WHY: Skipping offline concurrency design leads to lost updates — a persistent source of data corruption in enterprise applications that is hard to diagnose retrospectively.
Write a markdown artifact with:
WHY: Without a documented decision record, architectural decisions are re-litigated in every code review. The artifact creates shared vocabulary and makes the forces-and-resolution reasoning visible to the whole team.
src/, schema.sql, build files to infer stack and patterns in use.Output template:
# Pattern Stack Decision Record — [Subsystem Name]
## Stack
- Language / Framework: [e.g., Java 21 / Spring Boot 3]
- ORM / Persistence: [e.g., Hibernate 6 / JPA]
- Web Layer: [e.g., Spring MVC / Thymeleaf]
## Domain Logic Layer
- **Pattern:** [Transaction Script | Domain Model | Table Module]
- **Rationale:** [forces that drove the choice]
- **Alternatives rejected:** [why the others were ruled out]
## Data Source Layer
- **Pattern:** [Table Data Gateway | Row Data Gateway | Active Record | Data Mapper]
- **Behavioral patterns:** [Unit of Work | Identity Map | Lazy Load — as needed]
- **Rationale:** [follows from domain-logic choice + schema complexity]
## Web Presentation Layer
- **Controller:** [Page Controller | Front Controller + Application Controller]
- **View:** [Template View | Transform View | Two Step View]
- **Rationale:** [navigation complexity + team tooling]
## Concurrency Strategy
- **Pattern:** [Optimistic Offline Lock | Pessimistic Offline Lock | Coarse-Grained Lock | Implicit Lock]
- **Trigger:** [when this applies]
## Session State
- **Strategy:** [Client | Server | Database Session State]
- **Scalability implication:** [stateless vs server-affinity vs DB load]
## Distribution
- [Single process — preferred] OR [Remote Facade + DTO — required because: ...]
## Known Risks
- [Growth risks: when to re-evaluate the domain-logic choice]
## Next Steps
- [ ] Invoke `domain-logic-pattern-selector` for implementation depth on domain layer
- [ ] Invoke `data-source-pattern-selector` for persistence pattern detail
- [ ] Invoke `inheritance-mapping-selector` if the schema has inheritance hierarchies
1. Domain-logic choice is the central decision — make it first. Every other layer decision is shaped by whether you chose Transaction Script, Domain Model, or Table Module. Reversing this decision later is expensive. Invest time here before designing the persistence or web layers.
2. The First Law of Distributed Object Design: minimize distribution. Every process boundary is a performance tax. Run as much as possible in a single process. Introduce Remote Facade + DTO only where a hard requirement forces a boundary. Do not distribute for the sake of perceived scalability — measure first.
3. Active Record fits simple Domain Models; Data Mapper fits complex ones. Choosing Data Mapper when Active Record would suffice adds unnecessary mapping complexity. Choosing Active Record for a complex Domain Model creates tight coupling that constrains future refactoring. The tipping point is when the schema and the object model begin to diverge significantly.
4. O/R mapping tools over hand-rolled mappers. When Data Mapper is required, use an established mapping tool (Hibernate, SQLAlchemy, EF Core, TypeORM). Hand-rolling a Data Mapper is a significant engineering undertaking — only justified if the tooling is truly unavailable or inappropriate.
5. Web-presentation patterns are platform defaults — work with them. Most modern frameworks have already made the controller choice for you (Spring DispatcherServlet = Front Controller; Rails Router = Front Controller; classic ASP.NET Web Forms ≈ Page Controller). Override the default only when you have a specific reason; fighting the framework's grain is rarely worth the cost.
6. Optimistic Offline Lock is the right default for multi-request editing. Pessimistic locking is harder to implement correctly, creates hanging-lock failure modes, and adds server-affinity pressure. Default to Optimistic Offline Lock (version column) and move to Pessimistic only when you have measured high conflict rates and confirmed that late-failure is unacceptable to users.
7. Document the pattern stack and keep it visible. Architecture decisions fade from team memory. The Pattern Stack Decision Record is a living document — update it when the system grows and a layer's pattern needs to change (e.g., Transaction Scripts outgrowing into Domain Model).
Trigger: "We're building an order-management system for a B2B wholesaler. Complex pricing rules (tiered discounts, contract pricing, surcharges), multi-step order-approval workflow, 30 developers on multiple teams, Spring Boot + Hibernate stack."
Process:
@Version).Output: Pattern Stack Decision Record with Domain Model + Data Mapper (Hibernate) + Front Controller + Template View + Optimistic Offline Lock + Server Session State for workflow.
Trigger: "We're building a SaaS project-management tool. Standard CRUD with some business rules. Small team (5 engineers). Rails (or Django)."
Process:
lock_version column convention; Django provides select_for_update or F object compare-and-set.Output: Accept framework defaults (Active Record + Front Controller + Template View + Optimistic Offline Lock + Client Session State). Revisit domain-logic pattern if complexity grows.
Trigger: "We're migrating a legacy ASP.NET WebForms app to ASP.NET Core + EF Core. Complex lease-calculation logic, 15-person team, SQL Server."
Process:
[Timestamp] / rowversion) → Optimistic Offline Lock by default.Output: Domain Model (or Table Module) + Data Mapper (EF Core) + Front Controller (ASP.NET Core MVC) + Template View (Razor) + Optimistic Offline Lock + Database Session State for durable workflow.
references/pattern-stack-decision-table.md — quick-reference routing table: domain-logic pattern → data-source patterns → behavioral patterns needed.references/layer-anti-patterns.md — common mis-pairings and how to recognize them in a codebase.This skill is licensed under CC-BY-SA-4.0. Source: BookForge — Patterns of Enterprise Application Architecture by Martin Fowler, David Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, Randy Stafford.
Install related skills from ClawhHub:
clawhub install bookforge-domain-logic-pattern-selectorclawhub install bookforge-data-source-pattern-selectorclawhub install bookforge-inheritance-mapping-selectorclawhub install bookforge-object-relational-structural-mapping-guideclawhub install bookforge-web-presentation-pattern-selectorclawhub install bookforge-offline-concurrency-strategy-selectorclawhub install bookforge-session-state-location-selectorclawhub install bookforge-distribution-boundary-designerclawhub install bookforge-enterprise-base-pattern-catalogOr install the full book set from GitHub: bookforge-skills