--- name: programming-principles description: Apply distilled coding principles from 14 classic software books to code review, refactoring, design, and implementation decisions. Do not use for language- or framework-specific tutorials, tool manuals, or tasks already governed by a project's established conventions. license: MIT compatibility: Platform-agnostic. Works with any agent that supports the Agent Skills directory format. No external dependencies. metadata: source: https://github.com/mattpocock/agent-rules-books --- # Programming Principles (14 Books) Principles distilled from the `mattpocock/agent-rules-books` repo — 14 pre-made AGENTS.md rule sets derived from classic software engineering books. Use this skill directly during code review, refactoring, design, and implementation. For deeper per-book coverage, load the relevant reference file. ## Task-to-Book Mapping When the task involves... Load / apply principles from ──────────────────────────────────────────────────────────────────────── Everyday implementation & code review Clean Code, Code Complete Refactoring existing code Refactoring, WELC Architecture / dependency management Clean Architecture, APoSD Domain modeling / business rules DDD, DDD Distilled, IDDD Enterprise app patterns / layering PoEAA Production reliability / stability Release It! Data consistency / scalability / events DDIA Engineering craft / automation Pragmatic Programmer Designing APIs / module boundaries APoSD Legacy code / risky changes WELC, Refactoring ## How to Perform a Code Assessment For a structured, reproducible workflow that combines book principles with actual repo exploration, see `references/code-assessment-workflow.md`. It covers: loading the evaluation framework, reading the repo and GitHub context, deduplicating against existing issues/PRs, classifying findings by book + priority, and deciding whether each merits an issue. ## Cross-Cutting Principles Principles synthesized from multiple books, organized by concern. ### Naming & Communication - One term per concept across the codebase. RENAMING is design work. - Names reveal abstraction, not mechanism. Prefer domain vocabulary over technical implementation detail. - Functions are verbs, classes/types are nouns, booleans are predicates. - A name needing a comment to explain it is the wrong name. - Comments exist for rationale, contracts, warnings, and non-obvious constraints — never to narrate code or compensate for bad names. ### Functions & Routines - ONE level of abstraction per function. Tell the story top-down. - Keep parameters few. Boolean flags mean split the function. - Separate commands (mutate) from queries (answer). Never both. - When a module exceeds ~400 lines or requires scrolling to understand its full scope, it's a candidate for decomposition. Split by stable responsibility boundary, not by execution order or framework convention. - The happy path must be readable. Isolate error handling, edge cases, and cleanup from the main flow. - A function too long to name precisely is too long. Extract. ### Architecture & Boundaries - Source dependencies point INWARD toward higher-level policy. Domain and use cases never import frameworks, databases, UI, or vendor SDKs. - Every external dependency — HTTP clients, filesystems, databases, vendor SDKs — must sit behind a trait or interface owned by inner layers. Direct instantiation of infrastructure code inside application or domain logic is a structural violation (Dependency Inversion Principle). - Frameworks, databases, delivery mechanisms, and devices are outer-layer details. Keep them behind ports, gateways, and adapters. - Organize by business capability / use case first, NOT by technical layer (controllers/, services/, repositories/). - The dependency rule: inner layers OWN the interfaces they need; outer layers IMPLEMENT them. - Choose boundaries by volatility and policy importance, not by size or habit. - A wrapper, layer, or abstraction must HIDE more complexity than it adds. Pass-through layers are debt. ### Data & State - Prefer types that make invalid states unrepresentable. Use enums for closed sets, Value Objects for meaningful primitives, and booleans only for binary meanings. - Make data ownership explicit: distinguish source of truth from derived, cached, or ephemeral data. - Treat shared mutable state, globals, and ambient context as costs that must earn themselves. - Keep identity, lifecycle, mutation, and loading behavior visible. - One authoritative representation per piece of system knowledge. Derive or generate everything else. ### Testing - Tests are production code: readable, deterministic, aligned with behavior. - Keep tests focused on externally visible behavior, not internal implementation details. - Add a characterization test before changing behavior in untested code. - When fixing a bug, add a regression test that would have caught it. - Treat ignored, flaky, or skipped tests as unresolved questions. - The Boy Scout Rule for tests: leave the test suite cleaner than you found it. ### Error & Failure Handling - Distinguish: programmer errors (assert), contract violations (panic/fail), expected domain failures (return/result type), retryable failures, and permanent failures. - Treat every dependency, timeout, retry, queue, and degraded state as capable of failing in slow, partial, or prolonged ways. - Timeouts on ALL outbound calls. No infinite waits. Finite retries with exponential backoff and jitter. Never retry validation errors or permanent failures — distinguish retryable from non-retryable outcomes. - Validate external input at trust boundaries. Never trust shape, size, or semantics of things from outside the process. - Fail fast when continuing hides unrecoverable trouble. Let-it-crash only with supervision and isolation. ### Refactoring & Change - Refactoring is behavior-preserving structural improvement. Never disguise a feature or redesign as cleanup. - Work in small, reversible, buildable steps. Split patches too large for local reasoning. - Identify the structural friction blocking a change. Refactor BEFORE the feature only when it makes the feature safer or simpler. - Target the current blocking smell, not every smell in sight. Stop when the next cleanup would be speculative. - Remove duplication when the SAME edit appears a third time. - Decompose when a module exceeds ~400 lines or handles 3+ distinct responsibilities. A module you can't name in a single sentence is doing too much — extract the cohesive sub-concepts. - Prefer the simplest named move: rename, extract, inline, move, split, or substitute. ## Per-Book Compressed Rules ### Clean Code (Martin) Readability, local reasoning, maintainability. Corrects: "working code = clean." - Functions: one thing, one level of abstraction, top-down narrative - Names: intention-revealing, pronounceable, one concept per term - No boolean flags, no output parameters, no hidden side effects - Comments only for rationale/constraints, never to narrate - Tests as production code: readable, deterministic, fast - Boy Scout Rule: leave touched code cleaner ### A Philosophy of Software Design (Ousterhout) Deep modules, information hiding, complexity reduction. Corrects: "familiar patterns = simple." - Deep modules: small interface, meaningful hidden complexity. Reject thin wrappers. - Pull complexity downward into the module that owns the detail - Design interfaces around what callers need to know, not how impl works - Reduce exception surface via stronger invariants. Define away invalid states. - Comments document design decisions and hidden complexity - Names, consistency, and obviousness ARE design information ### Clean Architecture (Martin) Business rules independent of frameworks/databases/UI. Corrects: "details = architecture." - Dependencies point inward. Domain never imports frameworks, DB, UI, vendors. - Entities guard enterprise invariants; Use Cases orchestrate one action - Frameworks, DB, delivery = outer-layer details behind Ports/Adapters - Inner layers OWn interfaces; outer layers IMPLEMENT - Use cases are not merged by sharing; duplication from different actors stays - Core tests run without real DB, network, framework, or hardware ### Code Complete (McConnell) Construction discipline, defect reduction, verifiable code. Corrects: "typing = construction." - Sketch pseudocode at consistent abstraction before complex routines - Input validation at every trust boundary. Assertions for programmer assumptions. - Handle errors at the right abstraction. Never silently continue from corruption. - Rising complexity IS defect risk. Split tangled routines. - Build in small, verifiable increments. Integrate often. - Comments explain intent, constraints, contracts — not mechanics. ### Domain-Driven Design (Evans) + DDD Distilled (Vernon) Ubiquitous language, bounded contexts, tactical patterns. Corrects: "model = data schema." - Name the Bounded Context before interpreting any term or module - One term per concept within the context. Code speaks Ubiquitous Language. - Aggregates: small, one root, invariant-protected, one per transaction default - Value Objects: immutable, validated at construction, compare by value - Repositories return domain objects, not tables or ORM rows - Domain Events: past-tense business facts, not property-change notifications - Anti-corruption layer at every context boundary - Core Domain gets richer modeling; supporting subdomains stay simpler ### Implementing DDD (Vernon) Practical DDD: aggregates, events, services, persistence. Corrects: "renamed CRUD = DDD." - Reference other Aggregates by identity, not by object graph - Domain Services for operations that fit no Entity or Value Object - Application Services coordinate use cases — they don't own domain decisions - CQRS when consistency or representation needs justify separate models - Event Sourcing only when the event sequence IS the right persistence model - Test invariants, valid/invalid state transitions, and events directly ### Patterns of Enterprise Application Architecture (Fowler) Layering, patterns for enterprise apps. Corrects: "more patterns = better design." - Choose business logic pattern by force: Transaction Script → Table Module → Domain Model - Service Layer for use-case coordination and transaction boundaries - Repository speaks domain terms; Data Mapper keeps SQL out of domain objects - Unit of Work for one logical commit; Identity Map for one identity per scope - Remote Facade + DTOs at cross-layer boundaries — never leak domain internals - Session state chosen deliberately: client, server, or DB with scaling accounted for ### Refactoring (Fowler) Behavior-preserving structural improvement. Corrects: "cleanup = rewrite." - Preserve observable behavior. Isolate behavior change from structural change. - Small, reversible, testable steps. Safety net before risky work. - Preparatory refactoring: reshape blocking structure BEFORE the feature - Targeted at the current blocking smell, not every smell in sight - Simplest named move: rename, extract, inline, move, encapsulate, substitute - Stop when the requested change is easy and the blocking smell is gone ### Working Effectively with Legacy Code (Feathers) Safe change in untested code. Corrects: "rewrite = first move." - Legacy = code without trustworthy tests. Characterize before redesign. - Find or create a seam: place to change behavior without editing surrounding code - Break the ONE blocking dependency before making the change - Sprout Method, Sprout Class, Wrap Method, Wrap Class for insertion - Leave the area more testable than found - Reject: hidden dependency expansion, cosmetic-only refactoring, big rewrites ### Designing Data-Intensive Applications (Kleppmann) Distributed data, consistency, events, replication. Corrects: "everything is local/ordered/exactly-once." - Source of truth, derived representations, and consistency expectations must be EXPLICIT - Treat crashes, partial writes, duplicates, and timeouts as normal input - Write semantics: durable when? visible when? conflicts how? stale reads allowed? - Events describe facts. Consumers tolerate lag, duplicates, replay, versioned payloads. - Schemas, APIs, and events evolve across old/new readers/writers - Partition by workload-relevant locality; make hot-key and cross-partition costs explicit - Transactions and isolation matched to actual invariants, not blanket defaults ### Release It! (Nygard) Production reliability, stability patterns. Corrects: "happy path = production readiness." - Timeouts on every outbound call. No infinite waits. Bounded retries with backoff. - Circuit breakers, bulkheads, fast failure to isolate dependency failures - Design overload behavior: finite queues, load shedding, capacity for critical traffic - Startup, health checks, migrations, and operational controls: restartable, observable - Validate external responses for shape, plausibility, and semantics before trusting - Observability at every boundary: latency, saturation, errors, queue depth, breaker state ### The Pragmatic Programmer (Hunt & Thomas) Engineering craft, accountability, automation. Corrects: "local edit = done." - One authoritative source per fact. Everything else derives or traces. - Preserve orthogonality: independent components, narrow interfaces, separated concerns - Tracer bullets over piles of isolated pieces. Validate architecture end-to-end early. - Automate repetitive, error-prone, easy-to-forget work - Shorten feedback loops: relevant tests, automated checks, cheap early signals - Broken windows: fix or visibly contain small quality decay before it normalizes - Debug from reproduced facts: observe, isolate, explain, fix, verify ### Refactoring.Guru Smell catalog and technique catalog. Corrects: "pattern = always the answer." - Diagnose the smell before choosing the technique - Prefer the simplest treatment: rename before extract, extract before redesign - Each smell has a specific root cause and treatment path - See `references/refactoring-guru.full.md` for the full catalog ## Compatibility Guide Books that CONFLICT (do not load as equal guidance): - DDD ❌ PoEAA — different data ownership paradigms - IDDD ❌ PoEAA — same conflict at implementation level Books that OVERLAP (choose one, they push similar pressure): - Clean Code 🔁 Pragmatic Programmer, Code Complete, APoSD — code quality - DDD 🔁 DDD Distilled, IDDD — DDD at different depths; pick the level you need - Clean Architecture 🔁 IDDD, PoEAA — architecture/layering overlap - Refactoring 🔁 Refactoring.Guru — code improvement; choose Refactoring for strategy, Guru for catalog All other pairs are complementary. Default: one primary always-on book, others loaded on-demand per task. ## Local Reference Files Each book's mini rule set is available as a local reference file under `references/`. Load any with: ``` skill_view(name='programming-principles', file_path='references/{book-dir}.mini.md') ``` | File | Book | |------|------| | `references/a-philosophy-of-software-design.mini.md` | A Philosophy of Software Design | | `references/clean-architecture.mini.md` | Clean Architecture | | `references/clean-code.mini.md` | Clean Code | | `references/code-complete.mini.md` | Code Complete | | `references/designing-data-intensive-apps.mini.md` | Designing Data-Intensive Applications | | `references/domain-driven-design.mini.md` | Domain-Driven Design | | `references/domain-driven-design-distilled.mini.md` | DDD Distilled | | `references/implementing-domain-driven-design.mini.md` | Implementing DDD | | `references/patterns-of-eaa.mini.md` | Patterns of Enterprise App Architecture | | `references/refactoring.mini.md` | Refactoring | | `references/refactoring-guru.mini.md` | Refactoring.Guru | | `references/release-it.mini.md` | Release It! | | `references/the-pragmatic-programmer.mini.md` | The Pragmatic Programmer | | `references/working-effectively-with-legacy-code.mini.md` | Working Effectively with Legacy Code | | `references/code-assessment-workflow.md` | Assessment methodology — not a book, but the workflow for combining all books against a real repo | Each book also has a **full** version (11-42 KB) for deep reference when you need the complete rule catalog. Load on demand: ``` skill_view(name='programming-principles', file_path='references/{name}.full.md') ``` Note: `references/refactoring-guru.full.md` is an index that routes to two part files (`refactoring-guru.full-smells-and-priorities.md` and `refactoring-guru.full-technique-playbook-and-safety.md`). Loading the index shows the "Parts of this reference" table; then load the specific part you need. | Full File | Book | Size | |-----------|------|------| | `references/a-philosophy-of-software-design.full.md` | A Philosophy of Software Design | 13 KB | | `references/clean-architecture.full.md` | Clean Architecture | 17 KB | | `references/clean-code.full.md` | Clean Code | 13 KB | | `references/code-complete.full.md` | Code Complete | 12 KB | | `references/designing-data-intensive-apps.full.md` | Designing Data-Intensive Applications | 16 KB | | `references/domain-driven-design.full.md` | Domain-Driven Design | 42 KB | | `references/domain-driven-design-distilled.full.md` | DDD Distilled | 11 KB | | `references/implementing-domain-driven-design.full.md` | Implementing DDD | 12 KB | | `references/patterns-of-eaa.full.md` | Patterns of Enterprise App Architecture | 15 KB | | `references/refactoring.full.md` | Refactoring | 17 KB | | `references/refactoring-guru.full.md` | Refactoring.Guru | index + 2 parts | | `references/release-it.full.md` | Release It! | 13 KB | | `references/the-pragmatic-programmer.full.md` | The Pragmatic Programmer | 13 KB | | `references/working-effectively-with-legacy-code.full.md` | Working Effectively with Legacy Code | 13 KB | Progressive disclosure pattern: load the **mini** file for daily guidance (triggers, decision rules, final checklist). Load the **full** file only for deep sessions, audits, or when you need the complete rule catalog with code-smell indexes and technique references. ## Known Weaknesses (from repo criticism) - No empirical measurement of improvement — these are principle-based, not benchmarked. Apply judgment about whether rules improve actual outcomes. - Loading too many rule sets at once causes context saturation. Use at most one primary always-on set + one task-specific on-demand set. - Rules are book-derived, not incident-derived. The highest-value agent rules come from real failures, not theory. - Risk of pseudo-compliance: agent follows the letter of rules while missing the actual task. Test outputs against real requirements, not rule conformity.