speq-design-philosophy · git:20260726.540fbff · 2026-07-26 · sha256 fe74256a20ef0a7b
speq-design-philosophy git:20260726.540fbffA
Immutable. This exact content is served forever at /api/v1/blob/fe74256a20ef0a7b.
--- name: speq-design-philosophy description: Complexity-management design principles — deep modules, information hiding and leakage, module boundaries, dependency direction, strategic vs. tactical tradeoffs. Triggered by planner-agent, plan-reviewer, implementer-agent, implementer-expert-agent, and code-reviewer before any design, implementation, or review work. --- # Design Philosophy **A Philosophy of Software Design** (Ousterhout) complexity-management framework, extended with **Clean Architecture**'s (Martin) dependency rule. ## Core Principle Complexity is what erodes a system's understandability over time. Weigh every design decision by whether it adds to that erosion or reduces it — not by line count, module count, or whether it follows a named pattern. ## Deep Modules Weigh a module by how much it does for callers relative to what it costs them to learn. A deep one earns that cost back many times over — its interface is far easier to use than its internals would be to rebuild from scratch. A shallow one barely earns it back at all: learning the interface takes almost as much effort as writing the equivalent code yourself. | Signal | Fix | |--------|-----| | Interface as complex as a caller would write themselves | Deepen it — absorb more complexity, expose less | | Many small modules named for a role, not a responsibility (`-Manager`, `-Handler`, `-Processor`) | "Classitis" — merge related shallow modules into one deeper one | | A function whose entire body is a call to another function with the same arguments | Merge it into whichever side actually holds logic | Small is not automatically good. Depth, not size, decides whether an abstraction earns its place. ## Information Hiding & Leakage A module is well-designed when the rest of the system stays ignorant of one particular decision it makes internally. Trouble starts when that same decision surfaces again somewhere else in the codebase — among every kind of defect, this recurrence deserves the closest attention. - **Temporal leakage** — organizing modules around execution order (read, then parse, then write) rather than around what each stage actually knows means every stage ends up carrying the same format knowledge. - **Back-door leakage** — two modules independently assume the same data format, protocol, or convention with nothing enforcing agreement between them. Fix: combine the modules that share the decision, or give the decision its own home and have both existing modules depend on it. ## General- vs Special-Purpose Modules The governing test: an interface should handle every need the code has *today* (see `/speq-code-guardrails`' YAGNI Checks for the "not tomorrow's" half) without forcing a pile of narrow, special-case methods onto callers. A configuration parameter is a decision the module declined to make. Prefer a sensible default, auto-detection, or elimination over adding one. ## Strategic vs Tactical Programming Tactical: ship the feature, leave the module harder to work with next time. Strategic: invest roughly 10-20% of the time in design quality as part of every change, not as a separate cleanup phase. A pattern of shipping fastest by leaving every touched module harder to work with is a risk to flag, not a contribution to emulate. ## Comments as Design Intent Per `/speq-code-guardrails`' Comments rule — a public/interface doc comment states design intent, not just purpose. Struggling to write that comment is itself a signal: usually the abstraction underneath doesn't have a coherent shape yet. This doesn't relax the ban on inline or private-method comments. ## Dependencies & Boundaries Per Martin's *Clean Architecture*: - Dependencies point from volatile to stable. Business logic never names a delivery mechanism, storage engine, or framework. - Business logic performs no I/O and reads no ambient state — both are injected. - The consumer defines the abstraction it needs, in its own vocabulary — never shaped around a provider's API (Dependency Inversion). - Construct concrete implementations only at the entry point; no module builds its own dependencies. - No cycles in the module dependency graph. - Group modules by reason to change, not by technical role. - Extend by adding a case, not by editing a dispatch (Open/Closed). ## Quick Diagnostic No silent pass when reviewing a design — a new module, interface, or boundary. A change that introduces none of these may skip this table; answer every question for anything that does, and a "no" names the fix. | Question | If no | |----------|-------| | Does a one-sentence summary capture what a module is responsible for? | It's doing too much, or nothing coherent — split it | | Is calling the module noticeably easier than reimplementing it would be? | The interface costs more than it saves — hide more, expose less | | Would changing how a module works internally force an edit anywhere outside it? | A decision has leaked across a boundary — pull it into one owning module | | Does a public doc comment explain the reasoning behind an abstraction, not only restate its name? | Rewrite it — resistance to writing it usually means the design needs rework | | Is there exactly one module that owns each significant design decision? | Reorganize by what code knows, not by when it executes | | Could someone unfamiliar with the codebase tell where one module ends and the next begins, without reading either's internals? | Simplify the interfaces, or state the boundary in the interface doc comment | | Does any tactical shortcut in this change have a scheduled follow-up to revisit it? | Schedule one, or reconsider taking the shortcut at all | | Does business logic depend only inward — never on a delivery mechanism, storage engine, or framework? | Invert the dependency; the consumer defines the abstraction | ## Attribution Concepts from John Ousterhout's *A Philosophy of Software Design* and Robert C. Martin's *Clean Architecture*, adapted here. Inspired by the `wondelai/skills` collection.