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.
Enforces engineering safety and maintainability rules including trajectory freeze, clarification triggers, and uncertainty thresholds for code edits, refactoring, and git workflows.
Implements defense-in-depth validation across entry points, business logic, environment guards, and debug instrumentation to prevent invalid data failures deep in execution stacks.