Skip to content

Primitive first

Build the reusable primitive first, then consume it. A behavior that more than one feature needs is a primitive: define it once, test it once, and write every consumer against it. Do not inline a one-off where a primitive belongs, and do not grow a second variant of something that already exists.

  • One tested thing, not N. A primitive carries its own full test set, so every consumer inherits correctness. N inlined copies are N places to drift and N places a bug can hide.
  • Consistency by construction. When one engine backs every site, a contributor (and an operator) learns it once: the filter you write for a dynamic group is the filter you write for a list.
  • The learning tool renders the real engine. Operator surfaces teach a concept by running the primitive against real data (learning tool), so a primitive is the teaching artifact, not a diagram.

The primitives the system is written against

Section titled “The primitives the system is written against”
PrimitiveOne model forDoc
Expression enginelist filter, rule scope, dynamic-group membership, fire_criteria, calc reduceexpressions
ViewResult renderer contractevery read beyond one resource ({columns, rows}, one renderer)views, UI
Storage Gatewaythe only DB door: scope and in-transaction audit by constructionstorage, identity and access
Cascaderesolving config, credentials, and variables down one treecascade
Admission consumer and the two lanesthe one owner fence and the one data / record split on the busmessaging
Timer and clockschedule, watchdog, for-duration, and runbook-wait, all one durable modeltime
The action rowevery long-running operation’s handle, rule-fired or API-calledAPI, alarms and actions
datapoint_type registryone registry across metric, state, and logdatapoints
  • Reach for the primitive before writing the one-off. Need a filter, a read, a scheduled fire, a scoped query? It already exists, consume it. If you are about to hand-roll one, stop.
  • Extract on the second use, not the third. The moment a pattern is copied it is a primitive that has not been named yet. Pull it out, give it tests, point both callers at it.
  • A primitive lands with its tests and its first consumer in the same slice (vertical, not horizontal): build the primitive, prove it with one real consumer, ship both. The /add-collection-primitive and /canonical-datapoint skills are this doctrine made procedural.
  • Do not fork an engine. A second filter language, a second DB path, a second timer model is the anti-pattern this doctrine exists to prevent.

This composes with the others: the API is generated from the primitives, test-driven tests each primitive once, and the learning tool renders the real one.