@complexthings/superpowers-agent 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/docs/SUPERPOWERS.md +108 -0
- package/.agents/prompts/001-copilot-tool-mapping-do/001-copilot-tool-mapping-do.md +116 -0
- package/.agents/prompts/001-copilot-tool-mapping-do/SUMMARY.md +72 -0
- package/.agents/prompts/001-copilot-tool-mapping-do/copilot-tool-mapping-do-output.md +83 -0
- package/.agents/prompts/001-release-management-do/001-release-management-do.md +161 -0
- package/.agents/prompts/001-release-management-do/SUMMARY.md +19 -0
- package/.agents/prompts/001-release-management-do/completed/001-release-management-do.md +161 -0
- package/.agents/prompts/002-pull-command-do/SUMMARY.md +28 -0
- package/.agents/prompts/002-pull-command-do/completed/002-pull-command-do.md +122 -0
- package/.agents/prompts/002-pull-command-do/pull-command-do-output.md +174 -0
- package/.agents/prompts/command_updates_prompt.md +69 -0
- package/.agents/prompts/current_prompt.md +8 -0
- package/.agents/prompts/refactor.prompt.md +57 -0
- package/.agents/skills/.gitkeep +0 -0
- package/.agents/superpowers-agent +355 -0
- package/.agents/superpowers-bootstrap.md +42 -0
- package/.agents/templates/AGENTS.md.template +40 -0
- package/.agents/templates/SUPERPOWERS.md.template +108 -0
- package/.agents/templates/TOOLS.md.template +15 -0
- package/.github/workflows/main.yaml +32 -0
- package/AGENTS.md +60 -0
- package/LICENSE +21 -0
- package/README.md +724 -0
- package/hooks/hooks.json +15 -0
- package/hooks/session-start.sh +27 -0
- package/package.json +51 -0
- package/skills/architecture/ABOUT.md +20 -0
- package/skills/architecture/preserving-productive-tensions/SKILL.md +146 -0
- package/skills/architecture/preserving-productive-tensions/skill.json +9 -0
- package/skills/collaboration/brainstorming/SKILL.md +166 -0
- package/skills/collaboration/brainstorming/skill.json +9 -0
- package/skills/collaboration/brainstorming/spec-document-reviewer-prompt.md +50 -0
- package/skills/collaboration/brainstorming/visual-companion.md +277 -0
- package/skills/collaboration/dispatching-parallel-agents/SKILL.md +174 -0
- package/skills/collaboration/dispatching-parallel-agents/skill.json +9 -0
- package/skills/collaboration/executing-plans/SKILL.md +130 -0
- package/skills/collaboration/executing-plans/skill.json +9 -0
- package/skills/collaboration/finishing-a-development-branch/SKILL.md +261 -0
- package/skills/collaboration/finishing-a-development-branch/skill.json +9 -0
- package/skills/collaboration/leveraging-cli-tools/SKILL.md +132 -0
- package/skills/collaboration/leveraging-cli-tools/skill.json +9 -0
- package/skills/collaboration/receiving-code-review/SKILL.md +233 -0
- package/skills/collaboration/receiving-code-review/skill.json +9 -0
- package/skills/collaboration/requesting-code-review/SKILL.md +110 -0
- package/skills/collaboration/requesting-code-review/code-reviewer.md +146 -0
- package/skills/collaboration/requesting-code-review/skill.json +12 -0
- package/skills/collaboration/subagent-driven-development/SKILL.md +255 -0
- package/skills/collaboration/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/skills/collaboration/subagent-driven-development/implementer-prompt.md +113 -0
- package/skills/collaboration/subagent-driven-development/skill.json +15 -0
- package/skills/collaboration/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/collaboration/using-git-worktrees/SKILL.md +366 -0
- package/skills/collaboration/using-git-worktrees/skill.json +9 -0
- package/skills/collaboration/writing-plans/SKILL.md +121 -0
- package/skills/collaboration/writing-plans/plan-document-reviewer-prompt.md +52 -0
- package/skills/collaboration/writing-plans/skill.json +9 -0
- package/skills/debugging/defense-in-depth/SKILL.md +380 -0
- package/skills/debugging/defense-in-depth/skill.json +9 -0
- package/skills/debugging/root-cause-tracing/SKILL.md +361 -0
- package/skills/debugging/root-cause-tracing/find-polluter.sh +63 -0
- package/skills/debugging/root-cause-tracing/skill.json +12 -0
- package/skills/debugging/systematic-debugging/SKILL.md +299 -0
- package/skills/debugging/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/skills/debugging/systematic-debugging/condition-based-waiting.md +115 -0
- package/skills/debugging/systematic-debugging/defense-in-depth.md +122 -0
- package/skills/debugging/systematic-debugging/find-polluter.sh +63 -0
- package/skills/debugging/systematic-debugging/root-cause-tracing.md +169 -0
- package/skills/debugging/systematic-debugging/skill.json +9 -0
- package/skills/debugging/systematic-debugging/test-academic.md +14 -0
- package/skills/debugging/systematic-debugging/test-pressure-1.md +58 -0
- package/skills/debugging/systematic-debugging/test-pressure-2.md +68 -0
- package/skills/debugging/systematic-debugging/test-pressure-3.md +69 -0
- package/skills/debugging/verification-before-completion/SKILL.md +143 -0
- package/skills/debugging/verification-before-completion/skill.json +9 -0
- package/skills/finding-skills/SKILL.md +101 -0
- package/skills/finding-skills/skill.json +8 -0
- package/skills/meta/create-skill-json/SKILL.md +370 -0
- package/skills/meta/create-skill-json/skill.json +9 -0
- package/skills/meta/create-skill-json/test-scenarios.md +29 -0
- package/skills/meta/creating-prompts/SKILL.md +349 -0
- package/skills/meta/creating-prompts/examples/do-example.md +65 -0
- package/skills/meta/creating-prompts/examples/plan-example.md +75 -0
- package/skills/meta/creating-prompts/examples/refine-example.md +65 -0
- package/skills/meta/creating-prompts/examples/research-example.md +63 -0
- package/skills/meta/creating-prompts/scripts/get-next-number.sh +27 -0
- package/skills/meta/creating-prompts/skill.json +20 -0
- package/skills/meta/creating-prompts/templates/do-template.md +59 -0
- package/skills/meta/creating-prompts/templates/plan-template.md +58 -0
- package/skills/meta/creating-prompts/templates/refine-template.md +54 -0
- package/skills/meta/creating-prompts/templates/research-template.md +56 -0
- package/skills/meta/using-superpowers/SKILL.md +122 -0
- package/skills/meta/using-superpowers/skill.json +5 -0
- package/skills/meta/writing-prompts/SKILL.md +345 -0
- package/skills/meta/writing-prompts/skill.json +9 -0
- package/skills/problem-solving/ABOUT.md +40 -0
- package/skills/problem-solving/collision-zone-thinking/SKILL.md +188 -0
- package/skills/problem-solving/collision-zone-thinking/references/historical-examples.md +393 -0
- package/skills/problem-solving/collision-zone-thinking/skill.json +9 -0
- package/skills/problem-solving/inversion-exercise/SKILL.md +174 -0
- package/skills/problem-solving/inversion-exercise/skill.json +9 -0
- package/skills/problem-solving/meta-pattern-recognition/SKILL.md +116 -0
- package/skills/problem-solving/meta-pattern-recognition/skill.json +9 -0
- package/skills/problem-solving/scale-game/SKILL.md +222 -0
- package/skills/problem-solving/scale-game/skill.json +9 -0
- package/skills/problem-solving/simplification-cascades/SKILL.md +113 -0
- package/skills/problem-solving/simplification-cascades/skill.json +9 -0
- package/skills/problem-solving/when-stuck/SKILL.md +69 -0
- package/skills/problem-solving/when-stuck/skill.json +9 -0
- package/skills/research/ABOUT.md +20 -0
- package/skills/research/tracing-knowledge-lineages/SKILL.md +241 -0
- package/skills/research/tracing-knowledge-lineages/skill.json +9 -0
- package/skills/setup-skills/SKILL.md +47 -0
- package/skills/testing/condition-based-waiting/SKILL.md +359 -0
- package/skills/testing/condition-based-waiting/example.ts +158 -0
- package/skills/testing/condition-based-waiting/skill.json +12 -0
- package/skills/testing/test-driven-development/SKILL.md +434 -0
- package/skills/testing/test-driven-development/skill.json +9 -0
- package/skills/testing/testing-anti-patterns/SKILL.md +298 -0
- package/skills/testing/testing-anti-patterns/skill.json +9 -0
- package/skills/testing/verification-before-completion/SKILL.md +246 -0
- package/skills/testing/verification-before-completion/skill.json +10 -0
- package/skills/using-a-skill/SKILL.md +101 -0
- package/skills/using-a-skill/skill.json +8 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: inversion-exercise
|
|
3
|
+
description: Flip core assumptions to reveal hidden constraints and alternative approaches. Use this when stuck on "the only way" to solve a problem, during architecture or design decisions, at code review or project pre-mortems, when a solution feels forced, or anytime assumptions need stress-testing. Inversion bypasses confirmation bias by asking "how would this fail?" instead of "how do we succeed?" — a mental move that surfaces what forward thinking misses. Apply it proactively before major decisions, not just when stuck.
|
|
4
|
+
metadata:
|
|
5
|
+
when_to_use: when stuck on unquestioned assumptions or feeling forced into "the only way" to do something; also proactively before architecture decisions, API design, or project kickoffs
|
|
6
|
+
version: 2.0.0
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Inversion Exercise
|
|
10
|
+
|
|
11
|
+
## Why This Works
|
|
12
|
+
|
|
13
|
+
Carl Jacobi (the mathematician) discovered that many hard problems are easier when restated in inverse form. Charlie Munger applied this principle everywhere: "Invert, always invert."
|
|
14
|
+
|
|
15
|
+
> "All I want to know is where I'm going to die, so I'll never go there." — Charlie Munger
|
|
16
|
+
|
|
17
|
+
The cognitive mechanism: your brain cannot easily generate failure modes when it is focused on success. But it is surprisingly good at generating them when you ask for them directly. Inversion is an *access method* for a different cognitive pathway — one that bypasses optimism bias and confirmation bias.
|
|
18
|
+
|
|
19
|
+
**The practical upshot:** avoiding obvious stupidity is more tractable than seeking brilliance. Most production outages are not caused by missing brilliant features — they're caused by unexamined failure modes.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## The Four Forms of Inversion
|
|
24
|
+
|
|
25
|
+
### 1. Goal Inversion (Pre-Mortem)
|
|
26
|
+
|
|
27
|
+
Instead of "how do we succeed?", ask "how would we fail?"
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
FORWARD: "How do we make this deployment succeed?"
|
|
31
|
+
INVERTED: "Assume it's 6 months from now and this deployment failed badly.
|
|
32
|
+
What happened?"
|
|
33
|
+
|
|
34
|
+
Typical answers: no rollback plan, untested migration, no monitoring alerts,
|
|
35
|
+
deployed on Friday, insufficient load testing
|
|
36
|
+
|
|
37
|
+
These aren't hypotheticals — they're your checklist.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Gary Klein (HBR 2007) formalized this as the **Failure Pre-mortem**. The grammatical shift from "might fail" to "did fail" grants permission to voice concerns in an environment where optimism is rewarded. It makes it safe to be pessimistic.
|
|
41
|
+
|
|
42
|
+
**Use this at:** project kickoffs, architecture decisions, release planning, code review.
|
|
43
|
+
|
|
44
|
+
### 2. Assumption Inversion (Flip Core Beliefs)
|
|
45
|
+
|
|
46
|
+
Challenge what you believe about how the system works.
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
ASSUMPTION: "Clients must poll for updates"
|
|
50
|
+
INVERTED: "What if the server pushes updates?"
|
|
51
|
+
REVEALS: WebSockets, Server-Sent Events, webhooks
|
|
52
|
+
|
|
53
|
+
ASSUMPTION: "Data must be normalized in tables with strict schemas"
|
|
54
|
+
INVERTED: "What if data were denormalized with flexible schemas?"
|
|
55
|
+
REVEALS: Document stores, key-value stores — each optimized for different patterns
|
|
56
|
+
|
|
57
|
+
ASSUMPTION: "We must make this faster"
|
|
58
|
+
INVERTED: "What if we made this intentionally slower in places?"
|
|
59
|
+
REVEALS: Debounce search (add latency → better results), rate limiting,
|
|
60
|
+
lazy loading (delay → reduce initial load)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 3. Perspective Inversion (Opposite Stakeholder)
|
|
64
|
+
|
|
65
|
+
View from the opposing party.
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
API DESIGNER: "What do we want to expose?"
|
|
69
|
+
INVERTED: "What does the caller actually need to call?"
|
|
70
|
+
REVEALS: Consumer-driven contracts; Amazon's "write the press release first"
|
|
71
|
+
|
|
72
|
+
CODE AUTHOR: "Does this code work?"
|
|
73
|
+
INVERTED: "Under what conditions would this code fail?"
|
|
74
|
+
REVEALS: Edge cases, race conditions, input assumptions
|
|
75
|
+
|
|
76
|
+
DEFENDER: "How do we secure this system?"
|
|
77
|
+
INVERTED: "If I were an attacker, how would I break in?"
|
|
78
|
+
REVEALS: Threat modeling, red team exercises, STRIDE analysis
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 4. Process Inversion (Reverse the Sequence)
|
|
82
|
+
|
|
83
|
+
Reverse the order of steps.
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
NORMAL: Write code → write tests to verify it
|
|
87
|
+
INVERTED: Write tests (specification) → write code to satisfy them (TDD)
|
|
88
|
+
REVEALS: Forces you to think about the contract before implementation;
|
|
89
|
+
surfaces design problems earlier; ensures tests test behavior
|
|
90
|
+
|
|
91
|
+
NORMAL: Big batch releases, high-ceremony
|
|
92
|
+
INVERTED: Ship every commit; make deployment boring; test in production
|
|
93
|
+
REVEALS: The pain of releases was caused by their infrequency (CI/CD)
|
|
94
|
+
|
|
95
|
+
NORMAL: A class creates its own dependencies
|
|
96
|
+
INVERTED: A framework provides dependencies to the class (IoC/DI)
|
|
97
|
+
REVEALS: Testable, loosely coupled code; each class only knows interfaces
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## The Process
|
|
103
|
+
|
|
104
|
+
**Step 1: State the goal clearly**
|
|
105
|
+
Write it as a single sentence: "I want X."
|
|
106
|
+
|
|
107
|
+
**Step 2: Flip it**
|
|
108
|
+
"What would *guarantee* NOT-X?" or "What would *make* this fail?"
|
|
109
|
+
|
|
110
|
+
**Step 3: Generate freely on the inverted question**
|
|
111
|
+
Don't filter. List everything. The items that feel uncomfortable to acknowledge are often the most important.
|
|
112
|
+
|
|
113
|
+
**Step 4: Translate back**
|
|
114
|
+
Each item on the inverted list is a design constraint, checklist item, or thing to stop doing. Ask: "If this would cause failure, what does that tell me about what success requires?" The inverted list is often your real answer in disguise.
|
|
115
|
+
|
|
116
|
+
**Step 5: Combine with forward thinking**
|
|
117
|
+
Inversion shows you what to *avoid* and what *constraints* you're operating under. Forward thinking shows you what to *build*. Use both.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Software Patterns That *Are* Inversion
|
|
122
|
+
|
|
123
|
+
Recognizing these helps you understand *why* they work — and when to reach for them:
|
|
124
|
+
|
|
125
|
+
| Pattern | The Inversion | What It Unlocks |
|
|
126
|
+
|---------|--------------|-----------------|
|
|
127
|
+
| **TDD** | Write proof before code | Tests actually test behavior; design problems surface early |
|
|
128
|
+
| **Dependency Inversion (SOLID)** | High-level doesn't depend on low-level | Abstractions own interfaces; implementations are plugins |
|
|
129
|
+
| **IoC / DI** | Framework calls your code, not vice versa | Testable, loosely coupled, swappable implementations |
|
|
130
|
+
| **Immutability** | State never changes; new values replace old | No shared mutable state bugs; trivially thread-safe |
|
|
131
|
+
| **Result types** | Functions return error-or-value instead of throwing | Errors are explicit in the type system; no surprise exceptions |
|
|
132
|
+
| **Consumer-driven contracts** | Provider doesn't define API shape; consumer does | API always matches real consumer needs |
|
|
133
|
+
| **Pre-mortem** | Assume failure, ask what happened | Surfaces what optimism hides |
|
|
134
|
+
| **Threat modeling** | "How would I attack this?" before building | Catch vulnerabilities at design time, not after breach |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## When Inversion Is Especially Powerful
|
|
139
|
+
|
|
140
|
+
- **"There's only one way to do this"** — almost always wrong; inversion finds the alternatives
|
|
141
|
+
- **Solution feels forced or fights the system** — you're working against an inverted constraint
|
|
142
|
+
- **Can't articulate *why* the current approach is necessary** — the assumption may not hold
|
|
143
|
+
- **About to make an irreversible decision** — pre-mortem first, always
|
|
144
|
+
- **Building something that "should" be secure, fast, or correct** — invert to find where those properties break
|
|
145
|
+
- **Starting a new project or architecture** — "how would this fail in 12 months?" before a single line of code
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Failure Modes of Inversion
|
|
150
|
+
|
|
151
|
+
**False dichotomies:** Not every problem has a clean opposite. "How do we make users happy?" doesn't cleanly invert. Inversion works best when the domain is genuinely bipolar.
|
|
152
|
+
|
|
153
|
+
**Mistaking the inverted list for a complete solution:** The pre-mortem identifies failure modes, not solutions. "Here's how we'd fail" → "here's our mitigation plan" is additional work.
|
|
154
|
+
|
|
155
|
+
**Over-correcting on the inverted insight:** "Ship less frequently caused problems" doesn't mean "ship every 5 minutes without review." The inversion reveals the direction of improvement, not the optimal point.
|
|
156
|
+
|
|
157
|
+
**Stopping at the inversion:** Inversion gives you the floor (don't do these things). It doesn't give you the ceiling (what excellent looks like). Combine with forward thinking.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Quick Reference
|
|
162
|
+
|
|
163
|
+
| Want to... | Inversion move |
|
|
164
|
+
|-----------|---------------|
|
|
165
|
+
| Stress-test an architecture | Pre-mortem: "It failed in 12 months — why?" |
|
|
166
|
+
| Design a better API | "What would make this API impossible to use?" |
|
|
167
|
+
| Find security holes | "How would an attacker break this?" |
|
|
168
|
+
| Improve code quality | "Under what conditions does this code fail?" |
|
|
169
|
+
| Improve a process | "What would we do to guarantee this process fails?" |
|
|
170
|
+
| Escape a local maximum | "What assumption am I making that isn't necessarily true?" |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
> "Spend less time trying to be brilliant and more time trying to avoid obvious stupidity." — Shane Parrish
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: meta-pattern-recognition
|
|
3
|
+
description: Spot patterns appearing in 3+ domains to find universal principles. Use when you notice the same problem recurring across different contexts, when teams independently discover "identical" solutions, when experiencing déjà vu in problem-solving, or when you want to actively extract transferable principles. Triggers on phrases like "this feels familiar," "haven't we solved this before?", "same thing keeps happening," or "why do all these systems look the same?"
|
|
4
|
+
metadata:
|
|
5
|
+
version: 1.2.0
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Meta-Pattern Recognition
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
When the same shape appears in 3+ genuinely different domains, you've found something universal. Name it, and you unlock it everywhere.
|
|
13
|
+
|
|
14
|
+
**Core principle:** Find patterns in how patterns emerge — then apply them where nobody has looked yet.
|
|
15
|
+
|
|
16
|
+
Two modes: **passive** (recognize a pattern already recurring) and **active** (force patterns to surface through deliberate techniques).
|
|
17
|
+
|
|
18
|
+
## Quick Reference
|
|
19
|
+
|
|
20
|
+
| Pattern | Abstract Form | Seen In |
|
|
21
|
+
|---------|--------------|---------|
|
|
22
|
+
| CPU/DB/HTTP caching | Store frequently-accessed data closer to consumer | LLM prompt caching, CDN, memoization |
|
|
23
|
+
| Layering (network/OS/storage) | Separate concerns into abstraction levels | Architecture, org structure, compiler stages |
|
|
24
|
+
| Queuing (message/task/request) | Decouple producer from consumer via buffer | Event systems, async I/O, print spoolers |
|
|
25
|
+
| Pooling (connection/thread/object) | Reuse expensive resources rather than recreate | Memory allocators, worker pools, license servers |
|
|
26
|
+
| Rate limiting / circuit breakers | Bound consumption to prevent exhaustion | Token budgets, backpressure, admission control |
|
|
27
|
+
| Retry with exponential backoff | Respect the system you depend on | HTTP clients, DB reconnect, social negotiation |
|
|
28
|
+
|
|
29
|
+
## Passive Mode: Recognize a Recurring Pattern
|
|
30
|
+
|
|
31
|
+
1. **Spot repetition** — Same shape appears in 3+ distinct domains (not just 3 modules in one system)
|
|
32
|
+
2. **Extract abstract form** — State the pattern using zero domain-specific vocabulary
|
|
33
|
+
3. **Map variation points** — Where does it *have to* vary, and why? (reveals the true structure)
|
|
34
|
+
4. **Hunt new applications** — Where does this pattern apply that nobody has tried yet?
|
|
35
|
+
|
|
36
|
+
**Example:**
|
|
37
|
+
|
|
38
|
+
Pattern spotted: Rate limiting (APIs), traffic shaping (networks), circuit breakers (microservices), admission control (OSes)
|
|
39
|
+
|
|
40
|
+
Abstract form: *Bound resource consumption to prevent exhaustion*
|
|
41
|
+
|
|
42
|
+
Variation points: what resource, what measurement window, what happens when exceeded (reject / queue / degrade)
|
|
43
|
+
|
|
44
|
+
New application: LLM token budgets — same pattern prevents context-window exhaustion; variant is "soft limit + graceful degradation" rather than hard rejection.
|
|
45
|
+
|
|
46
|
+
## Active Mode: Force Patterns to Emerge
|
|
47
|
+
|
|
48
|
+
Use when you want to *generate* insights, not just spot them.
|
|
49
|
+
|
|
50
|
+
**Collision Zone Thinking** — Force two unrelated concepts together:
|
|
51
|
+
> "What if rate limiting applied to human attention, not API calls?"
|
|
52
|
+
The collision reveals a third concept neither domain had.
|
|
53
|
+
|
|
54
|
+
**The Medium Swap** — Apply a solution from one domain directly to another:
|
|
55
|
+
> TCP backpressure → LLM token streaming; biological immune memory → anomaly detection
|
|
56
|
+
|
|
57
|
+
**The Inversion Exercise** — Flip the core assumption:
|
|
58
|
+
> "What if caching *slowed* things down?" → reveals cache invalidation cost, stale data risk
|
|
59
|
+
|
|
60
|
+
**The Scale Game** — Test at 1000x bigger, 1000x smaller, instant, or year-long:
|
|
61
|
+
> Patterns that hold at extremes are truly universal; those that break reveal hidden assumptions.
|
|
62
|
+
|
|
63
|
+
**The 2+2=5 Framework** — Find synergistic combinations:
|
|
64
|
+
> Caching + streaming = speculative prefetch (a third concept neither had alone)
|
|
65
|
+
|
|
66
|
+
## Emergence Types
|
|
67
|
+
|
|
68
|
+
Watch for these when patterns arise unexpectedly:
|
|
69
|
+
|
|
70
|
+
- **Divergence** — Two concepts collide → third option neither implied ("creates" + "removes" = "transforms")
|
|
71
|
+
- **Tension** — Sustained contradiction generates insight rather than resolving (consistency vs. availability → eventually-consistent as a new idea, not a compromise)
|
|
72
|
+
- **Cascade** — One pattern recognition triggers a chain ("buffer" = RAM, Git staging, async queues, human short-term memory — all one pattern)
|
|
73
|
+
- **Void** — What's *not* connected reveals what's missing ("Why is there no pattern here?" often signals unsolved problems)
|
|
74
|
+
- **Meta** — Patterns in how patterns form ("Why do resource-management patterns always have the same 3 variation points?")
|
|
75
|
+
|
|
76
|
+
## Quality Check
|
|
77
|
+
|
|
78
|
+
Before claiming you've found a universal pattern:
|
|
79
|
+
|
|
80
|
+
- [ ] Does it appear in 3+ **genuinely different domains**? (not 3 places in one codebase)
|
|
81
|
+
- [ ] Can you state it with **zero domain-specific vocabulary**?
|
|
82
|
+
- [ ] Have you identified at least **2 variation points** explaining why it looks different per domain?
|
|
83
|
+
- [ ] Does applying it somewhere **new produce a useful result**?
|
|
84
|
+
- [ ] Can you name **what it replaces** — what separate mental models collapse into one?
|
|
85
|
+
|
|
86
|
+
## Simplification Cascades
|
|
87
|
+
|
|
88
|
+
The best meta-patterns eliminate complexity. When you find a universal principle, ask: **"If this is true, what do we no longer need?"**
|
|
89
|
+
|
|
90
|
+
> If all resource limits are "bound consumption to prevent exhaustion" → rate limiting, circuit breakers, and admission control no longer need separate mental models.
|
|
91
|
+
|
|
92
|
+
A good cascade eliminates 3+ previously separate concepts.
|
|
93
|
+
|
|
94
|
+
## Productive Tensions
|
|
95
|
+
|
|
96
|
+
Don't resolve contradictions too quickly — they generate patterns.
|
|
97
|
+
|
|
98
|
+
When two things seem to conflict, ask: What third concept does this tension reveal? Does this tension appear in other domains?
|
|
99
|
+
|
|
100
|
+
**Preserve failed pattern-matches.** They reveal where the abstraction breaks and what the true variation points are.
|
|
101
|
+
|
|
102
|
+
## Red Flags You're Missing Meta-Patterns
|
|
103
|
+
|
|
104
|
+
- "This problem is unique" — probably not; look harder
|
|
105
|
+
- Multiple teams solving "different" problems with identical solutions
|
|
106
|
+
- Reinventing wheels across domains without cross-pollination
|
|
107
|
+
- "Haven't we done something like this before?"
|
|
108
|
+
- Resolving contradictions too fast (destroying a pattern generator)
|
|
109
|
+
- Discarding failed pattern-attempts (they contain the variation data)
|
|
110
|
+
|
|
111
|
+
## Remember
|
|
112
|
+
|
|
113
|
+
- 3+ domains = likely universal; 5+ = probably foundational
|
|
114
|
+
- Abstract form (no jargon) reveals new applications — the vocabulary you choose shapes what you find next
|
|
115
|
+
- Variation points explain *why* it looks different, not just *how*
|
|
116
|
+
- Productive tensions and failures are data, not dead ends
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scale-game
|
|
3
|
+
description: Test at extremes (1000x bigger/smaller, instant/year-long) to expose fundamental truths hidden at normal scales. Use this skill whenever someone asks "will this scale?", "what happens at production load?", "what if 1000 users hit this simultaneously?", or when validating architecture, reviewing algorithms, designing systems, or reasoning about capacity. Also use proactively when you see O(n²) algorithms, shared mutable state, synchronous APIs, or in-memory data accumulation — any pattern whose behavior changes with scale.
|
|
4
|
+
metadata:
|
|
5
|
+
version: 3.1.0
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Scale Game
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
Test your approach at extreme scales to find what breaks and what surprisingly survives.
|
|
13
|
+
|
|
14
|
+
**Core principle:** Properties invisible at normal scales dominate at extreme scales. An O(n²) algorithm is fine at n=100 and catastrophic at n=1,000,000. Test at extremes to find the fundamentals before production does.
|
|
15
|
+
|
|
16
|
+
This is a thought experiment technique — most scale tests take seconds, not machines. The goal is insight, not measurement.
|
|
17
|
+
|
|
18
|
+
## Origins
|
|
19
|
+
|
|
20
|
+
This technique has deep roots across science and engineering:
|
|
21
|
+
|
|
22
|
+
- **Galileo (1638):** Dropping two cannonballs from the Leaning Tower — testing at "different weights" exposed that Aristotle's theory (heavier falls faster) was wrong. Extremes falsified conventional wisdom.
|
|
23
|
+
- **Einstein (1905):** "What would I see if I chased a light beam at light speed?" — an impossible-to-run experiment that led directly to special relativity. The extreme (v = c) revealed a contradiction in classical physics.
|
|
24
|
+
- **Fermi Estimation:** Reasoning by order of magnitude to establish bounds — "how many piano tuners in Chicago?" is the mathematical equivalent of the scale game: work from first principles to a number, then ask if the number makes sense at different scales.
|
|
25
|
+
- **Jeff Dean at Google:** "Numbers Everyone Should Know" established a canonical scale reference — L1 cache (0.5 ns) vs. cross-continental round trip (150 ms) is a 300,000,000× difference. Knowing these numbers lets you reason about systems at scale without building them.
|
|
26
|
+
- **Netflix Chaos Monkey (2011):** Institutionalized extreme failure testing. If your system can't survive random instance death, it can't survive production.
|
|
27
|
+
|
|
28
|
+
## Quick Reference
|
|
29
|
+
|
|
30
|
+
| Scale Dimension | Test At Zero/Minimum | Test At Maximum | What It Reveals |
|
|
31
|
+
|-----------------|---------------------|-----------------|-----------------|
|
|
32
|
+
| Volume | 0 items, 1 item | 1B items, unbounded | Algorithmic complexity class (O(n²) vs O(n log n)) |
|
|
33
|
+
| Concurrency | 1 user, sequential | 1M simultaneous users | Race conditions, lock contention, resource exhaustion |
|
|
34
|
+
| Speed / Latency | Instant (in-process) | 150ms cross-continent | Whether synchronous calls become blocking bottlenecks |
|
|
35
|
+
| Duration / Time | Milliseconds | Years of continuous runtime | Memory leaks, state accumulation, index bloat |
|
|
36
|
+
| Failure Rate | Never fails | Always fails | Error handling coverage, circuit breaker needs |
|
|
37
|
+
| Data Size | Empty payload | Terabyte payload | Buffer limits, streaming requirements |
|
|
38
|
+
| Cardinality | 1 tenant / 1 type | 100M tenants / 10K types | Partitioning needs, per-entity overhead |
|
|
39
|
+
| Depth / Nesting | Flat structure | 1000-level deep tree | Stack overflow, recursive algorithm limits |
|
|
40
|
+
| Network | LAN (microseconds) | Satellite link (600ms + packet loss) | Protocol choices, retry logic, idempotency |
|
|
41
|
+
| Cost | Free tier | $1M/month | Whether the design is economically viable at scale |
|
|
42
|
+
| Team Size | 1 engineer | 1000 engineers | Conway's Law — architecture mirrors team communication |
|
|
43
|
+
| Service Composition | 1 service | 150 chained services | Tail latency amplification (see Dynamo case study) |
|
|
44
|
+
|
|
45
|
+
## Process
|
|
46
|
+
|
|
47
|
+
1. **Pick dimension** — What could vary extremely? (Volume, concurrency, time, failure rate, data size, cost, team size)
|
|
48
|
+
2. **Establish baseline** — What does the system do at normal scale? What is "steady state"?
|
|
49
|
+
3. **Test minimum** — What if this was zero, one, or 1000× smaller/faster/fewer?
|
|
50
|
+
4. **Test maximum** — What if this was 1000× bigger/slower/more?
|
|
51
|
+
5. **Note what breaks** — Where do limits appear? What assumptions fail first?
|
|
52
|
+
6. **Note what survives** — What's fundamentally sound regardless of scale?
|
|
53
|
+
7. **Classify the failure mode** — Graceful degradation (slows down, sheds load) or catastrophic collapse (crashes, data loss, cascading failure)?
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
### Example 1: Error Handling
|
|
58
|
+
**Normal scale:** "Handle errors when they occur" seems fine
|
|
59
|
+
**At 0.001% failure rate × 1B requests/day:** = 1M errors/day. Logging each one crashes the log aggregator.
|
|
60
|
+
**Reveals:** Need to make errors impossible (stronger types), batch/sample errors at scale, or design for error as the steady state (chaos engineering mindset)
|
|
61
|
+
|
|
62
|
+
### Example 2: Synchronous APIs
|
|
63
|
+
**Normal scale (single server):** Direct function calls work. 1ms latency is negligible.
|
|
64
|
+
**At global scale (client in Sydney, server in Virginia):** 150ms network latency. Synchronous call blocks a thread for 150ms. At 1000 concurrent users, you need 1000 threads just waiting on network.
|
|
65
|
+
**Reveals:** Async/messaging becomes a survival requirement, not an optimization. A shared lock that takes 1ms at 10 users takes 10 seconds at 10,000 users.
|
|
66
|
+
|
|
67
|
+
### Example 3: In-Memory State
|
|
68
|
+
**Normal duration (hours/days):** Works fine
|
|
69
|
+
**At years of continuous runtime:** A 1KB/request memory leak at 1M requests/day = 1TB accumulated in ~3 years.
|
|
70
|
+
**Reveals:** Need explicit eviction (TTL, LRU), persistence with periodic cleanup, or bounded data structures. Can't rely on "restart to fix."
|
|
71
|
+
|
|
72
|
+
### Example 4: Naive Database Counter
|
|
73
|
+
**Normal scale (100 writes/sec):** `SELECT count, UPDATE count WHERE id=X` works fine
|
|
74
|
+
**At high write scale (100K writes/sec):** Row-level lock creates a bottleneck. All writes serialize. Throughput collapses.
|
|
75
|
+
**Reveals:** Sharded counters (N rows, randomly selected, aggregated on read). Google's AppEngine Sharded Counter is the canonical solution.
|
|
76
|
+
|
|
77
|
+
### Example 5: Monolith to Microservices
|
|
78
|
+
**Small team (5 engineers):** Monolith is fast, simple, easy to refactor
|
|
79
|
+
**At 500 engineers:** Deployment conflicts, slow builds, inability to independently release. Any commit blocks everyone.
|
|
80
|
+
**Reveals:** Conway's Law — system architecture mirrors team communication structure. Scale of *team* is a dimension, not just traffic.
|
|
81
|
+
|
|
82
|
+
### Example 6: Big-O as Algorithmic Scale Game
|
|
83
|
+
**Bubble sort at n=10:** 100 operations, imperceptible
|
|
84
|
+
**Bubble sort at n=1,000,000:** 10^12 operations — days of runtime
|
|
85
|
+
**Binary search at n=1,000,000:** ~20 operations
|
|
86
|
+
**Reveals:** The choice of algorithm doesn't matter at small n. It matters catastrophically at large n. Big-O notation is a formal scale game: classify behavior as n → ∞.
|
|
87
|
+
|
|
88
|
+
### Example 7: Chained Microservices Tail Latency
|
|
89
|
+
**1 service at 99% reliability:** 1% of requests are slow — acceptable
|
|
90
|
+
**100 chained services each at 99% reliability:** `1 - 0.99^100 = 63.4%` of requests hit at least one slow service
|
|
91
|
+
**Reveals:** Tail latency amplifies multiplicatively in service chains. 99% per-service reliability is broken system reliability at scale. Design for P99.9, not P50. (See Dynamo case study below.)
|
|
92
|
+
|
|
93
|
+
## Output Format
|
|
94
|
+
|
|
95
|
+
When doing a scale game analysis, structure findings as:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
Dimension tested: [volume / concurrency / duration / failure rate / cost / ...]
|
|
99
|
+
Current assumption: [what the design assumes]
|
|
100
|
+
At minimum scale: [behavior at zero/one/negligible]
|
|
101
|
+
At maximum scale: [behavior at 1000× / extreme]
|
|
102
|
+
Breaking point: [where the assumption fails]
|
|
103
|
+
Failure mode: [graceful degradation or catastrophic collapse?]
|
|
104
|
+
Insight: [what this reveals about the fundamental design]
|
|
105
|
+
Action: [what to change, verify, or accept as a known limit]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Example output:**
|
|
109
|
+
```
|
|
110
|
+
Dimension tested: duration
|
|
111
|
+
Current assumption: user session tokens cached in memory, evicted on timeout
|
|
112
|
+
At minimum scale: 1 active user — works perfectly
|
|
113
|
+
At maximum scale: 10 years of operation at 1M users/day
|
|
114
|
+
Breaking point: no TTL enforcement → tokens accumulate → OOM crash
|
|
115
|
+
Failure mode: catastrophic (OOM kills process, logs all sessions out)
|
|
116
|
+
Insight: in-memory session store has unbounded growth without explicit eviction
|
|
117
|
+
Action: add TTL + LRU eviction, or move to Redis with expiry
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Common Anti-Patterns
|
|
121
|
+
|
|
122
|
+
- **"It works in dev"** — Dev environments have tiny datasets, no concurrency, no memory pressure, and perfect network
|
|
123
|
+
- **"Should scale fine"** — This phrase without a scale test means "I haven't thought about it"
|
|
124
|
+
- **Only testing happy path scale** — Test failure at scale too. What happens when 10% of dependencies are down simultaneously?
|
|
125
|
+
- **Mistaking load test for stress test** — Load test confirms expected behavior. Stress test finds the failure mode. You need both.
|
|
126
|
+
- **Ignoring the cheap end** — Zero and one are often buggy (empty arrays, single-element edge cases, division by zero)
|
|
127
|
+
- **Forgetting duration** — A system that passes a 1-hour load test may fail after 72 hours of soak testing
|
|
128
|
+
- **Confusing throughput with latency** — High throughput with terrible tail latency is a broken system. Test P99 at scale, not averages.
|
|
129
|
+
- **Stopping at the first breaking point** — Note the breaking point, then ask: does it fail gracefully or catastrophically?
|
|
130
|
+
|
|
131
|
+
## Testing Spectrum (Related Formal Techniques)
|
|
132
|
+
|
|
133
|
+
| Technique | What Scale Is Being Tested | Purpose |
|
|
134
|
+
|-----------|---------------------------|---------|
|
|
135
|
+
| **Load testing** | Volume at expected peak | Confirm system handles projected load |
|
|
136
|
+
| **Stress testing** | Volume beyond expected peak | Find the breaking point and failure mode |
|
|
137
|
+
| **Soak testing** | Duration (hours to days at steady load) | Reveal memory leaks, slow resource accumulation |
|
|
138
|
+
| **Chaos engineering** | Failure rate (random instance/zone/region death) | Validate resilience when components fail |
|
|
139
|
+
| **Property-based testing** | Input space (random + extreme edge cases) | Find cases the developer didn't think to write |
|
|
140
|
+
| **Fermi estimation** | Back-of-envelope across dimensions | Sanity-check before building; identify order-of-magnitude problems |
|
|
141
|
+
|
|
142
|
+
## Non-Software Applications
|
|
143
|
+
|
|
144
|
+
The scale game applies in any domain where assumptions hold at one scale but fail at another:
|
|
145
|
+
|
|
146
|
+
- **Physics:** Newton's laws work at human scales; break at relativistic speeds (Einstein) and quantum scales
|
|
147
|
+
- **Economics:** "More is always better" breaks at scale — a market can have too much liquidity, creating instability
|
|
148
|
+
- **Organizations:** Flat communication works at 10 people; fails at 150 (Dunbar's number) — hierarchy becomes necessary
|
|
149
|
+
- **Security:** A password policy that annoys nobody at 10 users creates massive friction at 10M users, causing workarounds that defeat the policy
|
|
150
|
+
- **Business strategy:** Amazon's "Working Backwards" — writing the press release before the code forces clarity on who the customer is and what success looks like at any scale
|
|
151
|
+
|
|
152
|
+
## Real-World Case Studies
|
|
153
|
+
|
|
154
|
+
Use these as calibration for your own scale estimates — they show how scale assumptions fail in production.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### Pokémon GO: 50× the Expected Launch Traffic (2016)
|
|
159
|
+
|
|
160
|
+
**What they planned:** Niantic estimated 1× baseline traffic, with worst-case at 5×.
|
|
161
|
+
|
|
162
|
+
**What happened:** Within 15 minutes of the Australia/NZ launch, traffic surpassed all projections. Peak hit **50× the original target** — 10× their worst case. The Japan launch had **3× the US launch traffic**. Engineers had to expand Kubernetes clusters in-flight while millions were playing — adding 1,000+ nodes to a live system.
|
|
163
|
+
|
|
164
|
+
**Scale game lesson:** Your "worst case" estimate is rarely the actual worst case. Ask: "What happens at 10× our worst-case estimate?" Make sure the answer is "we add capacity" not "we fail."
|
|
165
|
+
|
|
166
|
+
*Source: Google Cloud blog, "Bringing Pokémon GO to life on Google Cloud," 2016.*
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### Amazon Dynamo: Designing for P99.9, Not the Mean (2007)
|
|
171
|
+
|
|
172
|
+
**The math:** A single page render calls 150+ services. If each has 99% reliability, the probability that *at least one* is slow: `1 - 0.99^150 = 78%`. 78% of page renders hit at least one slow service — even though each service looks healthy in isolation.
|
|
173
|
+
|
|
174
|
+
**Amazon's response:** Measure SLAs at P99.9. Design failure as the **normal case**, not the exception.
|
|
175
|
+
|
|
176
|
+
> *"Many algorithms that perform reasonably well under low load and small datasets can explode in cost if either request rates increase, the dataset grows or the number of nodes in the distributed system increases."*
|
|
177
|
+
> — Werner Vogels
|
|
178
|
+
|
|
179
|
+
**Scale game lesson:** "What is P99.9 latency when 10 services in my call graph are each independently slow?"
|
|
180
|
+
|
|
181
|
+
*Source: Amazon Dynamo paper, SOSP 2007.*
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
### Jeff Dean's Latency Numbers: The Reference Scale Table
|
|
186
|
+
|
|
187
|
+
The canonical reference for reasoning about distributed system scale:
|
|
188
|
+
|
|
189
|
+
| Operation | Latency | Relative to L1 |
|
|
190
|
+
|-----------|---------|----------------|
|
|
191
|
+
| L1 cache reference | 0.5 ns | 1× |
|
|
192
|
+
| L2 cache reference | 7 ns | 14× |
|
|
193
|
+
| Main memory reference | 100 ns | 200× |
|
|
194
|
+
| Read 4K randomly from SSD | 150,000 ns (150 µs) | 300,000× |
|
|
195
|
+
| Round trip within same datacenter | 500,000 ns (500 µs) | 1,000,000× |
|
|
196
|
+
| Disk seek | 10,000,000 ns (10 ms) | 20,000,000× |
|
|
197
|
+
| Send packet CA → Netherlands → CA | 150,000,000 ns (150 ms) | 300,000,000× |
|
|
198
|
+
|
|
199
|
+
**Key insight:** A cross-continental round trip is **300 million times slower** than an L1 cache hit. A disk seek is 20× slower than a datacenter round trip. These numbers determine whether synchronous APIs are viable and whether an algorithm that touches disk can meet a latency SLA.
|
|
200
|
+
|
|
201
|
+
*Source: Jeff Dean / Peter Norvig; GitHub gist jboner/2841832.*
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### Twitter: Temporal Sharding Collapse
|
|
206
|
+
|
|
207
|
+
**Original design:** Tweets from the same date range stored on the same shard — simple, predictable.
|
|
208
|
+
|
|
209
|
+
**At scale:** One shard filled completely every **3 weeks**. Old shards received no traffic (severe load imbalance). The design that was simple at launch became structurally broken at volume — required a full architecture rebuild.
|
|
210
|
+
|
|
211
|
+
**Scale game lesson:** "If our data grows at this rate, how full is each shard in 6 months? 2 years? Who handles writes once the shard is full?" Running that forward projection exposes the collapse point before you build it.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Remember
|
|
216
|
+
|
|
217
|
+
- **Extremes reveal fundamentals** — The scale game is a truth-forcing function
|
|
218
|
+
- **Test both directions** — Bigger AND smaller (zero and one are often the most revealing)
|
|
219
|
+
- **The failure mode matters as much as the breaking point** — Graceful degradation vs. catastrophic collapse
|
|
220
|
+
- **Thought experiments are free** — Most scale analysis takes minutes, not machines
|
|
221
|
+
- **The dimension you don't test is the one that bites you in production**
|
|
222
|
+
- **Big-O is a formal scale game** — If you know the complexity class, you know the scale behavior
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: simplification-cascades
|
|
3
|
+
description: Find one insight that eliminates multiple components - "if this is true, we don't need X, Y, or Z". Use when you see the same concept implemented multiple ways, a growing list of special cases, complexity spiraling with each new requirement, or code that keeps needing "one more" conditional branch. Also use when refactoring feels like whack-a-mole, when a config file keeps growing, or when you suspect a unifying abstraction exists but can't see it yet.
|
|
4
|
+
metadata:
|
|
5
|
+
when_to_use: when implementing the same concept multiple ways, accumulating special cases, complexity is spiraling, or refactoring one thing keeps breaking others
|
|
6
|
+
version: 2.0.0
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Simplification Cascades
|
|
10
|
+
|
|
11
|
+
## What This Is
|
|
12
|
+
|
|
13
|
+
A simplification cascade is a discovery: one unifying insight collapses multiple separate mechanisms, special cases, or components into one. The cascade effect matters — removing one concept makes others unnecessary, which reveals more to remove. The result is systems that are simultaneously smaller *and* more powerful.
|
|
14
|
+
|
|
15
|
+
**Core test:** After the cascade, is there less total code — not just reorganized code?
|
|
16
|
+
|
|
17
|
+
## How the Best Cascades in History Worked
|
|
18
|
+
|
|
19
|
+
These aren't just examples. They're the template:
|
|
20
|
+
|
|
21
|
+
- **Unix "everything is a file"**: Devices, pipes, sockets, processes — one `open/read/write/close` interface replaced dozens of specialized APIs
|
|
22
|
+
- **Lisp "code = data"**: Programs and data share the same representation (S-expressions), making macros natural, reducing the language to ~7 primitives, eliminating a syntax/semantics split
|
|
23
|
+
- **Monads**: What had been separate mechanisms — I/O, error handling, state, async, logging, parsing — became instances of one abstraction
|
|
24
|
+
- **REST**: Resources + uniform interface (GET/POST/PUT/DELETE) replaced the proliferation of SOAP, CORBA, and custom RPC styles
|
|
25
|
+
- **Lambda calculus**: Two operations (abstraction + application) encode all of computation
|
|
26
|
+
|
|
27
|
+
The pattern: someone asked "what if all of these are actually the same thing?" — and the answer was yes.
|
|
28
|
+
|
|
29
|
+
## Quick Diagnostic
|
|
30
|
+
|
|
31
|
+
| Symptom | What to suspect |
|
|
32
|
+
|---------|----------------|
|
|
33
|
+
| Same thing implemented 5+ ways | Abstract the common pattern |
|
|
34
|
+
| `if type == A / B / C / D` everywhere | Find the general case |
|
|
35
|
+
| Complex rules with growing exceptions | Find the rule with no exceptions |
|
|
36
|
+
| Excessive config options | Find defaults that cover 95% |
|
|
37
|
+
| Refactoring feels like whack-a-mole | Missing a unifying concept |
|
|
38
|
+
| "Don't touch that, it's complicated" | Complexity hiding an absent abstraction |
|
|
39
|
+
| "We need one more case..." (repeating) | You haven't found the general case |
|
|
40
|
+
| New requirements always need a new handler | Each requirement exposes missing abstraction |
|
|
41
|
+
|
|
42
|
+
## The Discovery Process
|
|
43
|
+
|
|
44
|
+
Cascades are found bottom-up, not designed top-down. You cannot force one.
|
|
45
|
+
|
|
46
|
+
1. **Accumulate instances** — Don't abstract at 1 or 2 cases; wait for 3. (Fowler's Rule of Three: one is a fact, two is coincidence, three is a pattern.)
|
|
47
|
+
2. **List the variations** — What's actually being implemented multiple ways?
|
|
48
|
+
3. **Ask the unifying question** — "What if these are all instances of the same thing?"
|
|
49
|
+
4. **Find the essence** — What's the same underneath all of them? What's incidental vs. fundamental?
|
|
50
|
+
5. **Extract the abstraction** — What's the domain-independent pattern?
|
|
51
|
+
6. **Test it** — Do all cases fit cleanly, without special-casing?
|
|
52
|
+
7. **Measure the cascade** — Count: how many things become deletable?
|
|
53
|
+
|
|
54
|
+
The discovery usually happens at step 3. Steps 4-7 are execution and validation.
|
|
55
|
+
|
|
56
|
+
## The Net Deletion Test
|
|
57
|
+
|
|
58
|
+
A real cascade reduces total code. If implementation requires significant new infrastructure, that may be a worthwhile trade — but it's not a cascade. Complexity moved is not complexity removed.
|
|
59
|
+
|
|
60
|
+
Ask: "Did we delete more than we wrote?"
|
|
61
|
+
|
|
62
|
+
## False Cascades: When Not to Simplify
|
|
63
|
+
|
|
64
|
+
Not every unification is a simplification. The AHA principle (Avoid Hasty Abstractions) captures the failure mode: the wrong abstraction is worse than duplication.
|
|
65
|
+
|
|
66
|
+
**Warning signs of a false cascade:**
|
|
67
|
+
|
|
68
|
+
| Signal | What it means |
|
|
69
|
+
|--------|--------------|
|
|
70
|
+
| Callers need to know what's underneath to use it correctly | The abstraction leaks — you found the wrong level |
|
|
71
|
+
| Special cases accumulate *around* the new abstraction | You haven't found the general case yet |
|
|
72
|
+
| Net lines of code went *up* | This is a trade, not a cascade |
|
|
73
|
+
| The abstraction is harder to explain than the concrete cases | Complexity moved, not removed |
|
|
74
|
+
| Instances must be bent or coerced to fit | The abstraction precedes the pattern |
|
|
75
|
+
|
|
76
|
+
**Joel Spolsky's addendum**: Even correct simplification cascades don't eliminate underlying complexity — they hide it most of the time. When the abstraction leaks (and eventually it will), you need to understand the layers. The cascade reduces cognitive load day-to-day; it doesn't eliminate the need to understand the substrate in edge cases.
|
|
77
|
+
|
|
78
|
+
## Productive Tension: DRY vs. AHA
|
|
79
|
+
|
|
80
|
+
These two principles aren't contradictions — they describe different moments in the same process:
|
|
81
|
+
|
|
82
|
+
- **DRY / Rule of Three**: Once three instances exist, unify them
|
|
83
|
+
- **AHA / YAGNI**: Don't abstract speculatively; prefer duplication over the wrong abstraction
|
|
84
|
+
|
|
85
|
+
**The resolution**: Duplicate until the right abstraction reveals itself. Then unify. The cascade is the moment when the right abstraction becomes visible. Before that moment, the discipline is *waiting*.
|
|
86
|
+
|
|
87
|
+
## Examples
|
|
88
|
+
|
|
89
|
+
### Cascade 1: Stream Abstraction
|
|
90
|
+
**Before:** Separate handlers for batch, real-time, file, and network data
|
|
91
|
+
**Insight:** "All inputs are streams — just different sources"
|
|
92
|
+
**After:** One stream processor, multiple stream adapters
|
|
93
|
+
**Deleted:** 4 separate implementations, 4 sets of tests, 4 maintenance burdens
|
|
94
|
+
|
|
95
|
+
### Cascade 2: Resource Governance
|
|
96
|
+
**Before:** Session tracking, rate limiting, file validation, connection pooling — all separate systems
|
|
97
|
+
**Insight:** "All are per-entity resource limits"
|
|
98
|
+
**After:** One `ResourceGovernor` with 4 resource types
|
|
99
|
+
**Deleted:** 4 custom enforcement systems and their interaction bugs
|
|
100
|
+
|
|
101
|
+
### Cascade 3: Immutability
|
|
102
|
+
**Before:** Defensive copying, locking, cache invalidation, temporal coupling — handled everywhere
|
|
103
|
+
**Insight:** "Treat everything as immutable data + transformations"
|
|
104
|
+
**After:** Functional patterns; state change = new value
|
|
105
|
+
**Deleted:** Entire classes of synchronization problems
|
|
106
|
+
|
|
107
|
+
## Remember
|
|
108
|
+
|
|
109
|
+
- Cascades are discovered, not designed — accumulate instances first
|
|
110
|
+
- The test is net deletion: less total code, not just reorganized code
|
|
111
|
+
- Complexity moved ≠ complexity removed
|
|
112
|
+
- One powerful abstraction > ten clever hacks
|
|
113
|
+
- The right unification usually feels obvious in retrospect
|