Files
skills/common/engineering/codebase-design/DEEPENING.md
T
gitadmin 68f9b4691e feat(skills): add engineering skill definitions under common/engineering/ all from @mattpocock
Add 10 skill definitions covering codebase design, domain modeling,
test-driven development, triage, and development workflows:

- codebase-design: vocabulary and patterns for designing deep modules
- domain-modeling: build and sharpen project domain models
- grill-with-docs: interview-based design refinement with documentation
- improve-codebase-architecture: scan and report on deepening opportunities
- resolving-merge-conflicts: structured approach to merge/rebase conflicts
- setup-skills: per-repo configuration for engineering skills
- tdd: test-driven development workflow with vertical slices
- to-issues: break plans into tracer-bullet vertical slice issues
- to-prd: synthesize conversations into PRDs
- triage: state machine for issue/PR triage roles

Includes supporting files for ADR formats, issue tracker integrations
(GitHub, GitLab, Gitea), triage labels, and agent brief templates.
2026-06-25 12:01:55 -04:00

38 lines
2.5 KiB
Markdown

# Deepening
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [SKILL.md](SKILL.md) — **module**, **interface**, **seam**, **adapter**.
## Dependency categories
When assessing a candidate for deepening, classify its dependencies. The category determines how the deepened module is tested across its seam.
### 1. In-process
Pure computation, in-memory state, no I/O. Always deepenable — merge the modules and test through the new interface directly. No adapter needed.
### 2. Local-substitutable
Dependencies that have local test stand-ins (PGLite for Postgres, in-memory filesystem). Deepenable if the stand-in exists. The deepened module is tested with the stand-in running in the test suite. The seam is internal; no port at the module's external interface.
### 3. Remote but owned (Ports & Adapters)
Your own services across a network boundary (microservices, internal APIs). Define a **port** (interface) at the seam. The deep module owns the logic; the transport is injected as an **adapter**. Tests use an in-memory adapter. Production uses an HTTP/gRPC/queue adapter.
Recommendation shape: *"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."*
### 4. True external (Mock)
Third-party services (Stripe, Twilio, etc.) you don't control. The deepened module takes the external dependency as an injected port; tests provide a mock adapter.
## Seam discipline
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection.
- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them.
## Testing strategy: replace, don't layer
- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them.
- Write new tests at the deepened module's interface. The **interface is the test surface**.
- Tests assert on observable outcomes through the interface, not internal state.
- Tests should survive internal refactors — they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface.