Pragmatic Programmer
Purpose
Apply the two foundational principles from The Pragmatic Programmer — DRY and Orthogonality — to keep systems easy to understand, change, and extend without fear.
Heuristics, not laws
These are defaults, not absolutes. A short inline duplication that keeps context local is cleaner than a forced abstraction. Coupling is sometimes intentional (a transaction boundary must bind things). Prefer clarity and safe change over checklist compliance.
When To Use
- Review code for DRY violations, coupling, global state, or similar-function sprawl.
- Refactor toward a single authoritative source of truth.
- Author new code with orthogonal, loosely-coupled design.
- User mentions: "DRY", "duplication", "coupling", "orthogonal", "global state", "similar functions", "single source of truth", "Pragmatic Programmer".
Operating Modes
Authoring mode
Flow: pre-write checklist → implement → self-review → validate.
Pre-write checklist:
- Can this knowledge (rule, format, schema, constant) be expressed once? Locate the authoritative source first.
- Do the components I'm connecting need to know about each other, or can I introduce a thin interface or event?
- Am I touching global state? If yes, is there a scoped owner instead?
- Is this function meaningfully different from an existing one, or a near-copy that belongs in a shared abstraction?
Review mode
Flow: read top-down → tag findings → severity → concrete fix → cite REFERENCE.md.
Authoring Workflow
- Locate knowledge — identify every concept, rule, schema, and constant. Each must live in exactly one place.
- Draw component boundaries — components should hide their internals. If changing A requires changing B, they are too coupled.
- Push state inward — replace global/module-level mutable state with scoped, owned state passed explicitly.
- Unify similar functions — when two functions differ only in a value or a small behavior, extract a parameterized common form.
- Validate — confirm no duplicate logic remains and that changes to one component do not ripple unexpectedly.
Review Workflow
- Read from high level to detail (module exports → implementation).
- Tag each finding with a principle:
DRY or Orthogonality.
- Assign severity:
blocker (correctness/divergence risk), major (maintenance tax), minor (clarity), nit.
- Propose a concrete fix — not vague advice.
- Cite the relevant
REFERENCE.md anchor.
Review severity rubric
| Severity |
Examples |
blocker |
Business rule expressed in two places that can diverge; shared global state mutated by unrelated modules |
major |
Copy-pasted validation logic; near-identical functions with no shared core; God module imports half the system |
minor |
Magic constant repeated in 2 places; two tiny helpers that could be one parameterized function |
nit |
Cosmetic repetition that carries no divergence risk |
Output Contract
Authoring
- Implement with minimal commentary. Add a brief rationale only for non-obvious orthogonality tradeoffs.
Review
Emit findings in this shape:
[severity] [DRY|Orthogonality] path:line — finding → suggested fix (REFERENCE.md#anchor)
Optional summary block: counts by severity and top 3 recommended fixes.
Quick Heuristics
DRY
- Knowledge, not just code — duplication of business rules in tests, schemas, docs, and configs counts.
- Single authoritative source — every constant, formula, and validation rule lives in exactly one place.
- Make reuse easy — if teammates duplicate because reuse is hard, fix the friction, not just the duplicate.
- Four duplication types to watch: imposed (forced by tooling), inadvertent (unintentional), impatient (shortcut), interdeveloper (team ignorance).
Orthogonality
- Shy code — modules should not reveal unnecessary internals and should not depend on other modules' implementations.
- No global data — global/module-level mutable state silently couples every reader and writer.
- No similar functions — near-duplicate functions signal a missing abstraction, not a naming problem.
- One change, one place — if fixing a bug requires edits in three files, the design has a coupling problem.
- Layer cleanly — infrastructure details (HTTP, DB) must not leak into domain logic.
Index of Detailed Topics
Deep rules and smell cues live in REFERENCE.md:
- DRY — types of duplication
- DRY — beyond code
- DRY — making reuse easy
- Orthogonality — decoupling
- Orthogonality — global state
- Orthogonality — similar functions
- Combined: where DRY and Orthogonality meet
- Smells and heuristics table
Illustrative TypeScript refactors: EXAMPLES.md.
Validation Loop
- After authoring: confirm each concept appears once; draw a dependency graph mentally — no surprise edges.
- After review fixes: re-read changed regions; confirm severity dropped or finding resolved.
Anti-Patterns to Flag Aggressively
- Business rule expressed in two or more places — tests, docs, code, or config all count.
- Copy-paste with tiny edits — the canonical signal of impatient duplication.
- Global mutable singletons accessed from unrelated modules.
- Parallel switch/if trees on the same discriminant — change one, must change the other.
- Near-identical functions differing only in a constant or a single behavior branch.
- Leaking infrastructure (SQL, HTTP status, file paths) into domain objects.
- Documentation that restates code — it will diverge; make the code speak instead.
- Schema defined twice — e.g., TypeScript type and a separate runtime validator with the same shape.
1---2name: pragmatic-programmer3description: Apply Pragmatic Programmer principles—DRY (Don't Repeat Yourself) and Orthogonality—when authoring, reviewing, or refactoring code. Detects knowledge duplication, tight coupling, global state abuse, and similar-function sprawl, then proposes authoritative single-source fixes. Use when the user asks for DRY review, coupling analysis, orthogonality check, "make this more pragmatic", or references The Pragmatic Programmer book principles.4---56# Pragmatic Programmer78## Purpose9Apply the two foundational principles from *The Pragmatic Programmer* — DRY and Orthogonality — to keep systems easy to understand, change, and extend without fear.1011## Heuristics, not laws12These are **defaults**, not absolutes. A short inline duplication that keeps context local is cleaner than a forced abstraction. Coupling is sometimes intentional (a transaction boundary must bind things). Prefer **clarity and safe change** over checklist compliance.1314## When To Use15- **Review** code for DRY violations, coupling, global state, or similar-function sprawl.16- **Refactor** toward a single authoritative source of truth.17- **Author** new code with orthogonal, loosely-coupled design.18- User mentions: "DRY", "duplication", "coupling", "orthogonal", "global state", "similar functions", "single source of truth", "Pragmatic Programmer".1920## Operating Modes2122### Authoring mode23Flow: **pre-write checklist → implement → self-review → validate**.2425Pre-write checklist:261. Can this knowledge (rule, format, schema, constant) be expressed **once**? Locate the authoritative source first.272. Do the components I'm connecting **need** to know about each other, or can I introduce a thin interface or event?283. Am I touching global state? If yes, is there a scoped owner instead?294. Is this function **meaningfully different** from an existing one, or a near-copy that belongs in a shared abstraction?3031### Review mode32Flow: **read top-down → tag findings → severity → concrete fix → cite [REFERENCE.md](REFERENCE.md)**.3334## Authoring Workflow351. **Locate knowledge** — identify every concept, rule, schema, and constant. Each must live in exactly one place.362. **Draw component boundaries** — components should hide their internals. If changing A requires changing B, they are too coupled.373. **Push state inward** — replace global/module-level mutable state with scoped, owned state passed explicitly.384. **Unify similar functions** — when two functions differ only in a value or a small behavior, extract a parameterized common form.395. **Validate** — confirm no duplicate logic remains and that changes to one component do not ripple unexpectedly.4041## Review Workflow421. Read from **high level to detail** (module exports → implementation).432. Tag each finding with a **principle**: `DRY` or `Orthogonality`.443. Assign **severity**: `blocker` (correctness/divergence risk), `major` (maintenance tax), `minor` (clarity), `nit`.454. Propose a **concrete fix** — not vague advice.465. Cite the relevant `REFERENCE.md` anchor.4748### Review severity rubric4950| Severity | Examples |51|----------|----------|52| `blocker` | Business rule expressed in two places that can diverge; shared global state mutated by unrelated modules |53| `major` | Copy-pasted validation logic; near-identical functions with no shared core; God module imports half the system |54| `minor` | Magic constant repeated in 2 places; two tiny helpers that could be one parameterized function |55| `nit` | Cosmetic repetition that carries no divergence risk |5657## Output Contract5859### Authoring60- Implement with minimal commentary. Add a brief rationale only for non-obvious orthogonality tradeoffs.6162### Review63Emit findings in this shape:6465`[severity] [DRY|Orthogonality] path:line — finding → suggested fix (REFERENCE.md#anchor)`6667Optional summary block: counts by severity and top 3 recommended fixes.6869## Quick Heuristics7071### DRY72- **Knowledge, not just code** — duplication of business rules in tests, schemas, docs, and configs counts.73- **Single authoritative source** — every constant, formula, and validation rule lives in exactly one place.74- **Make reuse easy** — if teammates duplicate because reuse is hard, fix the friction, not just the duplicate.75- **Four duplication types to watch**: imposed (forced by tooling), inadvertent (unintentional), impatient (shortcut), interdeveloper (team ignorance).7677### Orthogonality78- **Shy code** — modules should not reveal unnecessary internals and should not depend on other modules' implementations.79- **No global data** — global/module-level mutable state silently couples every reader and writer.80- **No similar functions** — near-duplicate functions signal a missing abstraction, not a naming problem.81- **One change, one place** — if fixing a bug requires edits in three files, the design has a coupling problem.82- **Layer cleanly** — infrastructure details (HTTP, DB) must not leak into domain logic.8384## Index of Detailed Topics85Deep rules and smell cues live in [REFERENCE.md](REFERENCE.md):8687- [DRY — types of duplication](REFERENCE.md#dry--types-of-duplication)88- [DRY — beyond code](REFERENCE.md#dry--beyond-code)89- [DRY — making reuse easy](REFERENCE.md#dry--making-reuse-easy)90- [Orthogonality — decoupling](REFERENCE.md#orthogonality--decoupling)91- [Orthogonality — global state](REFERENCE.md#orthogonality--global-state)92- [Orthogonality — similar functions](REFERENCE.md#orthogonality--similar-functions)93- [Combined: where DRY and Orthogonality meet](REFERENCE.md#combined-where-dry-and-orthogonality-meet)94- [Smells and heuristics table](REFERENCE.md#smells-and-heuristics-table)9596Illustrative **TypeScript** refactors: [EXAMPLES.md](EXAMPLES.md).9798## Validation Loop99- **After authoring**: confirm each concept appears once; draw a dependency graph mentally — no surprise edges.100- **After review fixes**: re-read changed regions; confirm severity dropped or finding resolved.101102## Anti-Patterns to Flag Aggressively103- Business rule expressed in **two or more places** — tests, docs, code, or config all count.104- **Copy-paste with tiny edits** — the canonical signal of impatient duplication.105- **Global mutable singletons** accessed from unrelated modules.106- **Parallel switch/if trees** on the same discriminant — change one, must change the other.107- **Near-identical functions** differing only in a constant or a single behavior branch.108- **Leaking infrastructure** (SQL, HTTP status, file paths) into domain objects.109- **Documentation that restates code** — it will diverge; make the code speak instead.110- **Schema defined twice** — e.g., TypeScript type and a separate runtime validator with the same shape.