Elegant Code
Elegant code = Correctness + Clarity + Minimal complexity + Natural efficiency + Easy change.
Not "shortest" or "cleverest." The solution that makes readers think: "Of course. That's simple, right, and hard to mess up."
Optimization Priority (in order)
- Correctness & safety — does what it claims, handles edge cases
- Clarity of intent — reader answers "what/why/how" from code itself
- Simplicity — minimal concepts that still solve the problem
- Changeability — modifications are localized and low-risk
- Efficiency — good algorithms; performance from good design, not micro-optimizations
Elegant vs "Smart" Code
| Elegant |
Smart/Clever |
| Clarity & solution |
Cleverness & brevity |
| Humans first |
Machine first (humans decode) |
| Low complexity |
High complexity |
| Easy to debug/change |
Fragile and opaque |
| "Of course!" |
"Wait… how?" |
The Workflow
Use this sequence when writing or refactoring:
1. Clarify the problem
- Define inputs, outputs, invariants, constraints, failure modes
- Identify postconditions (what must be true after)
- List edge cases and "gotchas"
2. Choose simplest correct approach
- Pick simplest algorithm/data structure meeting constraints
- Prefer fewer concepts over more layers
- If adding abstraction, state what complexity it removes
3. Design shape before details
- Outline modules/functions and responsibilities
- Decide boundaries: pure logic vs side effects (I/O, database, network)
4. Write readable-by-default code
- Clear names, small units, straightforward control flow
- Make "happy path" obvious; handle errors intentionally
5. Add guardrails
- Validation, assertions (where appropriate), tests
- Define invalid input handling
6. Refine (remove, simplify, clarify)
- Remove duplication, tighten interfaces, reduce nesting
- Each unit should read like a single thought
7. Verify against reality
- Run tests; benchmark if performance matters
- Confirm behavior matches original problem statement
Core Rules
Rule 1 — Preserve intent above everything
Reader must answer: What does this do? Why? What constraints? What can go wrong?
- Comments explain why, tradeoffs, constraints—not what code does
- If you need comments to explain what, the code is unclear
Rule 2 — Minimize concepts, not lines
Keep distinct "ideas" (types, abstractions, layers, config knobs) minimal.
- Prefer one good function over a mini-framework
- No "future-proofing" without concrete known need
- If abstraction adds indirection without removing complexity, remove it
Rule 3 — Common case simple; edge cases explicit
- Happy path easy to follow
- Edge cases via early returns, guard clauses, explicit validation
- Avoid deep nesting hiding the main story
Rule 4 — Small, cohesive units
- One primary responsibility per function/module/class
- Group related logic; separate unrelated concerns
- If name needs "and" (parseAndSave), it's doing too much
Rule 5 — Explicit data flow over hidden state
- Data through parameters and return values, not globals/singletons/mutable shared state
- If you can't test without elaborate setup, hidden context exists
- If call order matters, make it explicit
Rule 6 — DRY knowledge, not syntax
- Unify if two places must change together
- Allow small obvious repetition if abstraction is harder to read
- Duplicate code sometimes cheaper than leaky abstraction
Rule 7 — Right algorithmic shape
- Choose algorithms/data structures appropriate to constraints
- Prefer clarity unless profiling demands complexity
- Prefer asymptotic wins over micro-optimizations
Rule 8 — Make invalid states unrepresentable
- Represent domain constraints in types/structures so illegal combinations are impossible
- Validate at boundaries, convert to trusted internal representations
Rule 9 — Local reasoning
- Understand a unit without chasing definitions across codebase
- Small interfaces, directness over indirection
- Configuration close to usage or centralized with clear naming
Rule 10 — Idiomatic but readable
- Follow language/project conventions
- Don't use obscure tricks only experts recognize
- If idiom is compact but unclear, choose clearer form
Micro-Rules
Naming
- DO: Names encode intent and domain meaning, not mechanics
- DO: Concrete nouns/verbs:
calculate_total, is_valid, parse_header
- AVOID: Vague names:
data, process, handle, doThing, tmp, manager
- DO: One concept → one term (consistent vocabulary)
Functions
- Short enough for working memory
- Inputs/outputs obvious and stable
- Side effects clear from name or context
- Favor pure functions for core logic
- I/O at edges ("functional core, imperative shell")
Control Flow
- Avoid deep nesting; use guard clauses
- Early exits for invalid conditions
- Straightforward over clever
Error Handling
- Decide: recover, retry, fallback, or fail fast—then implement consistently
- Errors carry enough context to debug
- Validate at boundaries
- Never swallow errors silently
Dependencies
- Depend on stable interfaces, not unstable internals
- Minimal and purposeful dependencies
- Inject dependencies where it improves testability
Self-Review Checklist
Before finalizing code, verify:
Refactor Decision Rules
Refactor if:
- Function/module cannot be summarized in one sentence
- Must read twice to trust it
- One change requires edits in many unrelated places
- Bugs cluster in same area repeatedly
- Keep adding special cases ("just one more flag")
Avoid refactoring if:
- No tests and behavior unclear (add tests first)
- Code stable and rarely changed, improvements purely aesthetic
- Near deadline and risk is high (smallest safe improvements only)
Detailed References
- Measuring elegance: See references/scorecard.md for the elegance scorecard, objective metrics, and improvement checklist
- Anti-patterns: See references/anti-patterns.md for what kills elegance and "smart code" smells
- Continuous improvement: See references/continuous-improvement.md for the Continuous Elegance Loop and practices
1---2name: elegant-code3description: Language-agnostic rulebook for producing, reviewing, and improving elegant code. Use when writing new code, refactoring existing code, reviewing code quality, or when user asks for "elegant", "clean", "maintainable", or "well-structured" code. Applies to any programming language or framework.4---5
6# Elegant Code
7
8Elegant code = **Correctness + Clarity + Minimal complexity + Natural efficiency + Easy change.**
9
10Not "shortest" or "cleverest." The solution that makes readers think: *"Of course. That's simple, right, and hard to mess up."*
11
12## Optimization Priority (in order)
13
141. **Correctness & safety** — does what it claims, handles edge cases
152. **Clarity of intent** — reader answers "what/why/how" from code itself
163. **Simplicity** — minimal concepts that still solve the problem
174. **Changeability** — modifications are localized and low-risk
185. **Efficiency** — good algorithms; performance from good design, not micro-optimizations
19
20## Elegant vs "Smart" Code
21
22| Elegant | Smart/Clever |
23|---------|--------------|
24| Clarity & solution | Cleverness & brevity |
25| Humans first | Machine first (humans decode) |
26| Low complexity | High complexity |
27| Easy to debug/change | Fragile and opaque |
28| "Of course!" | "Wait… how?" |
29
30## The Workflow
31
32Use this sequence when writing or refactoring:
33
34### 1. Clarify the problem
35- Define inputs, outputs, invariants, constraints, failure modes
36- Identify postconditions (what must be true after)
37- List edge cases and "gotchas"
38
39### 2. Choose simplest correct approach
40- Pick simplest algorithm/data structure meeting constraints
41- Prefer fewer concepts over more layers
42- If adding abstraction, state what complexity it removes
43
44### 3. Design shape before details
45- Outline modules/functions and responsibilities
46- Decide boundaries: pure logic vs side effects (I/O, database, network)
47
48### 4. Write readable-by-default code
49- Clear names, small units, straightforward control flow
50- Make "happy path" obvious; handle errors intentionally
51
52### 5. Add guardrails
53- Validation, assertions (where appropriate), tests
54- Define invalid input handling
55
56### 6. Refine (remove, simplify, clarify)
57- Remove duplication, tighten interfaces, reduce nesting
58- Each unit should read like a single thought
59
60### 7. Verify against reality
61- Run tests; benchmark if performance matters
62- Confirm behavior matches original problem statement
63
64## Core Rules
65
66### Rule 1 — Preserve intent above everything
67
68Reader must answer: What does this do? Why? What constraints? What can go wrong?
69
70- Comments explain **why**, tradeoffs, constraints—not what code does
71- If you need comments to explain *what*, the code is unclear
72
73### Rule 2 — Minimize concepts, not lines
74
75Keep distinct "ideas" (types, abstractions, layers, config knobs) minimal.
76
77- Prefer one good function over a mini-framework
78- No "future-proofing" without concrete known need
79- If abstraction adds indirection without removing complexity, remove it
80
81### Rule 3 — Common case simple; edge cases explicit
82
83- Happy path easy to follow
84- Edge cases via early returns, guard clauses, explicit validation
85- Avoid deep nesting hiding the main story
86
87### Rule 4 — Small, cohesive units
88
89- One primary responsibility per function/module/class
90- Group related logic; separate unrelated concerns
91- If name needs "and" (parseAndSave), it's doing too much
92
93### Rule 5 — Explicit data flow over hidden state
94
95- Data through parameters and return values, not globals/singletons/mutable shared state
96- If you can't test without elaborate setup, hidden context exists
97- If call order matters, make it explicit
98
99### Rule 6 — DRY knowledge, not syntax
100
101- Unify if two places must change together
102- Allow small obvious repetition if abstraction is harder to read
103- Duplicate code sometimes cheaper than leaky abstraction
104
105### Rule 7 — Right algorithmic shape
106
107- Choose algorithms/data structures appropriate to constraints
108- Prefer clarity unless profiling demands complexity
109- Prefer asymptotic wins over micro-optimizations
110
111### Rule 8 — Make invalid states unrepresentable
112
113- Represent domain constraints in types/structures so illegal combinations are impossible
114- Validate at boundaries, convert to trusted internal representations
115
116### Rule 9 — Local reasoning
117
118- Understand a unit without chasing definitions across codebase
119- Small interfaces, directness over indirection
120- Configuration close to usage or centralized with clear naming
121
122### Rule 10 — Idiomatic but readable
123
124- Follow language/project conventions
125- Don't use obscure tricks only experts recognize
126- If idiom is compact but unclear, choose clearer form
127
128## Micro-Rules
129
130### Naming
131- **DO**: Names encode intent and domain meaning, not mechanics
132- **DO**: Concrete nouns/verbs: `calculate_total`, `is_valid`, `parse_header`
133- **AVOID**: Vague names: `data`, `process`, `handle`, `doThing`, `tmp`, `manager`
134- **DO**: One concept → one term (consistent vocabulary)
135
136### Functions
137- Short enough for working memory
138- Inputs/outputs obvious and stable
139- Side effects clear from name or context
140- Favor pure functions for core logic
141- I/O at edges ("functional core, imperative shell")
142
143### Control Flow
144- Avoid deep nesting; use guard clauses
145- Early exits for invalid conditions
146- Straightforward over clever
147
148### Error Handling
149- Decide: recover, retry, fallback, or fail fast—then implement consistently
150- Errors carry enough context to debug
151- Validate at boundaries
152- Never swallow errors silently
153
154### Dependencies
155- Depend on stable interfaces, not unstable internals
156- Minimal and purposeful dependencies
157- Inject dependencies where it improves testability
158
159## Self-Review Checklist
160
161Before finalizing code, verify:
162
163- [ ] **Correctness**: Meets requirements; edge cases handled; failures intentional
164- [ ] **Clarity**: Names meaningful; reads top-to-bottom; minimal mental jumps
165- [ ] **Simplicity**: No unnecessary abstractions; minimal moving parts
166- [ ] **Cohesion**: Each unit has one job; responsibilities not mixed
167- [ ] **Coupling**: Dependencies minimal; interfaces small and stable
168- [ ] **Data flow**: Inputs/outputs explicit; minimal hidden state
169- [ ] **Error handling**: Consistent strategy; errors include context
170- [ ] **Efficiency**: Algorithm/data structures fit constraints; no obvious waste
171- [ ] **Consistency**: Patterns match codebase norms
172- [ ] **Testability**: Core logic testable easily; tests exist for tricky parts
173
174## Refactor Decision Rules
175
176**Refactor if:**
177- Function/module cannot be summarized in one sentence
178- Must read twice to trust it
179- One change requires edits in many unrelated places
180- Bugs cluster in same area repeatedly
181- Keep adding special cases ("just one more flag")
182
183**Avoid refactoring if:**
184- No tests and behavior unclear (add tests first)
185- Code stable and rarely changed, improvements purely aesthetic
186- Near deadline and risk is high (smallest safe improvements only)
187
188## Detailed References
189
190- **Measuring elegance**: See [references/scorecard.md](references/scorecard.md) for the elegance scorecard, objective metrics, and improvement checklist
191- **Anti-patterns**: See [references/anti-patterns.md](references/anti-patterns.md) for what kills elegance and "smart code" smells
192- **Continuous improvement**: See [references/continuous-improvement.md](references/continuous-improvement.md) for the Continuous Elegance Loop and practices