Design Review, Problem-First
Why
The common failure in design review is not lack of knowledge about principles and
patterns — it is reaching for them too early. Once a principle's name is on the
table ("this violates SRP", "this isn't DRY", "we should use a Strategy here"), the
review quietly re-centers on making the code match the principle instead of
solving a real problem. The principle becomes the goal; the original need gets
bent to fit it. The result is abstraction nobody asked for, indirection that pays
for a flexibility that never arrives, and "cleaner" code that is harder to change.
Principles and patterns are compressed hindsight about problems that recur. They are
tools for problems, not standards code must satisfy. So this skill fixes the
order of reasoning: establish the problem first, and only then let a principle
earn its way in by solving that problem more cheaply than the alternatives.
The rule
A principle or pattern may only be named once a concrete, real problem it solves
has already been stated. Naming it earlier is the bug this skill exists to catch.
If you notice yourself typing a principle's name before you have written down a
specific, observable problem — stop, delete it, and go back to Step 1.
Procedure
Work the steps in order. Do not skip ahead to Step 4; that is the whole point.
Step 1 — State the problem in plain phenomena
Describe what is actually wrong using concrete, observable facts about this code:
what changes, what breaks, what is hard to read, what took long to trace.
- Banned in this step: the name of any principle, pattern, or "smell"
(SRP, DRY, coupling, God object, Strategy, …). If you can only express the
concern as "it violates X", you have not found the problem yet — you have found a
label. Translate it into the underlying phenomenon.
- Good: "Adding a new payment provider means editing five unrelated files and one
of them is a 400-line
switch." Bad: "It violates OCP."
If you cannot state a concrete phenomenon, there may be no problem. Go to Step 5.
Step 2 — Test whether the problem is real
Separate observed facts from hypothetical futures.
- Observed: it already happened, or is happening now (a bug shipped, a change
was painful, a test is flaky, a reviewer got lost). These count.
- Hypothetical: "what if we later need to…", "this won't scale if…", "a future
developer might…". These are speculative until evidence exists.
Apply YAGNI to hypotheticals: a speculative problem does not justify design work
now. Demote it to a note ("if X actually happens, revisit") and set it aside. Only
carry observed problems into Step 3.
Step 3 — Locate the pain, concretely
For each real problem, pin down where it hurts using measurable or demonstrable
symptoms, not verdicts:
| Symptom to look for |
How to make it concrete |
| Change amplification |
"One logical change edits N files / N call sites." |
| Duplication that drifts |
"Same rule in K places; they have already diverged / caused a bug." |
| Coupling |
"Changing A forces a change in B though they are unrelated." |
| Readability |
"It took me / a reviewer this long to answer a basic question about it." |
| Testability |
"To test X you must stand up Y and Z; there is no seam." |
State the pain as a symptom with evidence. "This is highly coupled" is a verdict;
"changing the tax rule requires touching the PDF renderer" is a symptom. Carry
symptoms, not verdicts, into Step 4.
Step 4 — Only now, consider principles and patterns
With a real problem (Step 2) and its concrete pain (Step 3) fixed, look for a fix.
- Brainstorm candidate solutions. A principle or pattern may enter here as one
candidate, named for the first time.
- Evaluation axis: not "does the code match this principle?" but "does this
solve the Step 3 pain more cheaply than the alternatives?" — cost counted in
added indirection, concepts a reader must hold, and future change effort.
- Always float at least one simpler alternative and compare against it
explicitly. The bar to clear: a rename, a helper function, a comment, inlining,
deleting code, or moving one thing — a pattern must beat the simplest option that
addresses the same pain, not just be applicable.
- Look at how the surrounding code already does it before proposing anything
written from scratch. An existing helper or convention at sibling call sites is
the first candidate; a fresh loop or branch has to beat it.
- Inventory what the plan keeps. A refactoring preserves behavior, including
behavior with no reason to exist: a dead parameter, a fallback arm that never
fires, a rule nobody asked for. List each condition, parameter, or branch the plan
carries forward unchanged, and for each either show it is live (callers,
fixtures, sibling call sites) or mark it a requirement question for the
user. Whether a rule should exist is not readable from the code, so an
unexplained shape is a question, not something to preserve silently.
- Tag every claim with its evidence. A finding checked against the code says
where (
checked: path:line); one that merely sounds right says so
(inferred).
- When you need to confirm what a principle or pattern actually means (definitions
are easy to misremember and misapply), consult
references/principles.md. Open it to verify a
definition you are already considering — not to browse for a principle to apply.
Step 5 — Conclude
State the decision and the reason, tied back to the Step 3 pain.
- "Change nothing" is a valid, first-class conclusion. No real problem (Step 2),
or no candidate that beats the simpler alternative (Step 4), means the right output
is to leave the code alone — and to say why, so the non-action is deliberate.
- If you do recommend a change, name the specific pain it removes and the simpler
option it beat.
Anti-pattern self-check
Before finalizing, scan your own reasoning for these tells that the order slipped:
- A principle/pattern name appears before a concrete problem is stated.
- The justification is "best practice" / "cleaner" / "more maintainable" with no
named pain behind it.
- The driving problem is hypothetical ("we might need…") with no evidence.
- No simpler alternative was considered, or it was dismissed without comparison.
- The recommendation adds a layer, interface, or indirection whose flexibility is
not exercised by any current requirement.
- The review restated a "smell" as if the smell itself were the problem.
- The plan keeps a condition, parameter, or branch that nothing has been shown to
exercise, and did not raise it as a requirement question.
- An
inferred claim is worded as if it had been checked.
Any hit → return to the step where the slip happened.
Output format
Problem (plain phenomena): <what is observably wrong — no principle names>
Real or hypothetical: <observed evidence, or demoted via YAGNI>
Concrete pain: <symptom + evidence, not a verdict>
Options considered: <candidate(s), incl. the simplest alternative and how
the surrounding code already does it; each tagged
checked: path:line / inferred>
Kept unchanged: <each shape the plan carries forward, with evidence it
is live OR "requirement question: ...">
Decision: <chosen option OR "change nothing">
Why this over the simpler option: <cost/benefit tied to the concrete pain>
Reference
references/principles.md — pointers to trusted, primary
sources for principle/pattern definitions, with a note on when to consult each
and the point each is most often misread on. It is a lookup for Step 4, not a menu
to shop from. Comprehensiveness is delegated to those external sources; searching
the web for a solution approach is fine, but confirm definitions against the
primary sources listed there.
1---2name: design-review3description: Evaluate a design or refactoring decision problem-first, treating design principles and patterns (SOLID, DRY, GoF patterns, etc.) as after-the-fact tools rather than goals to reach. Use when reviewing a design, judging whether to apply or invoke a principle/pattern, deciding whether code "should" be refactored, planning a refactoring (what it keeps needs the same scrutiny as what it changes), or whenever a review risks forcing code into a pattern for its own sake. Guards against pattern-fitting that drifts from the actual problem.4license: CC-BY-4.05---67# Design Review, Problem-First89## Why1011The common failure in design review is not lack of knowledge about principles and12patterns — it is **reaching for them too early**. Once a principle's name is on the13table ("this violates SRP", "this isn't DRY", "we should use a Strategy here"), the14review quietly re-centers on *making the code match the principle* instead of15*solving a real problem*. The principle becomes the goal; the original need gets16bent to fit it. The result is abstraction nobody asked for, indirection that pays17for a flexibility that never arrives, and "cleaner" code that is harder to change.1819Principles and patterns are compressed hindsight about problems that recur. They are20**tools for problems**, not standards code must satisfy. So this skill fixes the21*order of reasoning*: establish the problem first, and only then let a principle22earn its way in by solving that problem more cheaply than the alternatives.2324## The rule2526> **A principle or pattern may only be named once a concrete, real problem it solves27> has already been stated.** Naming it earlier is the bug this skill exists to catch.2829If you notice yourself typing a principle's name before you have written down a30specific, observable problem — stop, delete it, and go back to Step 1.3132## Procedure3334Work the steps in order. Do not skip ahead to Step 4; that is the whole point.3536### Step 1 — State the problem in plain phenomena3738Describe what is actually wrong using concrete, observable facts about *this* code:39what changes, what breaks, what is hard to read, what took long to trace.4041- **Banned in this step:** the name of any principle, pattern, or "smell"42 (SRP, DRY, coupling, God object, Strategy, …). If you can only express the43 concern as "it violates X", you have not found the problem yet — you have found a44 label. Translate it into the underlying phenomenon.45- Good: "Adding a new payment provider means editing five unrelated files and one46 of them is a 400-line `switch`." Bad: "It violates OCP."4748If you cannot state a concrete phenomenon, there may be no problem. Go to Step 5.4950### Step 2 — Test whether the problem is real5152Separate **observed facts** from **hypothetical futures**.5354- **Observed:** it already happened, or is happening now (a bug shipped, a change55 was painful, a test is flaky, a reviewer got lost). These count.56- **Hypothetical:** "what if we later need to…", "this won't scale if…", "a future57 developer might…". These are speculative until evidence exists.5859Apply YAGNI to hypotheticals: a speculative problem does not justify design work60now. Demote it to a note ("if X actually happens, revisit") and set it aside. Only61carry **observed** problems into Step 3.6263### Step 3 — Locate the pain, concretely6465For each real problem, pin down *where it hurts* using measurable or demonstrable66symptoms, not verdicts:6768| Symptom to look for | How to make it concrete |69| --- | --- |70| Change amplification | "One logical change edits N files / N call sites." |71| Duplication that drifts | "Same rule in K places; they have already diverged / caused a bug." |72| Coupling | "Changing A forces a change in B though they are unrelated." |73| Readability | "It took me / a reviewer this long to answer a basic question about it." |74| Testability | "To test X you must stand up Y and Z; there is no seam." |7576State the pain as a symptom with evidence. "This is highly coupled" is a verdict;77"changing the tax rule requires touching the PDF renderer" is a symptom. Carry78symptoms, not verdicts, into Step 4.7980### Step 4 — Only now, consider principles and patterns8182With a real problem (Step 2) and its concrete pain (Step 3) fixed, look for a fix.8384- Brainstorm candidate solutions. A principle or pattern may enter here as **one85 candidate**, named for the first time.86- **Evaluation axis:** not "does the code match this principle?" but **"does this87 solve the Step 3 pain more cheaply than the alternatives?"** — cost counted in88 added indirection, concepts a reader must hold, and future change effort.89- **Always float at least one simpler alternative** and compare against it90 explicitly. The bar to clear: a rename, a helper function, a comment, inlining,91 deleting code, or moving one thing — a pattern must beat the simplest option that92 addresses the same pain, not just be *applicable*.93- **Look at how the surrounding code already does it** before proposing anything94 written from scratch. An existing helper or convention at sibling call sites is95 the first candidate; a fresh loop or branch has to beat it.96- **Inventory what the plan keeps.** A refactoring preserves behavior, including97 behavior with no reason to exist: a dead parameter, a fallback arm that never98 fires, a rule nobody asked for. List each condition, parameter, or branch the plan99 carries forward unchanged, and for each either show it is live (callers,100 fixtures, sibling call sites) or mark it a **requirement question** for the101 user. Whether a rule *should* exist is not readable from the code, so an102 unexplained shape is a question, not something to preserve silently.103- **Tag every claim with its evidence.** A finding checked against the code says104 where (`checked: path:line`); one that merely sounds right says so105 (`inferred`).106- When you need to confirm what a principle or pattern *actually means* (definitions107 are easy to misremember and misapply), consult108 [references/principles.md](references/principles.md). Open it to **verify a109 definition you are already considering** — not to browse for a principle to apply.110111### Step 5 — Conclude112113State the decision and the reason, tied back to the Step 3 pain.114115- **"Change nothing" is a valid, first-class conclusion.** No real problem (Step 2),116 or no candidate that beats the simpler alternative (Step 4), means the right output117 is to leave the code alone — and to say why, so the non-action is deliberate.118- If you do recommend a change, name the specific pain it removes and the simpler119 option it beat.120121## Anti-pattern self-check122123Before finalizing, scan your own reasoning for these tells that the order slipped:124125- A principle/pattern name appears **before** a concrete problem is stated.126- The justification is "best practice" / "cleaner" / "more maintainable" with no127 named pain behind it.128- The driving problem is hypothetical ("we might need…") with no evidence.129- No simpler alternative was considered, or it was dismissed without comparison.130- The recommendation adds a layer, interface, or indirection whose flexibility is131 not exercised by any current requirement.132- The review restated a "smell" as if the smell itself were the problem.133- The plan keeps a condition, parameter, or branch that nothing has been shown to134 exercise, and did not raise it as a requirement question.135- An `inferred` claim is worded as if it had been checked.136137Any hit → return to the step where the slip happened.138139## Output format140141```142Problem (plain phenomena): <what is observably wrong — no principle names>143Real or hypothetical: <observed evidence, or demoted via YAGNI>144Concrete pain: <symptom + evidence, not a verdict>145Options considered: <candidate(s), incl. the simplest alternative and how146 the surrounding code already does it; each tagged147 checked: path:line / inferred>148Kept unchanged: <each shape the plan carries forward, with evidence it149 is live OR "requirement question: ...">150Decision: <chosen option OR "change nothing">151Why this over the simpler option: <cost/benefit tied to the concrete pain>152```153154## Reference155156[references/principles.md](references/principles.md) — pointers to trusted, primary157sources for principle/pattern **definitions**, with a note on when to consult each158and the point each is most often misread on. It is a lookup for Step 4, not a menu159to shop from. Comprehensiveness is delegated to those external sources; searching160the web for a *solution approach* is fine, but confirm *definitions* against the161primary sources listed there.