caching
Use when same data is fetched repeatedly. Use when database queries are slow. Use when implementing caching without invalidation strategy.
composition-over-inheritance
Use when tempted to use class inheritance. Use when creating class hierarchies. Use when subclass needs only some parent behavior.
aaa-pattern
Use when writing tests. Use when test structure is unclear. Use when arrange/act/assert phases are mixed.
api-versioning
Use when designing or modifying APIs. Use when adding breaking changes. Use when clients depend on API stability.
auth-patterns
Use when implementing authentication. Use when storing passwords. Use when asked to store credentials insecurely.
deadlock-prevention
Use when acquiring multiple locks. Use when operations wait for each other. Use when system hangs without crashing.
dependency-inversion-principle
Use when a class creates its own dependencies. Use when instantiating concrete implementations inside a class. Use when told to avoid dependency injection for simplicity.
dont-repeat-yourself
Use when writing similar code in multiple places. Use when copy-pasting code. Use when making the same change in multiple locations.
encapsulation
Use when exposing internal state. Use when making fields public for convenience. Use when external code modifies object internals.
error-boundaries
Use when deciding where to catch errors. Use when errors propagate too far or not far enough. Use when designing component/service isolation.
error-responses
Use when returning errors from APIs. Use when exposing internal errors. Use when error responses lack structure.
exception-hierarchies
Use when creating custom exceptions. Use when error handling feels chaotic. Use when catch blocks are too broad or too specific.
fail-fast
Use when handling errors. Use when tempted to catch and swallow exceptions. Use when returning default values to hide failures.
idempotency
Use when creating mutation endpoints. Use when trusting frontend to prevent duplicates. Use when payments or critical operations can be repeated.
immutability
Use when modifying objects or arrays. Use when tempted to mutate function parameters. Use when state changes cause unexpected bugs.
input-validation
Use when accepting user input. Use when handling request data. Use when trusting external data without validation.
interface-segregation-principle
Use when designing interfaces. Use when implementing interfaces with methods you don't need. Use when forced to implement throw/no-op for interface methods.
keep-it-simple
Use when tempted to write clever code. Use when solution feels complex. Use when showing off skills instead of solving problems.
law-of-demeter
Use when accessing nested object properties. Use when chaining method calls. Use when reaching through objects to get data.
lazy-loading
Use when loading all data upfront. Use when initial page load is slow. Use when fetching data that might not be needed.
liskov-substitution-principle
Use when creating subclasses or implementing interfaces. Use when tempted to override methods with exceptions or no-ops. Use when inheritance hierarchy feels wrong.
n-plus-one-prevention
Use when fetching related data in loops. Use when seeing multiple queries for one request. Use when database is slow on list endpoints.
open-closed-principle
Use when adding new functionality to existing code. Use when tempted to add if/else or switch branches. Use when extending behavior of existing classes.
race-conditions
Use when multiple operations access shared state. Use when order of operations matters. Use when "it works most of the time" but occasionally fails mysteriously.
rest-conventions
Use when designing API endpoints. Use when using wrong HTTP methods. Use when POST is used for reads.
secrets-handling
Use when working with API keys, passwords, or credentials. Use when asked to hardcode secrets. Use when secrets might leak.
separation-of-concerns
Use when component does too many things. Use when mixing data fetching, logic, and presentation. Use when code is hard to test.
single-responsibility-principle
Use when creating or modifying classes, modules, or functions. Use when feeling pressure to add functionality to existing code. Use when class has multiple reasons to change.
skill-awareness
Always active. Tracks usage of code-craft skills across sessions. Log skill applications to enable analytics and identify gaps.
test-driven-development
Use when implementing any new feature or function. Use when asked to "add tests later". Use when writing code before tests.
test-isolation
Use when writing tests that share state. Use when tests depend on other tests. Use when test order matters.
you-aint-gonna-need-it
Use when tempted to add features "for later". Use when building "production-ready" systems before needed. Use when adding flexibility that isn't required yet.