Generated banner for Codebase Design
Generated logo for Codebase Design

Codebase Design

Matt PocockCommunityCreated by Matt Pocock

  • Skill
  • Guidelines
  • Software development
  • MIT
  • No issues found

From the author

Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.
— the description by Matt Pocock

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

Codebase Design provides a structured framework for evaluating and improving software architecture by focusing on the concept of deep modules. It emphasizes creating modules that hide complex implementation details behind simple, high-leverage interfaces. By standardizing terminology like module, interface, seam, and adapter, this skill helps developers and AI agents communicate clearly about structural design, testability, and the trade-offs between interface complexity and implementation depth.

What it does

  • Defines a consistent vocabulary for software architecture to prevent ambiguity.
  • Provides criteria for identifying deep versus shallow modules.
  • Offers principles for designing interfaces that maximize leverage for callers and locality for maintainers.
  • Guides the placement of seams to improve testability and modularity.
  • Includes heuristics like the deletion test to evaluate the necessity of a module.
  • Encourages designing for testability by minimizing side effects and dependency creation.

When to use it

  • When designing a new module's interface or restructuring existing code.
  • When you need to decide where to place a seam in your architecture.
  • When you want to improve the testability of your codebase.
  • When you need to communicate design decisions clearly with other developers or AI agents.
  • When you are struggling with shallow modules that increase complexity rather than hiding it.

Advantages

  • Increases leverage by providing more capability per unit of interface.
  • Improves maintainability by concentrating logic and bugs in specific locations.
  • Simplifies testing by enforcing small, clear interface surfaces.
  • Reduces cognitive load through consistent, scale-agnostic terminology.
  • Helps identify when a module is earning its keep versus acting as a pass-through.

Usage examples

“Review this class interface using the deep module principles. Is it shallow?”
The agent evaluates the interface surface area, identifies if it hides complexity, and suggests refactoring to increase depth.
“Where should I place a seam in this order processing logic to make it more testable?”
The agent identifies logical boundaries and suggests an interface that allows for easier mocking or swapping of adapters.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/mattpocock/codebase-design/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip codebase-design.zip -d .agents/skills

Documentation by Matt Pocock

Codebase Design

Design deep modules: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. Use this language and these principles wherever code is being designed or restructured. The aim is leverage for callers, locality for maintainers, and testability for everyone.

Glossary

Use these terms exactly: don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point.

Module: anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. Avoid: unit, component, service.

Interface: everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. Avoid: API, signature (too narrow, they refer only to the type-level surface).

Implementation: what's inside a module, its body of code. Distinct from Adapter: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.

Depth: leverage at the interface. The amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is deep when a large amount of behaviour sits behind a small interface, shallow when the interface is nearly as complex as the implementation.

Seam (Michael Feathers): a place where you can alter behaviour without editing in that place; the location at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. Avoid: boundary (overloaded with DDD's bounded context).

Adapter: a concrete thing that satisfies an interface at a seam. Describes role (what slot it fills), not substance (what's inside).

Leverage: what callers get from depth. More capability per unit of interface they learn. One implementation pays back across N call sites and M tests.

Locality: what maintainers get from depth. Change, bugs, knowledge, and verification concentrate in one place rather than spreading across callers. Fix once, fixed everywhere.

Deep vs shallow

Deep module = small interface + lots of implementation:

┌─────────────────────┐
│   Small Interface   │  ← Few methods, simple params
├─────────────────────┤
│                     │
│  Deep Implementation│  ← Complex logic hidden
│                     │
└─────────────────────┘

Shallow module = large interface + little implementation (avoid):

┌─────────────────────────────────┐
│       Large Interface           │  ← Many methods, complex params
├─────────────────────────────────┤
│  Thin Implementation            │  ← Just passes through
└─────────────────────────────────┘

When designing an interface, ask:

  • Can I reduce the number of methods?

  • Can I simplify the parameters?

  • Can I hide more complexity inside?

Principles

  • Depth is a property of the interface, not the implementation. A deep module can be internally composed of small, mockable, swappable parts; they just aren't part of the interface. A module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface.

  • The deletion test. Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.

  • The interface is the test surface. Callers and tests cross the same seam. If you want to test past the interface, the module is probably the wrong shape.

  • One adapter means a hypothetical seam. Two adapters means a real one. Don't introduce a seam unless something actually varies across it.

Designing for testability

Good interfaces make testing natural:

  1. Accept dependencies, don't create them.

    // Testable
    function processOrder(order, paymentGateway) {}
    
    // Hard to test
    function processOrder(order) {
      const gateway = new StripeGateway();
    }
  2. Return results, don't produce side effects.

    // Testable
    function calculateDiscount(cart): Discount {}
    
    // Hard to test
    function applyDiscount(cart): void {
      cart.total -= discount;
    }
  3. Small surface area. Fewer methods = fewer tests needed. Fewer params = simpler test setup.

Relationships

  • A Module has exactly one Interface (the surface it presents to callers and tests).

  • Depth is a property of a Module, measured against its Interface.

  • A Seam is where a Module's Interface lives.

  • An Adapter sits at a Seam and satisfies the Interface.

  • Depth produces Leverage for callers and Locality for maintainers.

Rejected framings

  • Depth as ratio of implementation-lines to interface-lines (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.

  • "Interface" as the TypeScript interface keyword or a class's public methods: too narrow: interface here includes every fact a caller must know.

  • "Boundary": overloaded with DDD's bounded context. Say seam or interface.

Going deeper

  • Deepening a cluster given its dependencies, see DEEPENING.md: dependency categories, seam discipline, and replace-don't-layer testing.

  • Exploring alternative interfaces, see DESIGN-IT-TWICE.md: spin up parallel sub-agents to design the interface several radically different ways, then compare on depth, locality, and seam placement.

Files

ATTRIBUTION.md

Attribution

This folder is an unmodified copy of the Agent Skill "codebase-design", distributed by AutoGineer (https://autogineer.com/agent-skills).

The skill's own files are unmodified copies. AutoGineer is not affiliated with or endorsed by the author or the publisher.

Files added by AutoGineer

  • ATTRIBUTION.md: this file, written by AutoGineer

  • LICENSE: copied from LICENSE

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Matt Pocock
Publisher
Matt Pocock (Community)
Source
mattpocock/skills · skills/engineering/codebase-design · commit 4ae2317
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Matt Pocock or Matt Pocock.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download codebase-design.zip