Architecture Standards

This is the standard the Quality Gate holds structural and architectural decisions to: how a system is deployed, how a package is arranged inside, how boundaries are drawn so parts can be rebuilt, how tenants are walled off, and how external dependencies are chosen and contained. It expands the architectural side of the one-line rule the Coding Style Guide carries β€” dependencies point inward, ports and adapters at the edge β€” into a working standard for the shapes above that rule. It builds on the Infrastructure Planning Policy (which prefers managed, stateless, disposable services and weighs lock-in and exit cost) and shares the "assume breach" instinct of Application Security. Deviations are allowed, but β€” as everywhere in the handbook β€” they must be deliberate and justified in the project's design notes or an ADR.

Architecture is where OSBR's values become load-bearing. Be Nice: a teammate can run the whole system on a laptop, change two modules in one commit, read a package in the client's own vocabulary, and find the reasoning for every hard choice written down beside the code. Be Kind: we hand the next maintainer β€” human or AI β€” one process to reason about instead of a call graph across the network, a dependency they can swap without asking the whole codebase, and an exit written before it is needed rather than discovered at the worst moment. Be Strong: we refuse the false sophistication of a distributed system nobody needs yet, we keep the freedom to switch vendors, and we stay willing to throw away and rebuild code we now judge wrong β€” without ego or sunk-cost paralysis.

How to read this policy

1. Goal

The goal of OSBR's architecture is software a small team can ship, change, and hand over at the speed it actually has β€” without paying for sophistication it has no use for yet. Concretely:

A structure that does not serve one of these goals is ceremony. We optimise for the option to change cheaply, not for the appearance of a grown-up architecture.

2. Responsibility

This is not a job for a separate "architect" gatekeeping a catalogue. In a small team the person building the feature is the person who keeps the system in one piece; the defaults below are what make the sound choice the path of least resistance.

3. Practices

Deployment shape β€” modular monolith first

We stand on named, published practice: Fowler's MonolithFirst and Microservice Premium, the Modular Monolith (Simon Brown, Kamil Grzybek), the Majestic Monolith (Shopify, DHH), DDD bounded contexts as in-process modules, and the fallacies of distributed computing.

3-1. Start as one modular monolith

3-2. Give modules real in-process boundaries

3-3. Treat distribution as a cost, not a default

3-4. Split only on a documented, concrete need

3-5. Keep managed services as edge scaffolding

Package internals β€” anti-corruption structure

We stand on named practice: Evans's Anti-Corruption Layer, Cockburn's Hexagonal Architecture (Ports & Adapters), Martin's Dependency Rule, Palermo's Onion Architecture, Bernhardt's functional core / imperative shell, and package-by-feature. This is the code-level expression of the same Style Guide dependency rules.

3-6. Divide the package by domain (package-by-feature)

3-7. Split each domain section into three responsibilities

Inside a domain section there are exactly three homes for code β€” Onion/Clean collapsed to the smallest honest number of rings, mapping onto functional core, imperative shell:

Responsibility Holds Purity
model Domain data (value objects, entities) and pure functions over them β€” the rules and calculations Pure: no IO, no side effects, no framework types
service Outward procedures β€” the use cases that orchestrate the model to get something done Effectful, but only via ports it declares; no concrete SDK
dependency implementation The one place an external dependency (DB, SDK, HTTP API) is actually called; translates SDK/DB shapes to and from domain types Effectful and technology-specific; the SDK lives here

3-8. Point every dependency toward the domain

dependency-implementation  ──▢  service  ──▢  model
        (adapters)              (use cases)   (pure core)

3-9. Keep entry points as thin external shells

3-10. Let no external library type cross the boundary

This is the anti-corruption rule proper, and the one reviewers guard hardest.

Vendor neutrality β€” keep the freedom to switch

The anti-corruption layer of Β§3-10 is the mechanism; this cluster is the discipline around it β€” when to take a dependency on at all, and how to keep the exit payable. We stand on Cockburn's Ports & Adapters, Evans's ACL, and ADR practice (Nygard).

3-11. Add a dependency only on a clearly-met criterion

3-12. Log every dependency decision as an ADR

Every decision to take on (or deliberately reject) an external dependency MUST be recorded as an ADR. Each dependency ADR MUST state four things:

3-13. Preserve the freedom to switch β€” and prove it is preserved

Rebuildable boundaries β€” sacrificial architecture

We stand on Fowler's Sacrificial Architecture and Strangler Fig, the Building Evolutionary Architectures work (Ford, Parsons, Kua) and its fitness functions, YAGNI, Twelve-Factor disposability, and Brooks's second-system effect as the anti-pattern.

3-14. Draw boundaries along wholly-rebuildable units

3-15. Keep the regeneration basis in the repository

The regeneration basis is everything a rebuilder needs to regrow a module correctly without reverse-engineering it: what it must do, why, and which decisions are load-bearing.

3-16. Treat discard-and-rebuild as a normal option β€” especially early

3-17. Record the decision to rebuild

3-18. Do not gold-plate the first version (YAGNI)

Multi-tenancy β€” decide isolation before the first table

Isolation is one of the few architectural properties dramatically cheaper built in than retrofitted: a shared table with no tenant boundary, once it holds two customers' production data, cannot be split into per-tenant databases without a migration project. We name the endpoints and the middle with the industry's silo / pool / bridge vocabulary.

3-19. Decide the isolation model before the first tenant-scoped table

3-20. Automate tenant provisioning regardless of model

3-21. Enforce pooled isolation at the database

3-22. Design against the noisy neighbour

References

Deployment shape β€” monolith first & the cost of distribution

Package internals β€” boundary architectures

Vendor neutrality β€” lock-in, portability, decision records

Rebuildable boundaries β€” sacrificial & evolutionary architecture

Multi-tenancy β€” tenant isolation

Related OSBR standards