As the architect of a system, how do you decide that a second architectural style is justified, and how do you stop a hybrid architecture from decaying into an unmanaged mix of styles?
answer
- ASRs with numbers, not style fashion
- one paved road + few scoped exceptions
- ADR: context, decision, consequences, exit criteria
- fitness functions in CI or the rule decays
- Conway's law: only styles you can staff and operate
basics
~20 sPick one default style. Add a second only when a specific, measurable requirement - burst traffic, independent deployment, isolation - cannot be met otherwise. Scope it to a named boundary, record the decision and its exit criteria, and enforce the boundary with automated checks.
solid answer
~50 sStart from architecturally significant requirements: the quality attributes with numbers attached (peak burst profile, latency budget, availability target, release cadence, blast-radius limit). Declare one default 'paved road' style that most components use. A second style needs a written case that names the requirement the default cannot meet at acceptable cost, the exact boundary where the exception applies, the added operational cost, and the conditions under which it would be reversed - captured in an architecture decision record. Then make the boundary executable: fitness functions in CI (module dependency rules, allowed-dependency lists, latency and payload budgets, independent-deployability checks, contract tests) so the rule is verified continuously rather than remembered. Constrain choice with a small approved technology set and shared templates, because each style multiplies build, run, hiring and on-call cost. Match styles to team topology - Conway's law means an architecture your organisation is not shaped or staffed to operate will regress - and periodically retire styles that no longer earn their keep.
go deeper
Say you should have a main style and only add another when there is a clear reason, and write the reason down.
Tie the decision to a specific requirement the default cannot meet, keep the second style scoped to a named area, and mention decision records and automated checks.
Give the full case structure - ASR with numbers, boundary, contract, cost, exit criteria - plus concrete fitness functions and the operational cost of each additional style.
Add portfolio-level governance: paved roads and an approved technology set, the architectural-quantum test against premature decomposition, Conway's law and team topology as inputs, delivery and architecture metrics to detect decay, scheduled re-review, and planned recombination or retirement of exceptions.
## Start from requirements, not from styles **Architecturally significant requirements (ASRs)** are the constraints that actually shape structure: peak and burst load profile, tail-latency budget, availability target, data-consistency needs, regulatory isolation, release cadence per capability, blast-radius limits, cost ceiling, and team count and skills. A style is only ever a *means*. The question is never 'should we be event-driven?' but 'which requirement is currently unmet, and what is the cheapest structure that meets it?' Most quality attributes trade against each other: elasticity against latency predictability, independent deployability against transactional simplicity, decoupling against traceability. Naming which attribute wins where is the architect's actual output. ## The default-plus-exception model A governable hybrid has: 1. **One default style** - the paved road most components follow, with templates, libraries, pipelines and runbooks already built for it. 2. **A small number of named exceptions**, each with: - the ASR the default cannot meet at acceptable cost, stated with numbers; - the **boundary** where the exception applies (which capability, which module, which traffic class) - not 'anywhere the team feels like it'; - the integration contract with the rest of the system (API, event schema, ownership of data); - the added cost, honestly estimated: pipelines, observability, on-call knowledge, local development, hiring; - **exit criteria** - what would make you remove it again. These belong in **architecture decision records (ADRs)**: short, dated, immutable documents stating context, decision, consequences and status (superseded when replaced). Their value is that future teams inherit the *reason*, so they can tell whether the reason still holds. ## Sizing the unit: the architectural quantum A useful test for 'is this really a separate piece?' is the **architectural quantum**: an independently deployable unit with high functional cohesion and its own data store, including everything needed to run. If a proposed new service does not own its data or cannot deploy alone, it is not a quantum, and splitting it out buys distribution cost with no independence. This test catches most premature-decomposition proposals before they ship. ## Make the boundary executable: fitness functions A **fitness function** is an automated, objective test of an architectural characteristic, run in CI like any other test. Examples: - **Dependency rules** - the domain package imports no infrastructure; module A may only depend on B's public API. Tools: ArchUnit (JVM), dependency-cruiser (JS/TS), import-linter (Python), Spring Modulith module verification. - **Independent deployability** - a build that fails if a service's tests require booting other services; consumer-driven contract tests so a provider can deploy alone. - **Performance and size budgets** - endpoint latency percentiles, bundle size, function cold-start duration, message payload limits. - **Style-scope checks** - functions may not open a connection to the core database; no new synchronous call may be added across a designated boundary. The rule of thumb: **an architectural rule that is not executable will be violated within a few sprints**, not out of malice but under deadline. Governance by document review does not scale; governance by build failure does. ## Constrain the menu - Maintain a small **approved set** of styles and technologies (a tech radar with adopt/trial/hold, or a paved-road catalogue). Deviations are allowed but must be argued, and they come with the obligation to fund the operational tail. - Remember the **cost per style**: another deployment path, another observability integration, another failure mode in the incident runbook, another skill set to hire and be on call for, another local-development story. Two styles operated well beat five adopted enthusiastically. - Beware **resume-driven** and **conference-driven** adoption; the tell is a proposal whose justification is a technology name rather than a number. ## Organisation and Conway's law **Conway's law**: systems mirror the communication structures of the organisations that build them. Practically, an architecture that requires more independent teams, more operational maturity or more on-call depth than you have will regress toward your actual org chart. So style selection includes: do we have enough teams to own these services? Is there a platform team to provide the paved road? Can we staff on-call for this runtime? Sometimes the correct architectural act is the **inverse manoeuvre** - change team structure first, then let the architecture follow. ## Keep it honest over time - Re-review exceptions on a schedule; an exception whose ASR disappeared should be retired, and retirement should be planned in, not hoped for. - Watch delivery signals (deployment frequency, lead time for change, change failure rate, time to restore) plus architecture-specific ones (deployment coupling, cross-boundary synchronous call depth, consumer lag, blast radius of recent incidents). A decaying hybrid shows up as rising deployment coupling and lengthening lead times long before anyone calls it a problem. - Accept **recombination** as a legitimate move: collapsing an exception back into the default is a success of governance, not an admission of error.
- An engineer proposes moving one capability to a new style. What do you require in the proposal before approving it?The architecturally significant requirement it serves, stated with numbers and evidence that the current default cannot meet it at acceptable cost; the exact boundary the new style applies to; the integration contract and data ownership; the total operating cost including pipeline, observability, on-call and local development; who owns it; and the exit criteria that would trigger reverting. If the strongest argument is the technology's name or popularity, that is a rejection.
- Why are fitness functions considered essential to keeping a hybrid architecture intact?Because architectural rules are directional constraints that become invisible at code-review time once a codebase is large. An automated check - dependency rules, latency budget, contract test, deployment-independence test - turns the constraint into a build failure at the moment of violation, with the cheapest possible feedback. Rules enforced only by documents and goodwill erode within a few sprints under delivery pressure.
- How does Conway's law constrain which styles a hybrid can realistically use?Systems tend to mirror the communication structure of the organisation, so an architecture that assumes more independent teams, deeper operational maturity or broader on-call coverage than exists will drift back toward the real org chart - shared services, coordinated releases, and a distributed monolith. Either shape the teams to match the intended architecture first (the inverse manoeuvre), or choose a style the current organisation can actually own.
A city plan does not ban building types, it zones them: industry in one district with the utilities to support it, housing in another, and the zoning is enforced by inspections rather than by hoping developers remember the plan. Unzoned variety is not diversity, it is sprawl.
saying these in an interview costs you the question
- Choosing styles by fashion, conference talk or hiring appeal instead of a measured requirement
- Letting each team pick its own style with no default, boundary or approved set
- Recording no rationale, so successors cannot tell whether the reason still holds
- Relying on documentation and code review instead of automated fitness functions
- Ignoring the operational tail: pipelines, observability, on-call depth, local development, hiring
- Adopting a topology the organisation is not staffed or shaped to operate, then blaming the style
- Treating retirement of a style or a merge back into the default as failure rather than good governance