Skip to content
Back to skills

Dev Codebase Design

ASecurity

Use when deciding where new code lives, when adding a function, module, service or abstraction, when a change touches more than two files for one behavior, or when a test needs to reach past a public interface to check something.

  • 6 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 12, 2026
developmentgoreacttestingapidatabaseperformance

Works with

  • api

Security analysis

A100/100

Scanned September 12, 2026

npx -y skills add connorpham/vteam-harness --skill dev-codebase-design --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Dev Codebase Design?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Dev Codebase Design
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/connorpham-dev-codebase-design/badge)](https://www.skillsdirectory.com/skills/connorpham-dev-codebase-design)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: dev-codebase-design
description: "Use when deciding where new code lives, when adding a function, module, service or abstraction, when a change touches more than two files for one behavior, or when a test needs to reach past a public interface to check something."
---


# Codebase design — deep modules, small interfaces, real seams

## Identity

You design for the reader and the tester. A module earns its place by hiding
real behavior behind a small interface at a seam that actually varies; it does
not earn it by existing. You ask "if I deleted this, where would the complexity
go?" before you add anything, and you put code next to the code it changes
with, not next to code that merely looks similar.

## When this applies

- You are about to create a file, class, hook, service or helper.
- One behavior change requires edits in three or more places.
- You want to test something the public interface does not expose.
- A "utils" or "helpers" file is about to grow.

## Decide

| Question | Choose | Because |
|---|---|---|
| New abstraction or inline code? | Inline until the second real caller exists | One adapter is a hypothetical seam; two is a real one |
| Where does the new function live? | With the code that changes for the same reason | Locality: change, bugs and knowledge concentrate in one place |
| Interface: more methods or fewer? | Fewer methods, simpler params, more behind them | Depth is leverage per unit of interface a caller must learn |
| Dependency: create inside or accept? | Accept it (parameter, constructor, context) | Tests replace it at the seam instead of monkey-patching |
| Side effect or return value? | Return the result; let the edge apply it | Pure cores are testable and reusable; effects are neither |
| Tests need private access | Reshape the module — the interface is the test surface | Testing past the seam means the seam is in the wrong place |

## Rules

- **The deletion test.** Before adding a module, imagine deleting it: if
  complexity vanishes it was pass-through; if it reappears across N callers it
  earns its keep. *Otherwise:* the codebase fills with shallow layers that
  forward calls and hide nothing.
- **Interface = everything a caller must know.** Types, invariants, ordering,
  error modes, required config, performance shape — not just the signature.
  Document the non-obvious ones at the seam. *Otherwise:* the caller learns the
  invariant from a production stack trace.
- **Unidirectional flow.** App → features → shared; features never import each
  other; shared never imports up. Enforce with a lint rule where the stack
  allows. *Otherwise:* a change in one feature breaks another through an import
  nobody remembers adding.
- **Feature folders over layer folders.** `features/orders/{api,components,
  hooks,types}` beats `components/`, `hooks/`, `api/` each holding every
  feature. *Otherwise:* one feature's change is a scavenger hunt across six
  top-level directories.
- **No speculative generality.** No config flags, plugin points or generic
  parameters without a second concrete use in this ticket. *Otherwise:* you
  maintain flexibility nobody uses and reviewers cannot verify.
- **Accept dependencies, return results.** *Otherwise:* every test needs a
  live gateway, a real clock, and a database.

## Reviewer lens

- Apply the deletion test to each new module in the diff; what disappears?
- Is any dependency constructed inside the code under test rather than accepted?
- Does any file import across features, or upward from shared?

## Sources

mattpocock/skills `codebase-design` (deep modules, seams, deletion test) ·
Ousterhout, *A Philosophy of Software Design* · Feathers, *Working Effectively
with Legacy Code* (seams) · alan2207/bulletproof-react (feature folders,
`import/no-restricted-paths`).

Rationalizations, red flags and a worked example live in `reference/dev-codebase-design.md` — opened when needed, never loaded by default.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.