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).
Resolve defaults at the boundary so inner layers take required params
Apply default values once at the request boundary, then pass resolved values to inner layers as required (non-optional) arguments.
Bad example
| 1 | // Route leaves params optional and lets each layer guess the default |
| 2 | const limit = parseNumber(params.limit); // number | undefined |
| 3 |
|
| 4 | repository.feed(filters, limit); // passes undefined downstream |
| 5 |
|
| 6 | // Repository signature optional -> guard everywhere, default duplicated/ambiguous |
| 7 | async feed(filters: Filters, limit?: number) { |
| 8 | if (limit !== undefined) this.provider.setLimit(limit); |
| 9 | // else what? provider has its own implicit default? unclear and untestable |
| 10 | } |
Explanation (EN)
Optional params propagate `undefined` through every layer, so each one needs a `!== undefined` guard and may apply its own default. The 'real' default becomes ambiguous, defaults can silently diverge between layers, and the extra branching is dead weight once a default exists.
Objašnjenje (HR)
Opcionalni parametri propagiraju `undefined` kroz svaki sloj, pa svaki treba `!== undefined` strazu i moze primijeniti vlastiti default. 'Pravi' default postaje dvosmislen, defaulti se mogu tiho razici izmedu slojeva, a dodatno grananje je mrtvi teret kad default vec postoji.
Good example
| 1 | const DEFAULT_LIMIT = 10; |
| 2 |
|
| 3 | // Default resolved once, at the boundary |
| 4 | const limit = parseNumber(params.limit, 1) ?? DEFAULT_LIMIT; // always a number |
| 5 |
|
| 6 | repository.feed(limit, filters); |
| 7 |
|
| 8 | // Inner layer takes a required value -> no guard, no implicit default |
| 9 | async feed(limit: number, filters: Filters) { |
| 10 | this.provider.setLimit(limit); |
| 11 | } |
Explanation (EN)
Defaulting happens in exactly one place — the edge that knows the request shape. Downstream signatures become required, so the type checker proves the value is always present, the `undefined` guards vanish, and there is a single, obvious source of truth for each default.
Objašnjenje (HR)
Postavljanje defaulta dogada se na tocno jednom mjestu — rubu koji poznaje oblik zahtjeva. Nizvodni potpisi postaju obavezni, pa prevoditelj dokazuje da je vrijednost uvijek prisutna, `undefined` straze nestaju, a postoji jedan, ociti izvor istine za svaki default.
Exceptions / Tradeoffs (EN)
If an inner layer is a genuinely standalone public API consumed outside this boundary, it may need its own defaulting; but within a single request pipeline, default once at the entry point.
Iznimke / Tradeoffi (HR)
Ako je unutarnji sloj stvarno samostalni javni API koji se koristi izvan ove granice, mozda treba vlastito postavljanje defaulta; ali unutar jednog cjevovoda zahtjeva, postavi default jednom na ulaznoj tocki.