Typed Key-Value Memoisation
A cache without typed keys and typed values is a hash map of strings against strings — and the bugs that creep in are inevitably about a key that was supposed to be parsed back into an entity id but never was, or a value that was supposed to be deserialised but came back as a string. @frenchexdev/ddd-cache reifies the cache as a typed port with memory and Redis adapters so the typing survives the round trip.
What Cache Reifies
The cache is the simplest port in the corpus — get, set, delete, invalidate, optional TTL — but the discipline it enforces matters. The cache is never the source of truth. A cache miss must always fall through to a source (a repository, a read model, a projection), and a cache write must always follow a successful source write. Read-through caching is the default shape: the application asks the cache for customer:cu_abc, the cache returns the value or hands a callback to the source, the source returns the customer, the cache stores it for next time with a TTL.
The hard part is invalidation. Two operational regimes — process-local memory and shared Redis — have different invalidation cost profiles. The memory adapter's invalidate(pattern) is instant but only affects the local process; the Redis adapter's invalidate(pattern) is visible across replicas but costs a network round-trip. The corpus does not pick a policy; the port exposes the operations, the team decides whether the application invalidates on every aggregate write or relies on TTL expiry.
The Runtime: ddd-cache and adapters
Three packages — ddd-cache, ddd-cache-memory-adapter, ddd-cache-redis-adapter — all M4/M5 stubs pinned to CacheReadThroughRequirement.
The Analyzer: ddd-cache-analyzer
Spec-first (spec.ts). Priority Medium. One info-severity rule, DDD-CACHE-001, recommending the Cache suffix on the port class. The single-rule analyzer is the smallest spec in the corpus — caching is structurally simple; the operational complexity is in the team's invalidation discipline, not in the port shape.
Cross-Links
- Wraps reads from
@Repository— the read-through callback hits the repository on miss. - Invalidated by
@CommandHandlers after the aggregate write succeeds. - May accelerate
@ReadModelqueries served by@QueryHandlers. - Lives behind
@Port/@Adapter; the conformance suite enforces the invalidate-replace semantics consistently across substrates.
Back to the series index.