Essay / Software Engineering
Architecture Decisions Have Expiration Dates
Architecture decisions depend on assumptions that change. Record context, review triggers and migration costs so yesterday’s sensible choice stays visible.
An architecture decision record can be perfectly accurate and still lead a team in the wrong direction two years later. The record says a queue was unnecessary because one process performed all writes. The system now has several writers, but the decision survives as a rule detached from the condition that made it sensible.
Decisions age when their context changes. Their expiration date is rarely printed in advance. It appears as a new workload, a different ownership model, an operational constraint or a dependency that no longer behaves as expected. Keeping architecture useful requires remembering those conditions as carefully as the selected technology.
An architecture decision is correct relative to a context, not forever.
Preserve the argument behind the choice
Michael Nygard’s account of architecture decision records proposes short records that capture context, decisions and consequences. The important property is that a future reader can understand why a choice was made. A technology inventory alone does not provide that explanation.
“Use static generation” is an outcome. A useful argument might say that content is public, updates happen through a controlled publishing process, requests do not require personalized server computation, and the owner wants limited production operations. Those conditions explain why static generation fits.
If later requirements introduce authenticated private dashboards, the old decision has not necessarily become foolish. Its scope may simply exclude the new need. The team can preserve static publication for public pages while considering a separate boundary for private functionality.
This distinction prevents architecture debates from becoming retrospective judgments about competence. The useful question is what changed and which part of the earlier reasoning still holds. An explicit record lets the team answer without reconstructing every conversation from memory.
Separate assumptions from commitments
Some statements describe the world; others commit the team to behavior. “The supplier sends one complete file each night” is an assumption. “We preserve the previous accepted catalogue until validation succeeds” is a commitment. Mixing them makes it difficult to know what should change when evidence arrives.
A record can distinguish these categories without becoming a large template. List the assumptions that materially influenced the decision, the behavior the system must preserve, and the consequences accepted in exchange. Focus on facts whose reversal would actually affect the choice.
For a shared-hosting site, an assumption might be that production serves static files. A commitment might be that deployments never delete provider-owned content. Adding a new article does not challenge either. Adding a server endpoint challenges the first and requires an explicit review rather than an accidental change to deployment configuration.
The same approach helps with organizational assumptions. If a design depends on one team owning a database schema, record that condition. When ownership splits, the technical interface may need revision even if traffic and data volume remain unchanged.
Use review triggers that can be observed
A calendar review can be helpful, but many decisions deserve attention when a specific condition changes. “Review when we add a second writer” is more actionable than “review occasionally.” It identifies the event that invalidates part of the argument.
Other triggers include a new consumer of a contract, a change in data retention, an operational incident revealing an unhandled failure mode, or a workload exceeding the range used in validation. Avoid triggers so vague that every routine change qualifies.
A compact record might contain:
| Element | Example |
|---|---|
| Current context | One controlled catalogue publisher |
| Decision | Publish validated immutable snapshots |
| Accepted consequence | Readers may temporarily see the previous revision |
| Review trigger | Independent writers need to publish concurrently |
The table describes an illustrative decision, not a universal architecture recommendation. Its strength is that a future change has a visible place to attach. Someone adding another publisher can see that they are crossing an assumption boundary.
Reversibility has several dimensions
Calling a decision reversible can conceal substantial work. Replacing a library in source may be easy while migrating stored data is difficult. Changing a provider may require little application code but careful DNS, certificate and deployment coordination. Reversibility should include the whole operating system of the product.
Consider data format, public contract, operational knowledge and user habit separately. An internal helper with no persisted output is often easier to replace than a public URL that readers have bookmarked. A database column used by external integrations may have a longer migration path than its code references suggest.
A reversible choice still needs a credible route back.That route may involve compatibility readers, dual formats for a limited period, export tooling or a tested recovery procedure. It should be proportional to the consequence. Building an elaborate abstraction around every dependency can cost more than a realistic future migration.
The trade-off discussion applies here: flexibility is something the team pays for now. Buy it where the expected change and its cost justify the additional machinery, rather than treating maximum optionality as a universal goal.
Migration cost is part of the new decision
An alternative architecture can be better in isolation and still be the wrong change today. The comparison must include migration effort, temporary compatibility, testing, operational risk and the opportunity cost of delaying other work.
This does not mean existing decisions deserve permanent protection. Sunk effort should not justify continuing an unsuitable design. It means the relevant comparison is between future paths from the current state, rather than between two imaginary projects starting from nothing.
A useful migration proposal describes the intermediate states. Can old and new formats coexist? Which system remains authoritative? How will the team know migration is complete? What happens if the work stops halfway? These questions often expose costs that a final-state diagram omits.
For a small product, the sensible response may be to isolate one painful boundary while leaving the rest unchanged. That can create room for later migration without committing the team to a rewrite whose benefits depend on finishing everything at once.
Decision decay appears in everyday work
Architecture rarely announces that it has expired. Instead, maintainers accumulate exceptions. A supposedly simple import needs special handling for several producers. A shared field acquires flags to indicate which process last wrote it. A deployment procedure requires steps that no longer match its documentation.
These are signals to investigate, not automatic proof that a rewrite is necessary. Some exceptions reflect legitimate domain variation. Others show that an old boundary no longer matches the work. Reviewing several recent changes can reveal which explanation is more plausible.
Ask whether new behavior can be expressed naturally within the existing model. If every change requires bypassing the same abstraction, the abstraction may be preserving yesterday’s assumptions. If one isolated case is awkward while the rest remains clear, a local adjustment may be sufficient.
This is a practical form of evolutionary architecture: preserve useful constraints, expose where they are failing, and change the smallest boundary that addresses the evidence. It does not require predicting every future requirement or continuously replacing working components.
Supersede records without erasing history
When a decision changes, keep the earlier reasoning available and mark it superseded. Link the replacement record and explain which assumptions changed. Otherwise a future maintainer may rediscover the old argument and unknowingly repeat the same debate.
The new record should describe the current choice, not merely say that the previous one was wrong. Include the consequences newly accepted and the validation needed for the migration. An architecture change is still a trade, even when the old approach has become clearly inadequate.
Review the record alongside the implementation. If the code introduces a different boundary from the one described, resolve the mismatch before treating the decision as complete. Documentation that describes an intended future while the system behaves differently creates another source of uncertainty.
A useful architecture history lets someone follow the changing constraints of the product. It shows why a choice fit, what challenged it, and how the team moved forward. That history makes the next decision easier because the context is available instead of buried under an unexplained rule.