Coding Effectively
Correctness over convenience
Model the full error space, not the path you had in mind. Handle every edge case — race conditions, timing issues, partial failures. Encode constraints in the type system, and prefer compile-time guarantees to runtime checks. Never bypass the type system to silence a compiler error (as any, unchecked casts). When uncertain, explore and iterate rather than assume.
Error handling
Never swallow an error. Every error is one of three things:
- Recoverable locally — handle it
- Unrecoverable locally — pass it up the stack
- Non-critical — log it, increment a metric, or both
Two tiers: user-facing errors get semantic exit codes, rich diagnostics, and actionable messages. Internal errors are programming errors, and may panic or use internal types. Never emit a generic message where the specific cause is known.
Message format — lowercase sentence fragments, so that "operation failed: " + error.message composes:
Good: failed to connect to database: connection refused
Bad: Failed to Connect to Database: Connection Refused
Design
- Don't abstract until you have seen the pattern three times. Three similar lines beat a premature abstraction.
- Prefer specific, composable logic over abstract frameworks.
- Evolve the design incrementally rather than perfecting it upfront, and don't build for hypothetical future requirements.
- Document the trade-off when making a non-obvious choice.
Before implementing a feature, read references/property-driven-design.md. Property questions surface design gaps — deleted entities, case sensitivity, tie-breaking — during design rather than during debugging.
File organization
- Name files for what they contain, never a generic category:
string-formatting.ts,date-arithmetic.ts,user-validation.ts, notutils.tsorhelpers.ts. When tempted to create one of those, ask what the functions have in common and name the file after that. - Keep module boundaries strict, with restricted visibility.
- Platform-specific code goes in its own file:
unix.ts,windows.ts,posix.ts, selected by conditional compilation or a runtime check. - Test helpers belong in dedicated modules, not mixed into production code.
- Prefer many small files to a few large ones.
Style
- Keep the happy path left-aligned. Return early instead of nesting.
- Declare identifiers in the files that need them; export or make public only when something else needs them.
- Declare variables close to their usage.
- Limit assignment scope — reassignment and shadowing cause subtle bugs.
Code comments
REQUIRED: Load the 'house-style-code-comments' skill for the comment policy.