OBEY Code Complete by Steve McConnell
Purpose
This repository follows Code Complete in the sense of Steve McConnell:
apply disciplined software construction practices that reduce defects, improve readability, and produce robust code under real-world constraints.
All code generation, edits, and reviews must optimize for:
- low-defect construction
- readable and intention-revealing code
- controlled complexity
- defensive programming where appropriate
- strong routine and class design
- practical correctness over style theater
This file is a binding engineering policy: MUST is binding, SHOULD is a strong default, and MUST NOT is forbidden.
Primary Directive
Construction quality is not accidental.
When uncertain, choose the option that:
- lowers defect probability
- makes the code easier to inspect and reason about
- reduces control-flow complexity
- uses data and routines clearly
- protects the program against invalid states and misuse
Do not optimize for cleverness, minimal keystrokes, or fashionable idioms at the cost of clarity.
Foundational Construction Rules
- Write code primarily for human readers.
- Favor clarity, locality, and explicitness over trickiness.
- Keep control flow simple and visible.
- Make correctness easier to achieve than incorrectness.
- Use conventions consistently.
Construction Prerequisites and Decisions
- Do not treat construction as isolated typing; verify that requirements, architecture, major risks, and coding conventions are clear enough for the change.
- Resolve major construction decisions before large implementation work: language constraints, error policy, data representation, reuse strategy, integration approach, and testing approach.
- Use upstream uncertainty as a reason to build a small validated slice, not as an excuse for speculative code.
- Keep the software metaphor or design model only if it helps make concrete construction decisions.
- Measure twice before cutting when an early decision will be expensive to reverse.
Pseudocode Programming Process
- For complex routines, sketch the routine in precise pseudocode or comments before filling in details.
- Refine pseudocode until it names the real steps at a consistent abstraction level.
- Convert clear pseudocode into code and keep only comments that still add intent, constraints, or rationale.
- Do not use pseudocode as a substitute for understanding the algorithm.
Routine Design Rules
- Routines should have one clear purpose.
- The routine name should describe the result or action precisely.
- Keep the interface as small as practical.
- Avoid long parameter lists and flag arguments.
- Separate setup, validation, computation, and side effects when they are conceptually different.
- Return values should be meaningful and hard to misuse.
- Prefer guard clauses and straightforward structure over deeply nested logic.
Anti-patterns (MUST NOT):
- routines that do several unrelated things
- routines whose names describe implementation detail instead of purpose
- many hidden side effects
- boolean parameters that switch routine mode
Variable and Data Rules
- Use names that reveal purpose and meaning.
- Keep variable scope as small as practical.
- Initialize variables deliberately.
- Prefer named constants or stable values where a variable is not meant to change.
- Avoid magic numbers and unexplained sentinel values.
- Use stronger data types when primitives hide meaning.
Anti-patterns (MUST NOT):
- reused loop/index/temp variables beyond their purpose
- long-lived mutable locals carrying many meanings
- values whose units or semantics are unclear
Data Type Rules
- Choose data types that make invalid or ambiguous values harder to represent.
- Name constants for magic values, units, bounds, and sentinel meanings.
- Use booleans only for true binary meanings; replace flag fields with clearer states when needed.
- Use enumerations or named alternatives when a value belongs to a closed set.
- Use arrays, records, maps, and tables only where their shape communicates the data meaning.
- Encapsulate unusual data structures behind routines or types that reveal purpose.
- Keep units, ranges, precision, encoding, and ownership visible near the data they affect.
Control Flow Rules
- Prefer the simplest control flow that expresses the logic.
- Keep nesting shallow when possible.
- Replace complicated boolean logic with named predicates or clearer structure.
- Use case/switch constructs only when they improve clarity.
- Eliminate impossible paths and dead branches.
- Avoid surprising exits unless they clarify the routine.
Anti-patterns (MUST NOT):
- deeply nested conditionals
- complicated loop exits with hidden state changes
- control flow dependent on side effects in expressions
- clever one-liners that obscure the logic
Statement, Conditional, and Loop Rules
- Organize straight-line code so dependencies appear before use and related statements stay together.
- Keep conditionals positive and direct when possible.
- Put the normal path where readers can find it quickly.
- Use loops with clear initialization, termination, and update rules.
- Keep loop bodies focused; extract work when a loop hides several responsibilities.
- Avoid unusual control structures unless they are clearer than ordinary alternatives.
- Use table-driven methods when repeated branching is stable and the table can be validated.
Defensive Programming Rules
- Validate inputs at trust boundaries.
- Use assertions or invariant checks where programmer assumptions matter.
- Distinguish between recoverable conditions and programming errors.
- Fail in a way that preserves diagnosability.
- Do not silently continue from corrupted or impossible state.
Anti-patterns (MUST NOT):
- assuming all callers are correct
- burying invalid state until it causes distant failures
- swallowing exceptions without context
Error Handling Rules
- Handle errors at the right level of abstraction.
- Preserve useful context.
- Do not let error handling dominate the normal path.
- Standardize similar failure handling.
- Prefer explicit, well-understood failure semantics over ad hoc conventions.
Table-Driven and Data-Driven Rules
- Prefer data-driven logic over long repeated condition chains when the mapping is stable and explicit.
- Use tables or maps for configuration-like decisions.
- Keep the structure obvious and validated.
- Do not hide complex logic in inscrutable data encodings.
Class and Module Design Rules
- Each class or module should own a focused responsibility.
- Separate interface from implementation.
- Hide representation and incidental detail.
- Keep classes cohesive.
- Reduce coupling through clear contracts and limited knowledge of internals.
Anti-patterns (MUST NOT):
- god classes
- modules with mixed persistence, formatting, business logic, and integration concerns
- public surfaces that expose internal bookkeeping
Complexity Management Rules
- Treat rising complexity as a defect risk.
- Prefer simple code over clever code.
- Break apart large or tangled routines and modules.
- Remove duplication that multiplies maintenance effort.
- Choose designs that reduce the amount a maintainer must keep in working memory.
Construction with Preconditions and Postconditions
- Be explicit about routine assumptions.
- Encode important invariants close to the code they protect.
- Keep contracts simple and testable.
- Use assertions for programmer mistakes, validation for external input, and domain errors for expected business failures.
Comment Rules
- Comments should explain intent, rationale, contracts, and non-obvious facts.
- Do not comment obvious code instead of improving it.
- Keep comments accurate or delete them.
- Prefer self-documenting structure first, comments second.
Coding Standards Rules
- Be consistent within the codebase.
- Use formatting, naming, and file structure to support readability.
- Standardize common idioms so readers do not need to relearn style per module.
- Prefer a shared convention over local personal taste.
Incremental Construction Rules
- Build in small, verifiable increments.
- Integrate frequently enough to surface conflicts and misunderstanding early.
- Keep partial work from rotting in long-lived isolation.
- Review and improve code as part of construction, not only after it.
Quality, Collaboration, Debugging, and Refactoring
- Use reviews, inspections, pair work, tests, and static checks according to the risk of the code.
- Treat debugging as diagnosis: reproduce, isolate, explain, fix, and verify rather than guessing.
- Fix the root cause when practical, not only the symptom.
- Add tests around defects so the same failure is easier to detect next time.
- Refactor when structure hides intent, duplicates knowledge, or raises defect probability.
- Keep refactoring separate from behavior changes when that improves reviewability.
Performance, Integration, Tools, and Craftsmanship
- Do not tune performance until the requirement and evidence justify it.
- When tuning is justified, measure before and after, and keep clarity unless the tradeoff is explicit.
- Integrate frequently enough to expose construction conflicts early.
- Use programming tools, scripts, debuggers, profilers, editors, and build automation to reduce error-prone manual work.
- Keep layout and style consistent enough that readers can focus on meaning.
- Prefer self-documenting code, but add documentation where the code cannot express intent, constraints, or usage.
- Treat personal discipline, curiosity, and ability to withstand careful review as part of construction quality.
Review Rules
When reviewing code, actively look for:
- unclear names
- weak routine boundaries
- long parameter lists
- unnecessary nesting
- hidden side effects
- poor defensive checks at trust boundaries
- duplicated logic
- confusing control flow
- god classes or mixed responsibilities
- comments compensating for poor structure
Forbidden Patterns
Cleverness over Clarity
- dense tricks that are hard to inspect
- compressed expressions that save lines but increase interpretation cost
Routine Bloat
- one routine doing several phases and concerns
- long signatures with many unrelated parameters
Defensive Vacuum
- no validation at trust boundaries
- no checks around critical assumptions
- silent fallback from impossible state
Comment-as-Crutch
- obvious comments over bad code
- stale comments that mislead
Consistency Neglect
- arbitrary naming and formatting changes
- module-specific mini dialects inside one codebase
Code Generation Rules
When generating code, default to:
- clear names
- focused routines
- explicit data meaning
- simple control flow
- defensive checks at boundaries
- cohesive classes/modules
- consistent style
Avoid by default:
- dense clever code
- broad god objects
- fragile hidden assumptions
- unnecessary complexity in loops and conditionals
- comments where better names or decomposition would do
Testing Rules
- Test routine behavior around normal, boundary, and invalid inputs.
- Test defensive checks where boundary validation matters.
- Keep tests aligned with routine contracts.
- Test complex data-driven logic with representative tables and edge cases.
Review Checklist
Before finalizing any change, verify:
- Are names clear and intention-revealing?
- Are routines focused and reasonably small?
- Is control flow straightforward?
- Are trust boundaries defended?
- Are contracts and invariants explicit enough?
- Did we reduce or at least not increase complexity?
- Are classes/modules cohesive?
- Did we avoid cleverness that harms inspection?
- Are comments used only where they add value?
- Is the style consistent with the rest of the codebase?
If any answer is no, revise before shipping.
Final Instruction
When uncertain, choose the option that:
- lowers defect risk
- improves readability
- simplifies control flow
- strengthens defensive correctness
- keeps the code easier to inspect and maintain
Write code that would stand up to careful review.
1---2name: book-code-complete-full3description: Code Complete (Steve McConnell) — Full rules — comprehensive mandatory coding standards. Use when asked to apply Code Complete principles or review code against Code Complete standards.4license: MIT5---6
7# OBEY Code Complete by Steve McConnell
8
9## Purpose
10
11This repository follows **Code Complete** in the sense of Steve McConnell:
12apply disciplined software construction practices that reduce defects, improve readability, and produce robust code under real-world constraints.
13
14All code generation, edits, and reviews must optimize for:
15- low-defect construction
16- readable and intention-revealing code
17- controlled complexity
18- defensive programming where appropriate
19- strong routine and class design
20- practical correctness over style theater
21
22This file is a binding engineering policy: `MUST` is binding, `SHOULD` is a strong default, and `MUST NOT` is forbidden.
23
24---
25
26## Primary Directive
27
28Construction quality is not accidental.
29
30When uncertain, choose the option that:
311. lowers defect probability
322. makes the code easier to inspect and reason about
333. reduces control-flow complexity
344. uses data and routines clearly
355. protects the program against invalid states and misuse
36
37Do not optimize for cleverness, minimal keystrokes, or fashionable idioms at the cost of clarity.
38
39---
40
41## Foundational Construction Rules
42
431. Write code primarily for human readers.
442. Favor clarity, locality, and explicitness over trickiness.
453. Keep control flow simple and visible.
464. Make correctness easier to achieve than incorrectness.
475. Use conventions consistently.
48
49---
50
51## Construction Prerequisites and Decisions
52
531. Do not treat construction as isolated typing; verify that requirements, architecture, major risks, and coding conventions are clear enough for the change.
542. Resolve major construction decisions before large implementation work: language constraints, error policy, data representation, reuse strategy, integration approach, and testing approach.
553. Use upstream uncertainty as a reason to build a small validated slice, not as an excuse for speculative code.
564. Keep the software metaphor or design model only if it helps make concrete construction decisions.
575. Measure twice before cutting when an early decision will be expensive to reverse.
58
59---
60
61## Pseudocode Programming Process
62
631. For complex routines, sketch the routine in precise pseudocode or comments before filling in details.
642. Refine pseudocode until it names the real steps at a consistent abstraction level.
653. Convert clear pseudocode into code and keep only comments that still add intent, constraints, or rationale.
664. Do not use pseudocode as a substitute for understanding the algorithm.
67
68---
69
70## Routine Design Rules
71
721. Routines should have one clear purpose.
732. The routine name should describe the result or action precisely.
743. Keep the interface as small as practical.
754. Avoid long parameter lists and flag arguments.
765. Separate setup, validation, computation, and side effects when they are conceptually different.
776. Return values should be meaningful and hard to misuse.
787. Prefer guard clauses and straightforward structure over deeply nested logic.
79
80Anti-patterns (MUST NOT):
81- routines that do several unrelated things
82- routines whose names describe implementation detail instead of purpose
83- many hidden side effects
84- boolean parameters that switch routine mode
85
86---
87
88## Variable and Data Rules
89
901. Use names that reveal purpose and meaning.
912. Keep variable scope as small as practical.
923. Initialize variables deliberately.
934. Prefer named constants or stable values where a variable is not meant to change.
945. Avoid magic numbers and unexplained sentinel values.
956. Use stronger data types when primitives hide meaning.
96
97Anti-patterns (MUST NOT):
98- reused loop/index/temp variables beyond their purpose
99- long-lived mutable locals carrying many meanings
100- values whose units or semantics are unclear
101
102---
103
104## Data Type Rules
105
1061. Choose data types that make invalid or ambiguous values harder to represent.
1072. Name constants for magic values, units, bounds, and sentinel meanings.
1083. Use booleans only for true binary meanings; replace flag fields with clearer states when needed.
1094. Use enumerations or named alternatives when a value belongs to a closed set.
1105. Use arrays, records, maps, and tables only where their shape communicates the data meaning.
1116. Encapsulate unusual data structures behind routines or types that reveal purpose.
1127. Keep units, ranges, precision, encoding, and ownership visible near the data they affect.
113
114---
115
116## Control Flow Rules
117
1181. Prefer the simplest control flow that expresses the logic.
1192. Keep nesting shallow when possible.
1203. Replace complicated boolean logic with named predicates or clearer structure.
1214. Use case/switch constructs only when they improve clarity.
1225. Eliminate impossible paths and dead branches.
1236. Avoid surprising exits unless they clarify the routine.
124
125Anti-patterns (MUST NOT):
126- deeply nested conditionals
127- complicated loop exits with hidden state changes
128- control flow dependent on side effects in expressions
129- clever one-liners that obscure the logic
130
131---
132
133## Statement, Conditional, and Loop Rules
134
1351. Organize straight-line code so dependencies appear before use and related statements stay together.
1362. Keep conditionals positive and direct when possible.
1373. Put the normal path where readers can find it quickly.
1384. Use loops with clear initialization, termination, and update rules.
1395. Keep loop bodies focused; extract work when a loop hides several responsibilities.
1406. Avoid unusual control structures unless they are clearer than ordinary alternatives.
1417. Use table-driven methods when repeated branching is stable and the table can be validated.
142
143---
144
145## Defensive Programming Rules
146
1471. Validate inputs at trust boundaries.
1482. Use assertions or invariant checks where programmer assumptions matter.
1493. Distinguish between recoverable conditions and programming errors.
1504. Fail in a way that preserves diagnosability.
1515. Do not silently continue from corrupted or impossible state.
152
153Anti-patterns (MUST NOT):
154- assuming all callers are correct
155- burying invalid state until it causes distant failures
156- swallowing exceptions without context
157
158---
159
160## Error Handling Rules
161
1621. Handle errors at the right level of abstraction.
1632. Preserve useful context.
1643. Do not let error handling dominate the normal path.
1654. Standardize similar failure handling.
1665. Prefer explicit, well-understood failure semantics over ad hoc conventions.
167
168---
169
170## Table-Driven and Data-Driven Rules
171
1721. Prefer data-driven logic over long repeated condition chains when the mapping is stable and explicit.
1732. Use tables or maps for configuration-like decisions.
1743. Keep the structure obvious and validated.
1754. Do not hide complex logic in inscrutable data encodings.
176
177---
178
179## Class and Module Design Rules
180
1811. Each class or module should own a focused responsibility.
1822. Separate interface from implementation.
1833. Hide representation and incidental detail.
1844. Keep classes cohesive.
1855. Reduce coupling through clear contracts and limited knowledge of internals.
186
187Anti-patterns (MUST NOT):
188- god classes
189- modules with mixed persistence, formatting, business logic, and integration concerns
190- public surfaces that expose internal bookkeeping
191
192---
193
194## Complexity Management Rules
195
1961. Treat rising complexity as a defect risk.
1972. Prefer simple code over clever code.
1983. Break apart large or tangled routines and modules.
1994. Remove duplication that multiplies maintenance effort.
2005. Choose designs that reduce the amount a maintainer must keep in working memory.
201
202---
203
204## Construction with Preconditions and Postconditions
205
2061. Be explicit about routine assumptions.
2072. Encode important invariants close to the code they protect.
2083. Keep contracts simple and testable.
2094. Use assertions for programmer mistakes, validation for external input, and domain errors for expected business failures.
210
211---
212
213## Comment Rules
214
2151. Comments should explain intent, rationale, contracts, and non-obvious facts.
2162. Do not comment obvious code instead of improving it.
2173. Keep comments accurate or delete them.
2184. Prefer self-documenting structure first, comments second.
219
220---
221
222## Coding Standards Rules
223
2241. Be consistent within the codebase.
2252. Use formatting, naming, and file structure to support readability.
2263. Standardize common idioms so readers do not need to relearn style per module.
2274. Prefer a shared convention over local personal taste.
228
229---
230
231## Incremental Construction Rules
232
2331. Build in small, verifiable increments.
2342. Integrate frequently enough to surface conflicts and misunderstanding early.
2353. Keep partial work from rotting in long-lived isolation.
2364. Review and improve code as part of construction, not only after it.
237
238---
239
240## Quality, Collaboration, Debugging, and Refactoring
241
2421. Use reviews, inspections, pair work, tests, and static checks according to the risk of the code.
2432. Treat debugging as diagnosis: reproduce, isolate, explain, fix, and verify rather than guessing.
2443. Fix the root cause when practical, not only the symptom.
2454. Add tests around defects so the same failure is easier to detect next time.
2465. Refactor when structure hides intent, duplicates knowledge, or raises defect probability.
2476. Keep refactoring separate from behavior changes when that improves reviewability.
248
249---
250
251## Performance, Integration, Tools, and Craftsmanship
252
2531. Do not tune performance until the requirement and evidence justify it.
2542. When tuning is justified, measure before and after, and keep clarity unless the tradeoff is explicit.
2553. Integrate frequently enough to expose construction conflicts early.
2564. Use programming tools, scripts, debuggers, profilers, editors, and build automation to reduce error-prone manual work.
2575. Keep layout and style consistent enough that readers can focus on meaning.
2586. Prefer self-documenting code, but add documentation where the code cannot express intent, constraints, or usage.
2597. Treat personal discipline, curiosity, and ability to withstand careful review as part of construction quality.
260
261---
262
263## Review Rules
264
265When reviewing code, actively look for:
266- unclear names
267- weak routine boundaries
268- long parameter lists
269- unnecessary nesting
270- hidden side effects
271- poor defensive checks at trust boundaries
272- duplicated logic
273- confusing control flow
274- god classes or mixed responsibilities
275- comments compensating for poor structure
276
277---
278
279## Forbidden Patterns
280
281### Cleverness over Clarity
282- dense tricks that are hard to inspect
283- compressed expressions that save lines but increase interpretation cost
284
285### Routine Bloat
286- one routine doing several phases and concerns
287- long signatures with many unrelated parameters
288
289### Defensive Vacuum
290- no validation at trust boundaries
291- no checks around critical assumptions
292- silent fallback from impossible state
293
294### Comment-as-Crutch
295- obvious comments over bad code
296- stale comments that mislead
297
298### Consistency Neglect
299- arbitrary naming and formatting changes
300- module-specific mini dialects inside one codebase
301
302---
303
304## Code Generation Rules
305
306When generating code, default to:
3071. clear names
3082. focused routines
3093. explicit data meaning
3104. simple control flow
3115. defensive checks at boundaries
3126. cohesive classes/modules
3137. consistent style
314
315Avoid by default:
316- dense clever code
317- broad god objects
318- fragile hidden assumptions
319- unnecessary complexity in loops and conditionals
320- comments where better names or decomposition would do
321
322---
323
324## Testing Rules
325
3261. Test routine behavior around normal, boundary, and invalid inputs.
3272. Test defensive checks where boundary validation matters.
3283. Keep tests aligned with routine contracts.
3294. Test complex data-driven logic with representative tables and edge cases.
330
331---
332
333## Review Checklist
334
335Before finalizing any change, verify:
336- Are names clear and intention-revealing?
337- Are routines focused and reasonably small?
338- Is control flow straightforward?
339- Are trust boundaries defended?
340- Are contracts and invariants explicit enough?
341- Did we reduce or at least not increase complexity?
342- Are classes/modules cohesive?
343- Did we avoid cleverness that harms inspection?
344- Are comments used only where they add value?
345- Is the style consistent with the rest of the codebase?
346
347If any answer is no, revise before shipping.
348
349---
350
351## Final Instruction
352
353When uncertain, choose the option that:
3541. lowers defect risk
3552. improves readability
3563. simplifies control flow
3574. strengthens defensive correctness
3585. keeps the code easier to inspect and maintain
359
360Write code that would stand up to careful review.