ryanthedev/code-foundations/cc-defensive-programming
Claude Code and agent skill by ryanthedev/code-foundations
- community
Checking that the SKILL.md file is still in the repository.
Applies Code Complete's defensive programming rules: barricade design, assertion vs error-handling selection, input validation policy, and correctness-vs-robustness strategy for the current context. For hardening code at trust boundaries; not for diagnosing an active failure (use cc-debugging) or post-completion verification (use aposd-verifying-correctness).
Install
npx vskill@latest install ryanthedev/code-foundations/cc-defensive-programmingSKILL.md
cc-defensive-programming
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) |
Two rules that override the textbook
- "Internal team API" is still external. Any data crossing a network or process boundary is external input — validate it, even from a service your own team owns.
- A barricade reduces redundant validation; it does not replace defense-in-depth. Inside the barricade you may assume data is validated — except for security-critical paths (auth, crypto, PII), where you validate again. Barricade validation has bugs too.
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.
When NOT to apply
- Pure functions without side effects (but still validate inputs at system boundaries).
- Prototype/spike code, time-boxed before committing to an error strategy.
- Test code — test doubles intentionally violate production patterns.
- Performance-critical inner loops where assertion overhead is profiled at >5%.
Security-critical code (authentication, authorization, cryptographic operations, PII handling) is never exempt, regardless of the above. When in doubt, validate.
Modes
CHECKER
Execute the defensive-programming, assertion, and exception checklists against the code: Read(${CLAUDE_SKILL_DIR}/checklists.md). VIOLATION = missing validation, empty catch, side-effecting assertion; WARNING = inconsistent handling, missing docs. CHECKER output: the ID'd checklist is the item set (the tables in this SKILL.md explain the items, they are not counted twice). Report each VIOLATION and WARNING as | Item | Status | Evidence | Location |; do not list passing or non-applicable items — close with one line N items checked, M pass, K n/a.
APPLIER
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.
Assertion vs error handling
| 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.
Correctness vs robustness
- Correctness — never return an inaccurate result; shut down rather than produce a wrong answer (safety-critical, financial, data pipelines).
- Robustness — keep operating even if results are sometimes inaccurate (consumer apps, internal tools).
| 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? |
Barricade design
- Identify external interfaces (user input, files, network, APIs, inter-service calls).
- Place validation at the barricade boundary — all external data checked here.
- Inside the barricade, use assertions for internal bugs (data assumed validated).
- Strategy: external boundary = error handling; internal = assertions.
Class-level barricade: public methods validate and sanitize; private methods within that class may assume safe data.
Error-handling strategy options
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 |
Modern error propagation
Synchronous exception propagation assumes a synchronous call stack; these patterns need explicit handling:
- async/await — an unhandled rejection crashes Node; wrap awaited calls and re-throw domain-level exceptions.
- Callbacks — errors don't propagate; use the error-first
callback(error, result)pattern or wrap in promises. - `Promise.all` — first rejection loses other results; use
allSettledand decide fail-entirely vs partial. - Event handlers / React — synchronous throws are silently swallowed; log explicitly and use error boundaries for render errors.
Offensive programming (development builds)
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.
Security
- Security scanPassed, 82 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/cc-defensive-programming/SKILL.md
Popularity
- Repository stars
- 172
- Repository forks
- 15
- 7-day trend score
- 26
Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 20 Mar 2026, 7 months ago.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/ryanthedev/code-foundations/cc-defensive-programming)