Topic: Engineering principles template
Engineering Principles Template — ADR vs Principle, the Promotion Path, and the Standing-Rule Repository
Architecture decision records document specific choices. Engineering principles document standing rules — the defaults your team applies to future decisions without needing a new ADR each time. Most teams that adopt ADRs eventually discover they need both: ADRs for "why did we pick Kafka for payments?" and principles for "we default to event streaming for async workflows." This page explains the distinction, provides the principle template, shows how to store principles alongside ADRs, and describes the promotion path from repeated ADR pattern to codified principle.
TL;DR
An ADR records a specific decision with fixed alternatives and a defined outcome. An engineering principle is a standing rule that governs future similar decisions without requiring a new ADR each time. Store principles in a sibling directory to your ADRs (doc/principles/), use the template below for each principle file, and review active principles annually. When three or more ADRs independently reach the same conclusion, extract the pattern as a principle and link back to the founding ADRs. The WhyChose extractor surfaces the ChatGPT and Claude sessions where engineering principles were originally deliberated — the raw material for writing the Rationale section.
ADR vs engineering principle — the core distinction
The confusion between principles and ADRs is understandable: both are written records about technical choices. The difference is in scope, mutability, and purpose.
Architecture decision record
An ADR captures a specific, time-bounded decision:
- Context is particular: "The payments service needs a message queue because the charge processor is synchronous and blocks the user-facing API."
- Alternatives are specific: Kafka, RabbitMQ, Amazon SQS.
- Outcome is fixed: Kafka, because cross-datacenter replication and the audit log requirement.
- Immutable after acceptance: the Status changes (Accepted → Superseded), but the decision text does not. The record is a historical artifact.
- Applies to one thing: the payments service message queue. Other services writing a similar ADR would repeat the process.
Engineering principle
A principle captures a standing rule — a default that governs future similar choices:
- Context is general: "We build async inter-service workflows on event streams, not direct calls."
- No alternatives section: the principle is the conclusion of prior deliberations, not a record of ongoing deliberation.
- Mutable: principles are revised as the team's constraints, scale, and tooling change. The revision history is preserved in git.
- Applies to all future decisions of the type: any team building an async service-to-service integration should follow this principle as the default — no new ADR required unless they depart from it.
The practical test
Ask: "Is this a decision or a default?" If a specific context forced a specific choice and you want to record why — write an ADR. If you want to express a preference that should apply to future similar situations without requiring independent research each time — write a principle. If you're not sure, write the ADR first. Principles emerge from ADR patterns; they're not written speculatively.
The engineering principle template
Store each principle as a Markdown file in a principles/ directory. The recommended filename convention: PRIN-0001-prefer-postgres-for-oltp.md — the PRIN- prefix distinguishes principle files from ADR files if they share a repository, and the sequential number preserves insertion order without encoding the principle content in the filename.
# [Principle title — state the default, not the problem]
* Status: [active | under-revision | deprecated]
* Last Reviewed: YYYY-MM-DD
* Reviewers: [@alice, @bob]
* Tags: [data, infrastructure, api-design]
---
## Statement
[One to three sentences expressing the standing rule. Write it prescriptively: "Prefer X.
Use Y when Z." The statement should be actionable without reading the full document.]
## Rationale
[Why does this principle exist? What evidence, experience, or constraints led here?
Typically 2-4 paragraphs. This is where you explain the failures, near-misses, or
deliberations that motivated the principle. Reference the founding ADRs by number.]
**Founding ADRs:** [ADR-0043](../adr/0043-payments-queue-architecture.md),
[ADR-0051](../adr/0051-notifications-event-stream.md),
[ADR-0067](../adr/0067-audit-log-streaming.md)
## When to deviate
[Explicitly define the exceptions. A principle without a deviation clause becomes a
bureaucratic obstacle — teams will quietly violate it rather than revise it.
List the conditions under which an ADR justifying departure is appropriate.]
* [Condition 1 — e.g., when the downstream consumer is a third-party system with no
message queue client support and integration is contractually required]
* [Condition 2]
## What changes when this principle applies
[Concrete behavioral guidance: what does an engineer do differently because this
principle exists? This is not the Rationale restated — it is operational guidance.]
* [Implication 1]
* [Implication 2]
## Related
* [ADR-0043 Payments queue architecture](../adr/0043-payments-queue-architecture.md) — founding ADR
* [PRIN-0003 Async-first service communication](PRIN-0003-async-first-communication.md) — sibling principle
* [ADR best practices guide](https://whychose.com/seo/architecture-decision-record-best-practices) — quality standards this principle extends
The Statement section
The Statement should be one to three sentences that a new engineer can read in 30 seconds and immediately apply. Write it prescriptively: "Prefer PostgreSQL for OLTP workloads. Use a different datastore only when a specific constraint — query pattern, scale target, consistency model — is incompatible with PostgreSQL, and document that constraint in an ADR." Avoid hedging language ("generally", "usually", "when appropriate") in the Statement — hedging belongs in the "When to deviate" section.
The Rationale section
The Rationale is where the principle earns its authority. It should explain what evidence — incidents, ADR patterns, deliberations — produced the principle. A principle without rationale is a diktat; it will be followed resentfully or ignored. Two to four paragraphs is the right length. Reference the founding ADRs explicitly with relative links so engineers can trace the principle back to specific decisions.
The "When to deviate" section
Every viable engineering principle has explicit exceptions. Writing the exceptions down serves two purposes: it prevents the principle from becoming a rigid rule that blocks justified departures, and it clarifies what the principle is actually protecting against. A principle that has no valid exceptions is usually too narrow to be a principle — it should probably be a hard constraint instead. The "When to deviate" section also signals to engineers that departure requires an ADR: if they find themselves in one of the listed conditions, they write an ADR justifying the departure before proceeding.
The ADR-to-principle promotion path
Principles rarely emerge fully formed. They crystallize from patterns — from multiple independent teams or services reaching the same conclusion for the same reasons. The promotion path:
Step 1 — Accumulate founding ADRs
Track ADRs that share a conclusion. When three or more ADRs independently choose the same option for overlapping reasons, the pattern is ready to be examined. You don't need to extract a principle from every pattern — only from patterns where the shared reasoning is robust enough to serve as a default for future decisions.
Step 2 — Articulate the pattern
Read the Rationale sections of the founding ADRs. What constraints appear in all of them? What alternatives were rejected across all three for the same reasons? The intersection of their rationales is the principle's Statement. The union of their context sections is the principle's Rationale.
Step 3 — Identify the deviation conditions
Read the Alternatives sections of the founding ADRs. The cases where an alternative was considered but rejected give you the deviation conditions — the circumstances where a future engineer might legitimately reach a different conclusion. These become the "When to deviate" list.
Step 4 — Write and review
Write the principle document using the template above. Open a PR with the same review ceremony as an ADR — @mention the authors of the founding ADRs, set a review deadline, close if no blocking objection. The founding ADR authors are the right reviewers because they have lived through the context that the principle is trying to generalize.
Step 5 — Link bidirectionally
Update each founding ADR to add a cross-reference to the principle. The ADR's Outcome section or a Related section at the bottom should note: "This ADR contributed to PRIN-0007 Async-first service communication — which now governs this design pattern as the default." The principle links back to the founding ADRs. This bidirectional link graph allows future engineers to trace from current principle → founding decisions → original context.
Step 6 — Retire the redundant ADR work
After the principle is active, future teams building similar systems do not need to write a new ADR to justify following the default. The principle replaces the repeated ADR work for the default case. Teams only write an ADR when they depart from the principle — and that ADR should reference the principle it's departing from and explain why the deviation conditions apply.
Storing principles alongside ADRs
Directory structure
The recommended structure for a repository with both ADRs and principles:
doc/
adr/
0001-initial-database-selection.md
0043-payments-queue-architecture.md
0067-audit-log-streaming.md
principles/
PRIN-0001-prefer-postgres-for-oltp.md
PRIN-0002-event-streaming-for-async-workflows.md
PRIN-0003-rest-for-synchronous-apis.md
README.md ← index of active principles with one-line summaries
The PRIN- prefix avoids filename collisions if ADRs and principles ever share a directory, and makes grep results immediately readable: PRIN-0001 is clearly a principle, 0043 is clearly an ADR.
The principles README
A principles/README.md (or PRINCIPLES.md at the repository root) serves as the index. It should list every active principle with a one-line statement and a link to the full document. Keep the index readable without scrolling — if it exceeds two screens, the team has too many active principles. Ten to fifteen active principles is a healthy ceiling for most engineering organizations. More than that usually indicates that some principles are actually ADRs masquerading as principles, or that the team is over-principling rather than governing through decisions.
CI validation for principles
Apply the same CI lint to principle files as to ADRs. Minimum checks: Status field is one of the recognized values (active, under-revision, deprecated); Last Reviewed date is parseable and less than 18 months old for active principles; Founding ADRs links resolve. The 18-month staleness check is the highest-value lint — it forces teams to confront principles that have drifted out of sync with current practice.
Principle lifecycle — review, revision, and deprecation
Active
A principle is active when its Statement represents the team's current default and the "When to deviate" conditions accurately describe the exceptions. Active principles should be reviewed at least annually. The Last Reviewed date in the template is the mechanism — a quarterly or annual calendar event scoped to principles files triggers the review.
Under revision
Set Status to under-revision when a principle is being actively reconsidered — typically triggered by a new ADR that departed from the principle under conditions not covered by the deviation list, or by a significant change in tooling or scale. Open a PR for the revision using the same review ceremony as the original. The git history preserves the old Statement; the PR discussion captures why it changed.
Deprecated
A principle is deprecated when it no longer applies — the technology it governed is being sunset, the constraint that produced it has been resolved, or a newer principle supersedes it. Deprecated principles should not be deleted. Mark Status as Deprecated, add a Deprecated-By field referencing the superseding principle or the ADR that changed the direction, and leave the file in the directory. Engineers who encounter the deprecated principle in git history or cross-references need to understand why it was valid at the time and why it changed.
Common lifecycle anti-patterns
| Anti-pattern | Why it fails | Correction |
|---|---|---|
| Principle without founding ADRs | No evidence base — reads as opinion, not pattern. Teams ignore it or fight it. | Write the founding ADRs first; extract the principle from their pattern. |
| No deviation clause | Becomes a bureaucratic barrier to justified departures. Teams quietly violate it. | Write the "When to deviate" section before publishing. |
| Principle never reviewed | Drifts out of sync with current practice. Newer engineers inherit outdated defaults. | Enforce Last Reviewed staleness check in CI. |
| Too many principles | No engineer can hold 30 principles in working memory. Governance collapses. | Audit quarterly; deprecate principles that are now codified in platform defaults. |
| Principle that should be an ADR | A principle that applies to one specific system or decision is an ADR with an inflated scope claim. | If the Statement reads "For the X service, prefer Y" — it's an ADR, not a principle. |
When a principle conflicts with an existing ADR
Teams adopting principles retrospectively will encounter ADRs that appear to contradict a new principle. This is expected — the principle emerged from a pattern across ADRs, but some early ADRs may have made different choices before the pattern was recognized. The resolution protocol:
- If the ADR pre-dates the principle's founding ADRs and the system it governs is still active, write a new ADR for that system acknowledging the principle and explaining either (a) why the system will migrate to align, or (b) why the system qualifies for the deviation clause.
- If the ADR's system has been decommissioned or migrated, annotate the ADR with a superseded-by pointer to the principle. No new ADR needed.
- Do not retroactively change the Status of the existing ADR to Superseded without a replacement ADR — the original decision needs a replacement record, not just a status change.
The conflict surface is how teams discover that a principle's "When to deviate" section is incomplete. When the conflict resolution discussion produces a new exception case, update the principle's deviation clause before closing the PR.
WhyChose and engineering principle authorship
The hardest section to write in an engineering principle is the Rationale — specifically, the explanation of why the pattern emerged. The deliberation that produced the pattern happened in ChatGPT and Claude sessions, across multiple ADRs, over months of conversations where alternatives were considered and rejected. By the time someone sits down to extract the principle from three founding ADRs, the reasoning is scattered across chat histories that aren't in the same window as the principle template.
The WhyChose extractor processes a conversations.json export and surfaces the sessions where architecture alternatives were evaluated for the decisions that eventually became the founding ADRs. The extracted output includes the specific rejection reasons for non-chosen options — exactly the content that belongs in the principle's Rationale section ("we rejected direct service-to-service calls because the coupling produced three cascade failures in 18 months; event streaming decoupled the failure domain"). Copy the extracted rationale into the principle document before opening the PR.
The workflow: export ChatGPT or Claude conversations → run the WhyChose extractor → filter to sessions matching the founding ADR topics → use the extracted Alternatives Considered and rejection reasons as the principle's Rationale. The extractor doesn't write the principle — you do. But it surfaces the reasoning that was already in the chat history, so the Rationale section is grounded in the actual deliberation, not reconstructed from memory six months later.
Further Reading
- ADR best practices — quality practices that make decision records worth reading six months later: the Considered Options section, the honest-downside requirement, and the common mistakes that reduce ADR value. Principles complement these best practices — they reduce the ADR volume for default decisions, so the ADRs that do get written are the high-signal departures from defaults.
- ADR decision authority matrix — who writes, reviews, and approves. Principle review authority typically follows the same matrix at Class 3 (foundational) scope — principles should be reviewed by the widest stakeholder set because they govern the most decisions.
- ADR governance patterns — async teams, decision authority, and the RFC announcement loop. The same governance ceremony (announce-then-silence, consent-based review) applies to principle review PRs — the reviewer set is typically broader than a single ADR because principles affect all future decisions of the governed type.
- The RFC-to-ADR process — how engineering RFCs become architecture decision records. For significant principle changes (not just routine reviews), an RFC process is appropriate — the principle is high-stakes enough to warrant a dedicated comment window before the PR is opened.
- ADR vs Design Decision Record — the scope distinction between architecture (cross-cutting, affects multiple teams) and design (service-local, single team). Engineering principles operate at the architecture scope by definition — they govern decisions that cross service or team boundaries. Service-local defaults don't need principles; they belong in the service's README or CONTRIBUTING guide.
The Rationale section is where principles stall
A principle without a grounded Rationale is an opinion. The deliberation that produced the pattern happened in Claude and ChatGPT sessions, across the founding ADRs, over months of conversations. The WhyChose extractor surfaces those sessions and produces the Considered Options and rejection reasons that belong in the principle's Rationale section. Extract the reasoning before you've lost it — the founding ADR sessions are the most decision-rich content in your chat history.