Enterprise Base Pattern Catalog

v1.0.0

Reference catalog for Fowler's 11 enterprise base patterns from Chapter 18 of PEAA. Use when another skill or user says 'we need a Gateway here', 'this shoul...

0· 20·0 current·0 all-time
byHung Quoc To@quochungto
Security Scan
Capability signals
Crypto
These labels describe what authority the skill may exercise. They are separate from suspicious or malicious moderation verdicts.
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
Name and description match the provided SKILL.md and reference file content. The skill requests no binaries, env vars, or config paths that would be unrelated to a pattern catalog; the declared tools (Read, Grep, optional Glob) are appropriate for scanning an optionally-supplied codebase to produce language-specific sketches.
Instruction Scope
SKILL.md is a lookup-and-guidance instruction set: match a problem to one of 11 patterns, return definitions and an implementation sketch, and route to other selectors when appropriate. It explicitly accepts an optional codebase input and requests Read/Grep (and optionally Glob) to analyze provided snippets — this is coherent with producing tailored sketches, but means the skill will inspect any code you supply. It does not instruct the agent to read unrelated system files, environment variables, or post data to external endpoints.
Install Mechanism
No install spec and no code files with executable content are present; the skill is instruction-only, which is the lowest-risk install surface.
Credentials
The skill declares no required environment variables, credentials, or config paths. There are no unexpected secret requests in SKILL.md or the reference files.
Persistence & Privilege
always is false and model invocation is not disabled (the platform default). The skill does not request persistent system presence, nor does it modify other skills or system-wide settings. Autonomous invocation is allowed by default but is not combined with other privilege or credential requests.
Assessment
This skill appears coherent and low-risk: it's a read-only reference that will only inspect code you explicitly provide (via the optional codebase input) using Read/Grep. Before installing, consider: (1) the skill is marked draft — review the GitHub source if you need production-quality guarantees; (2) do not supply sensitive secrets or private files as the optional codebase unless you want them analyzed; (3) if you prefer the agent not to call this skill autonomously, restrict it to user-invocable only in your agent settings. No credentials or external installers are required.

Like a lobster shell, security has layers — review code before you run it.

Runtime requirements

📚 Clawdis
bookforgevk978r4333zsj82r306mge776x1858tp9latestvk978r4333zsj82r306mge776x1858tp9tags:vk978r4333zsj82r306mge776x1858tp9
20downloads
0stars
1versions
Updated 9h ago
v1.0.0
MIT-0

Enterprise Base Pattern Catalog

The 11 base patterns in Chapter 18 of Patterns of Enterprise Application Architecture are cross-cutting utility patterns that appear everywhere in enterprise application design. They are not architectural patterns (like Data Mapper or Front Controller) — they are the building blocks those patterns are built from. Every other PEAA skill references at least one of these.

This skill is a lookup-and-guide: identify the pattern by name or by problem description, then get the canonical definition, when to apply it, a modern language sketch, and any critical cautions.


When to Use

Use this skill when:

  • Another PEAA skill says "introduce a Gateway here" or "this is a Value Object" and you need the definition.
  • You're describing a cross-cutting utility problem: wrapping an external API, replacing null checks, making monetary arithmetic correct, isolating tests from external services, or breaking a package dependency cycle.
  • You want to name a pattern you already know exists but can't recall precisely.
  • You want the modern equivalent of a 2002-era base pattern.

NOT for: choosing among data-source patterns, domain logic patterns, web presentation patterns, concurrency patterns, or session state patterns. For those, see the dedicated selector skills in this set.


Context and Input Gathering

Accept either:

  1. A pattern name: "What is Registry?", "Explain Special Case", "When do I use Separated Interface?"
  2. A problem description: "I have floats for monetary amounts", "null checks for missing customers everywhere", "I want to swap a real tax service with a stub in tests"
  3. A cross-skill invocation: "We need a Gateway for the Stripe API — what does that look like?"

If a codebase is available, read the relevant file to produce a language-specific sketch. If not, use a stack-agnostic pseudocode sketch.

Sufficiency check: The pattern name or problem description alone is sufficient to proceed. No codebase required.


Process

Step 1 — Identify the Pattern

Match the input against the quick-lookup table. Accept either exact name or problem-description.

