Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Cache reads/writes must degrade gracefully, not crash the request
Isolate cache get/set/parse in their own try/catch so a cache outage or corrupt entry falls back to a fresh fetch with a warning instead of failing the whole operation.
Bad example
| 1 | async function fetchWithCache<T>(key: string, ttl: number, fetcher: () => Promise<T>): Promise<T> { |
| 2 | const cached = await cache.get(key); // cache outage -> throws |
| 3 | if (cached) return JSON.parse(cached) as T; // corrupt entry -> throws |
| 4 | const data = await fetcher(); |
| 5 | await cache.set(key, JSON.stringify(data), ttl); // write failure -> throws |
| 6 | return data; |
| 7 | } |
Explanation (EN)
Any failure in the cache get, parse, or set takes down the whole call, even though the request could have succeeded by just fetching fresh data.
Objašnjenje (HR)
Bilo kakav kvar u dohvacanju, parsiranju ili spremanju u predmemoriju rusi cijeli poziv, iako je zahtjev mogao uspjeti jednostavnim dohvacanjem svjezih podataka.
Good example
| 1 | async function fetchWithCache<T>(key: string, ttl: number, fetcher: () => Promise<T>): Promise<T> { |
| 2 | try { |
| 3 | const cached = await cache.get(key); |
| 4 | if (cached) { |
| 5 | try { return JSON.parse(cached) as T; } |
| 6 | catch { logger.warn(`Corrupted cache entry: ${key}, fetching fresh`); } |
| 7 | } |
| 8 | } catch (e) { |
| 9 | logger.warn(`Cache read failed: ${key}`, e instanceof Error ? e.message : undefined); |
| 10 | } |
| 11 |
|
| 12 | const data = await fetcher(); // a real fetch failure SHOULD propagate |
| 13 |
|
| 14 | try { |
| 15 | await cache.set(key, JSON.stringify(data), ttl); |
| 16 | } catch (e) { |
| 17 | logger.warn(`Cache write failed: ${key}`, e instanceof Error ? e.message : undefined); |
| 18 | } |
| 19 | return data; |
| 20 | } |
Explanation (EN)
Each cache interaction is guarded independently so the cache can fail without breaking the request, while errors from the real data fetcher still propagate.
Objašnjenje (HR)
Svaka interakcija s predmemorijom je zasticena neovisno tako da predmemorija moze otkazati bez rusenja zahtjeva, dok se greske iz stvarnog dohvacaca podataka i dalje propagiraju.
Exceptions / Tradeoffs (EN)
If a cache is a hard correctness dependency (e.g. distributed lock), a failure there may legitimately need to abort — but that should be a deliberate, documented choice. Balance against do-not-silently-default-on-error-for-critical-values: degrade gracefully on cache miss/corruption only by falling through to the real source, never by inventing a value.
Iznimke / Tradeoffi (HR)
Ako je predmemorija tvrda ovisnost o ispravnosti (npr. distribuirani lock), kvar tamo mozda legitimno mora prekinuti - ali to treba biti namjeran, dokumentiran izbor.