From code-foundations
Applies Code Complete defensive programming: barricade design, assertion vs error-handling, input validation policy, and correctness-vs-robustness strategy for the current code context.
How this skill is triggered — by the user, by Claude, or both
Slash command
/code-foundations:cc-defensive-programmingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Defensive code keeps small failures from compounding into silent, hard-to-diagnose ones. These four checks catch the violations that corrupt data and hide bugs rather than crashing loudly — each is almost always required; exceptions need explicit justification:
Defensive code keeps small failures from compounding into silent, hard-to-diagnose ones. These four checks catch the violations that corrupt data and hide bugs rather than crashing loudly — each is almost always required; exceptions need explicit justification:
| Check | Why |
|---|---|
| No executable code in assertions | Assertions are compiled out of production builds; the code vanishes with them |
| No empty catch blocks | Silently swallows bugs that cascade into harder failures downstream |
| External input validated at entry | Unvalidated input is security vulnerabilities and data corruption |
| Assertions for bugs only | Anticipated runtime errors need handling, not assertions (which are disabled in production) |
Shared thresholds and the information-hiding rationale: Read(${CLAUDE_PLUGIN_ROOT}/references/cc-foundations.md).
External input = any data not provably controlled by the current code path: user input, files, network/API/DB responses, environment variables, and data from any other service.
Security-critical code (authentication, authorization, cryptographic operations, PII handling) is never exempt, regardless of the above. When in doubt, validate.
Execute the defensive-programming, assertion, and exception checklists against the code: Read(${CLAUDE_SKILL_DIR}/checklists.md). Output one row per item: | Item | Status | Evidence | Location |, status ∈ VIOLATION (missing validation, empty catch, side-effecting assertion) / WARNING (inconsistent handling, missing docs) / PASS.
Produce assertion placement, error-handling strategy, barricade architecture, and validation implementations. Search the codebase for the existing error-handling pattern (exception vs return code vs Result type, custom exception classes, logging conventions) and follow it — consistency in error handling is what makes failures debuggable. Full gate: Read(${CLAUDE_PLUGIN_ROOT}/references/pattern-reuse-gate.md).
| Condition | Assertion | Error handling |
|---|---|---|
| Should never occur (programmer bug) | Yes | No |
| Can occur at runtime / anticipated bad input | No | Yes |
| External input | No | Yes — always validate |
| Internal interface, same module | Yes | No |
| Internal interface crossing a trust boundary | Yes | Yes |
| Public-API precondition violation | Yes | Yes |
| Security-critical / highly robust system | Both | Both (defense in depth) |
When a condition is genuinely unclear ("is this a bug or expected?"), clarify requirements with a domain expert rather than guessing.
| Domain | Lean toward | Key question |
|---|---|---|
| Safety-critical (medical, aviation) | Correctness | — |
| Enterprise/B2B, financial, data pipelines | Correctness | Would wrong data drive a bad business decision? Does downstream assume integrity? |
| SaaS platforms | Balanced | Blast radius of a wrong answer vs unavailability? |
| Consumer apps, internal tools | Robustness | Can the user recover from a crash? |
| Real-time systems | Context-dependent | Is stale data better or worse than no data? |
Class-level barricade: public methods validate and sanitize; private methods within that class may assume safe data.
Choose one and apply it consistently — error handling is an architectural decision.
| Strategy | Use for |
|---|---|
| Return neutral value | Display defaults, non-critical config |
| Substitute next valid data | Streaming/sensor data with redundancy |
| Return previous answer | Display refresh, non-critical caching (never financial data) |
| Substitute closest legal value | Input clamping, slider bounds |
| Log warning and continue | Non-critical degradation, feature flags |
| Return error code | APIs with status conventions, C-style interfaces |
| Centralized error handler | Consistent logging, monitoring integration |
| Display error message | User-facing apps (don't leak security info) |
| Shut down gracefully | Safety-critical, data-corrupting errors |
Synchronous exception propagation assumes a synchronous call stack; these patterns need explicit handling:
callback(error, result) pattern or wrap in promises.Promise.all — first rejection loses other results; use allSettled and decide fail-entirely vs partial.Make errors loud during development so they're found early; make them unobtrusive with graceful recovery in production. Techniques: make asserts abort, fill allocated memory and freed objects with junk, fail hard on default/else clauses, email error logs to yourself.
| After | Next |
|---|---|
| Validation complete | Skill(code-foundations:cc-control-flow-quality) |
npx claudepluginhub ryanthedev/code-foundationsAsserts internal assumptions (preconditions, postconditions, invariants) in functions, modules, or services to crash loudly at the violation site rather than propagating corrupt state downstream.
Implements defense-in-depth validation across entry points, business logic, environment guards, and debug instrumentation to prevent invalid data failures deep in execution stacks.
Strategies for handling errors: exceptions, error types, recovery strategies, and error propagation.