WHY: The 11 base patterns have overlapping surface descriptions (Gateway, Mapper, and Adapter all "wrap" something). Disambiguation prevents recommending the wrong pattern.

If a pattern name is given: look it up directly.

If a problem description is given: match against these trigger signatures:

Problem signaturePattern
"Wrap a 3rd-party / external API / resource behind a clean interface"Gateway
"Decouple two subsystems so neither knows about the other"Mapper
"Many classes in the same layer share common behavior"Layer Supertype
"Break a dependency cycle between packages / layers"Separated Interface
"Global finder / locator for widely-needed objects"Registry
"Equality should be based on value, not reference; small immutable object"Value Object
"Monetary amounts — avoid rounding errors, multi-currency, allocation"Money
"Null checks for the same condition scattered in many places"Special Case
"Swap implementation at configuration time (test vs production)"Plugin
"External service is unavailable / slow — need to test without it"Service Stub
"Generic tabular in-memory data structure for data-aware UI tools"Record Set

If multiple patterns could apply: list them with selection criteria (see Gateway vs Mapper below).

If no base pattern fits: route to the appropriate selector. Examples:

  • Data access architecture question → data-source-pattern-selector
  • Domain logic organization → domain-logic-pattern-selector
  • Web layer structure → web-presentation-pattern-selector
  • Concurrency → offline-concurrency-strategy-selector

WHY: Routing prevents this skill from giving partial answers on topics covered better by other skills in the set.


Step 2 — Deliver the Pattern Response

For the identified pattern, produce:

  1. One-sentence definition (the PEAA intent statement).
  2. Why it exists — the problem without the pattern.
  3. When to apply — specific conditions and contra-indicators.
  4. Critical cautions — the most common mis-application.
  5. Modern language parallel — what this looks like in the user's stack today.
  6. Implementation sketch — 10-20 lines in the user's language (or pseudocode if language is unknown).

WHY: Each component serves a different reader. The definition serves recall; the "why it exists" serves understanding; the cautions prevent misuse; the modern parallel prevents dismissing the pattern as obsolete.

Always include these cautions by pattern:

  • Gateway: Distinguish from Table Data Gateway. Not the same thing.
  • Mapper: Use only when BOTH subsystems must be unaware. Otherwise use Gateway (much simpler).
  • Separated Interface: Fowler explicitly warns against applying to every class. Only use to break a specific dependency or support multiple independent implementations.
  • Registry: Global data. Guilty until proven innocent. Prefer DI container in modern systems.
  • Value Object: Must be immutable. Aliasing bugs from mutable Value Objects are subtle.
  • Money: Never use floats. Use the allocate-by-ratio algorithm for splitting sums — simple rounding loses or gains pennies.
  • Special Case: Optional<T> is not equivalent — it makes nullability explicit but doesn't eliminate branching at every call site.
  • Service Stub: Keep stubs simple. Complexity defeats the purpose.

Step 3 — Produce the Design Note Artifact

Output a short design note (a markdown block) suitable for pasting into a code review comment, ADR, or design doc:

## Pattern: [Pattern Name]

**Applied to:** [the specific component in the user's system]

**Why this pattern:** [one sentence connecting the problem to the pattern's intent]

**Implementation shape:**
[10-20 line code sketch in the user's language]

**Cautions:**
- [most relevant caution for this usage]

WHY: A concrete artifact makes the guidance actionable. Without a sketch, the recommendation remains abstract. The cautions prevent the most common misapplication of the pattern in this specific context.


Step 4 — Surface Adjacent Patterns (Optional)

If another base pattern complements or must be used alongside the primary recommendation:

  • Gateway → mention Service Stub and Plugin (the testing triad).
  • Plugin → mention Separated Interface (Plugin requires it).
  • Service Stub → mention Gateway (stub replaces a Gateway, not raw code).
  • Separated Interface → mention Plugin (for runtime wiring).
  • Value Object → mention Money (if the value object involves monetary amounts).

WHY: The base patterns form a triad (Gateway + Plugin + Service Stub) and a pair (Value Object + Money). Mentioning them together prevents the user from applying one pattern while missing the pattern it depends on.


Inputs

  • Pattern name or problem description (required)
  • Language/stack (optional — used to tailor the implementation sketch)
  • Relevant code file or snippet (optional — used to make the design note concrete)

Outputs

  1. Pattern identification — which of the 11 base patterns matches
  2. Definition and rationale — intent, why it exists, when to apply
  3. Critical cautions — most important mis-application to avoid
  4. Modern parallel — how the pattern appears in the user's language/framework today
  5. Design note artifact — markdown block with implementation sketch and cautions

Key Principles

1. Gateway and Table Data Gateway are not the same. Table Data Gateway (Chapter 10) is a specific data-access pattern that accesses one database table and returns Record Sets. The generic Gateway (Chapter 18) is a broader pattern for wrapping any external resource. Every Table Data Gateway IS a Gateway, but not all Gateways are Table Data Gateways. Using "Gateway" to mean "database gateway that returns rows" is the most common PEAA vocabulary error.

WHY: Confusion between the two leads engineers to reject the generic Gateway pattern when they already know Table Data Gateway — or to misapply the pattern to a data-access context where Table Data Gateway is the correct choice.

2. Money pattern means no floats, ever. double and float are binary floating-point types. They cannot exactly represent most decimal fractions. 0.1 + 0.1 + 0.1 != 0.3 in IEEE 754. For monetary arithmetic, use integer cents (long) or fixed-point decimal (BigDecimal, decimal, Decimal). The Money pattern wraps these with currency-awareness and safe allocation.

WHY: Float-based monetary arithmetic silently accumulates rounding errors. These errors surface as penny discrepancies in financial reports, which have compliance and audit consequences.

3. Special Case chains, while Optional terminates. When you replace a null customer with a NullCustomer Special Case, nullCustomer.contract can return a NullContract (another Special Case) rather than null. This chain propagates polymorphism through the domain model without any null checks anywhere. Optional<T> requires the caller to handle the empty case at each .get() — it shifts the null-check burden rather than eliminating it.

WHY: The entire value of Special Case is eliminating branching. Understanding the chain behavior is essential to implementing Special Case correctly.

4. Registry is service-locator style — prefer DI injection in modern systems. Fowler himself says Registry is "global data, guilty until proven innocent" and to use it only as a last resort. Modern DI containers (Spring, .NET DI, Guice) push dependencies into constructors at wiring time, making dependencies explicit, testable, and auditable. Registry is appropriate in a narrow set of cases: deeply nested utility code that cannot be wired via constructor, or lightweight applications without a DI framework.

WHY: Registry is commonly cargo-culted from older codebases into modern ones where DI would be simpler and safer. Flagging the tradeoff prevents this.

5. Separated Interface has a cost — only use it to break specific dependencies. Each Separated Interface requires a factory with its own interface and implementation. Fowler explicitly warns against applying this to every class. For most classes, put the interface and implementation together. Separate them only when (a) you need to break a layer dependency cycle, (b) you need multiple independent implementations, or (c) you're working across team boundaries.

WHY: The pattern's benefit is targeted dependency management. Applied universally, it doubles the boilerplate without adding clarity.


Examples

Scenario 1: Wrapping a 3rd-Party Shipping API

Trigger: "We integrate with FedEx via their proprietary SDK. Every service class that needs shipping rates calls the SDK directly. I want to hide it behind a clean interface."

Process:

  1. Identify: external resource with awkward API → Gateway pattern.
  2. Check for confusion: is this a data-access gateway? No — it's a shipping service → generic Gateway (not Table Data Gateway).
  3. Recommend: create ShippingRateGateway interface + FedExShippingRateGateway implementation. The interface reflects your application's needs, not FedEx's full SDK.
  4. Surface adjacents: design the Gateway to be replaceable with a Service Stub for testing. Use Plugin or DI to wire the implementation.

Output (design note):

## Pattern: Gateway

**Applied to:** FedEx shipping rate integration

**Why this pattern:** The FedEx SDK has a complex, proprietary API. Wrapping it in a
Gateway isolates all SDK coupling in one class, enables unit testing via a stub, and
makes future provider changes (FedEx → UPS) a single-class swap.

**Implementation shape (TypeScript):**
interface ShippingRateGateway {
  getRates(origin: Address, destination: Address, weight: kg): ShippingRate[];
}

class FedExShippingRateGateway implements ShippingRateGateway {
  getRates(origin, destination, weight) {
    // translate to FedEx SDK call + translate response
  }
}

class StubShippingRateGateway implements ShippingRateGateway {
  getRates() { return [{ carrier: "FedEx", service: "Ground", price: Money.dollars(12.50) }]; }
}

**Cautions:**
- This is a generic Gateway (Chapter 18), not a Table Data Gateway (Chapter 10).
  Table Data Gateway is for database table access specifically.

Scenario 2: Money Stored as Floats

Trigger: "Our invoice totals sometimes show $0.01 discrepancies. We store monetary amounts as double in the database and in our Java domain objects."

Process:

  1. Identify: monetary arithmetic with float → Money pattern.
  2. Root cause: IEEE 754 floating-point cannot represent decimal fractions exactly.
  3. Recommend: introduce a Money class with long (cents) + Currency field. Replace all double/float money fields.
  4. Allocation warning: if they split amounts (tax splits, discount allocation), flag Foemmel's Conundrum — simple rounding can gain or lose pennies. Use the allocate(ratios[]) method.

Output:

## Pattern: Money

**Applied to:** Invoice total calculation

**Why this pattern:** `double` cannot represent most decimal fractions exactly in
IEEE 754. $0.01 discrepancies are the direct result. Money pattern wraps amount
(stored as integer cents) + Currency and enforces safe arithmetic.

**Implementation shape (Java):**
public record Money(long cents, Currency currency) {
    public Money add(Money other) {
        assertSameCurrency(other);
        return new Money(cents + other.cents, currency);
    }
    public Money[] allocate(int[] ratios) { /* use ratio algorithm, not rounding */ }
}

**Cautions:**
- Never use double/float for monetary amounts.
- For allocation (70/30 splits): use allocate-by-ratio, not simple rounding.
  Rounding 5 cents 70/30 loses or gains a penny. The ratio algorithm distributes
  remainders one cent at a time.

Scenario 3: Null Checks for Missing Customer

Trigger: "When a customer hasn't been identified yet (occupant utility account), we return null from findCustomer(). Now we have null checks in 12 places, all doing the same fallback: name='Unknown', balance=0, lastBill=null."

Process:

  1. Identify: repeated null checks with same fallback behavior → Special Case pattern.
  2. Distinguish: Null Object (GoF) is Special Case specialized for null. This is the right pattern.
  3. Recommend: create UnknownCustomer extends Customer with default implementations. Change findCustomer() to return UnknownCustomer() instead of null. Remove the 12 null checks.
  4. Chain note: unknownCustomer.lastBill should return a NullBill Special Case, not null.

Output:

## Pattern: Special Case (Null Object variant)

**Applied to:** findCustomer() returning null for unidentified occupant accounts

**Why this pattern:** 12 identical null-check blocks are code duplication. Special Case
eliminates the branching by making the missing case a valid polymorphic subtype.

**Implementation shape (Python):**
class UnknownCustomer(Customer):
    @property
    def name(self) -> str: return "Unknown"
    @property
    def balance(self) -> Decimal: return Decimal("0")
    @property
    def last_bill(self) -> Bill: return NullBill()

def find_customer(id: str) -> Customer:
    result = db.find_customer(id)
    return result if result else UnknownCustomer()

**Cautions:**
- last_bill should return NullBill(), not None — chain the Special Case pattern.
- Optional[Customer] shifts branching to call sites, not eliminating it.
  Special Case removes branching entirely.

References

  • references/base-patterns-cheatsheet.md — per-pattern deep-dive: full definitions, implementation sketches, modern parallels, and Fowler's cautions for all 11 patterns.

Related PEAA skills that invoke base patterns:

  • data-source-pattern-selector — recommends Gateway (wrapping data sources) and Mapper.
  • domain-logic-pattern-selector — recommends Service Stub for testing domain logic, Value Object, Special Case.
  • object-relational-structural-mapping-guide — covers Embedded Value (persistence strategy for Value Object, Money).
  • distribution-boundary-designer — recommends Separated Interface for distribution boundaries.
  • web-presentation-pattern-selector — references Plugin for theme/environment-based view selection.

License

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.


Related BookForge Skills

Install related skills from ClawhHub:

  • clawhub install bookforge-data-source-pattern-selector
  • clawhub install bookforge-domain-logic-pattern-selector
  • clawhub install bookforge-distribution-boundary-designer
  • clawhub install bookforge-object-relational-structural-mapping-guide

Or install the full book set from GitHub: bookforge-skills

Comments

Loading comments...