ConstraintsGENERALSTAGE-SPECIFICILLUSTRATIVE

Constraints Shape Architecture

Given the same requirements, two different sets of constraints produce two different correct architectures. The store with six weeks, two developers and tens of users is a monolith on one server; the same store with a partner sending a launch spike and a platform team is something else. Neither is the "right" architecture — each is the right one for its constraints.

The moveWorked exampleNext questions

The situation, the reflex, and why it stalls

Every lesson starts where being stuck starts: someone has a problem, and the first move that comes to mind feels like progress.

The question

How do the constraints turn into an architecture, and how do you know whether a design decision came from a constraint or from taste?

The situation

You have the requirements and the seven constraints written down. A colleague has drawn an architecture: an API gateway, three services, a message queue, a cache, a search index. You have drawn a monolith with one database. Both of you believe you are right, and the requirements support both.

The reflex

Argue about the architectures. Microservices versus monolith, queue versus synchronous, cache versus not — each side citing what it has seen work elsewhere. The argument is about the diagrams, and the diagrams are about other projects.

Why it stalls

The argument cannot be settled because neither diagram is wrong in general; both are right somewhere, and "somewhere" is exactly what the constraints describe and the argument ignores.

What the reflex produces — and fails to produce
  • The argument cannot be settled because neither diagram is wrong in general; both are right somewhere, and "somewhere" is exactly what the constraints describe and the argument ignores.
  • The compromise is a hybrid: two services instead of three, a queue "for later". It fits neither set of constraints and costs more than either design.
  • The design that wins is the one argued more confidently, and the confidence came from a previous project with a different team, a different deadline and a different user count.
  • Every later change to the design is argued the same way, because the record shows two diagrams and no reasons.
ProblemUnderstandRequirementsConstraintsUnknownsDecompositionSmallest StepModelExperimentObserveDebugLearnIterate

The move

Precisely enough to apply it to a problem you have never seen — not a slogan.

  • Trace each piece of a proposed architecture back to a constraint or a requirement, and remove the pieces that trace to neither. A queue traces to "work that must not block the response and must survive a crash" — which is a requirement — or to "expected load exceeds what one process can handle synchronously" — which is a user-count constraint; if neither is on the list, the queue is taste. A service boundary traces to "a team that must deploy independently" or "a component with different scaling or a different required technology"; with two developers and one deployment it traces to nothing.
  • Do it in both directions. From the constraints: what does each one force? Six weeks forces few pieces; two developers force one deployment they can both run; tens of users forces nothing; a contracted provider forces its integration shape; the budget forces a ceiling on managed services; the law forces a region and a deletion path. Then from the architecture: what does each piece cost in time, people, money and operational surface — and which constraint pays for it?
  • Write the mapping down as the architecture's reasons, so that the design is "a monolith because six weeks and two developers", not "a monolith". When a constraint changes — a third developer, a partner sending traffic, revenue lifting the budget — the mapping says which piece to reconsider, and the reconsideration is a decision rather than a fresh argument (Architecture From Requirements).
  • Accept that the same requirements with different constraints produce a different architecture, and that the other one is not wrong. The colleague's diagram is the store built by a platform team with a launch partner and a year; it is a correct answer to a different question, and saying so ends the argument better than winning it.

The store, with its reasons

The diagram is the store's architecture as the constraints produced it. What matters is not the boxes — there are few — but that each edge and each absence has a reason on the list. The pieces that are not here are not forgotten; they are on the trigger list with the constraint change that would bring each one in.

pages and APIcard fields go here, never to appproducts, carts, orders, ledgerupload / servecreate chargewebhook: paid (may repeat)confirmationsCustomer / admin browserOne application process (web + scheduled report)One database (permitted region)Object storage: imagesPayment provider (contracted; hosted fields)Email sender
UserLLMAgentToolDataDecisionHumanGuardrail

From a constraint to a piece of the design

The pipeline is the trace run forward. It is short because each step is a question, and the failure of each step is the way architecture arguments usually go wrong: a piece with no constraint, a constraint with no piece, or a trigger nobody watches.

Tracing a constraint into the architecture
  1. 1
    Name the constraint

    One of the seven, with its number, source and hard/soft mark.

    fails by An adjective — "lots of users" — that can be traced to anything.

  2. 2
    What does it force?

    The pieces, regions, integrations or limits the constraint requires: hosted fields from the provider, a region from the law, one deployment from two developers.

    fails by Forcing what the author wanted anyway and calling it the constraint's doing.

  3. 3
    What does it forbid?

    The pieces the constraint rules out: three services with two developers, a managed search service under the budget, a cheaper region under the law.

    fails by Only ever asking what is forced, so the design grows and never shrinks.

  4. 4
    Cost what remains

    Time, people, money, operational surface per piece — and the constraint that pays for each.

    fails by A piece nobody pays for, kept because it is already drawn.

  5. 5
    Write the trigger

    For each piece not built: the constraint change or measurement that would justify it, and the piece it would justify.

    fails by A trigger nobody watches; the piece arrives late, in an outage.

Run it once per constraint, then once per proposed piece in the other direction. The two passes should agree; where they do not, one of them is taste.

The first slice under these constraints

The slice below is what the constraints make the first thing to build: not the catalog, but the deployment and the provider, because six weeks and a contracted provider make those the two things most likely to surprise. What it does not prove is the point — a walking skeleton that reaches the provider says nothing about the store working, and it is still the right first slice for this constraint set.

The constrained walking skeleton
One product page and one test-mode charge, deployed in the permitted region, by both developers.
  1. DeploymentOne container on one host in the permitted region, deployed by a pipeline both developers have run.
  2. PageShows one product from the database and a Pay button that renders the provider's hosted fields.
  3. APIReturns the product; creates a test-mode charge for it; receives the provider's webhook and logs it.
  4. DatabaseOne product row; one row recording the webhook it received.
proves
The environment works in the region the law requires; both developers can deploy; the contracted provider's hosted fields and webhook actually reach the store — the three constraint-driven unknowns, answered in the first days.
does not prove
Anything about carts, orders, stock, failure handling, or whether the store is usable — and nothing about load, because tens of users was never a constraint that needed proving. Those are the next slices, and the trigger list says which pieces they may bring in.

How to do it

Most important first.

  • For every box and arrow in a proposed architecture, write the requirement or constraint it traces to. Boxes that trace to nothing are candidates for removal; boxes that trace only to "we might need it" are removed (Add Complexity Only When Required).
  • For each of the seven constraints, write what it forces and what it forbids. Check the architecture against both lists.
  • Cost every piece in the four currencies — time to build, people to run, money per month, and operational surface when it fails — and name the constraint that pays for each (The Complexity Ledger).
  • Write the architecture as sentences with reasons, not as a diagram alone. "One deployment, because two developers and six weeks" survives the argument; the diagram does not.
  • When a constraint changes, re-run the trace for the pieces that cited it. Do not redesign; reconsider the specific decisions the lapsed constraint made (When Assumptions Change).

Worked on a concrete problem

The move has to produce something. This is what it produced.

  • The store, traced. One application process: six weeks, two developers, tens of users — nothing forces more. One database: same. Object storage for images: the data constraint (images are the large thing) and the budget (storage is cheap, database disk is not). Hosted payment fields and webhook handling: the required provider and the card-data law. Deployment region: the data-protection obligation. A scheduled job for the nightly report: a functional requirement, run inside the same process because nothing forces a separate one. Not present: gateway, services, queue, cache, search index — each traced to nothing on the list, each written down with the constraint change that would bring it back.
  • The colleague's architecture, traced against different constraints — the ones it was actually designed for, from their last project. Three services: three teams deploying independently. A queue: a partner sending a launch spike whose order writes had to be absorbed. A cache: measured read load from a catalogue a hundred times larger. A search index: a functional requirement for full-text search over that catalogue. Every piece traced — to a constraint the store does not have. The argument ended there.
  • The trigger list that came out of it, written next to the monolith: a second deployment when a component needs a different scaling profile or a different required technology; a queue when a measured spike makes checkout wait or when email sending starts failing checkouts; a cache when the product pages are measured slow under real traffic and the database is the reason; a search index when the catalogue outgrows filter-by-name or full-text search becomes a requirement. Each trigger is a constraint change or a measurement, and each names the piece it justifies.
  • The chat app under two constraint sets, for contrast. A solo learner with no deadline: one process, one database, a websocket connection per client, messages in a table — realtime is a requirement, but nothing forces a message broker. The same app for a team with a required identity provider, a platform they must deploy on and an expected launch of many concurrent users: the identity provider shapes auth, the platform shapes deployment, and the concurrent-user estimate — if it is measured rather than hoped — justifies separating the connection-holding process from the rest. Same requirements, two correct architectures.

How you know it worked

What now exists that did not before, and what question you can now ask.

  • Every piece of the architecture has a written reason that names a requirement or a constraint, and the pieces that had none are gone.
  • The architecture argument ended by naming the constraints each design was for, not by one side winning.
  • A trigger list exists beside the design, and each trigger is a constraint change or a measurement that would justify a specific piece.
  • Someone with the constraints and the requirements — but not the diagram — could reconstruct most of the architecture from the reasons.

The questions you can now ask

The field this whole domain exists for. After this lesson, these are the questions to put to an unfamiliar problem.

Next questions
  • ?For this box or arrow: which requirement or constraint forces it, and would that constraint force it for someone who did not already want it?
  • ?What does each of the seven constraints force and forbid here, and does the design respect both lists?
  • ?Which constraint pays for this piece's time, people, money and operational surface?
  • ?If the argument is between two architectures, which constraints is each one actually designed for — and are they ours?

What can go wrong

How the move itself fails
  • The trace becomes a justification exercise. Every piece the author wanted is traced to some constraint, however tenuous; "a cache because users" is not a trace, it is a rationalisation. The test is whether the constraint would have forced the piece for someone who did not already want it.
  • Constraints are used to reject everything. A team that traces "nothing forces it" for every proposed piece ends up with a monolith that a real constraint — a partner spike, a platform requirement — genuinely did force something for, and ignored.
  • The trigger list is written and never watched. The user count crosses the threshold, the measurement is never made, and the queue that the trigger justified is added six months late, in an outage.
  • The move is applied to an existing architecture as if it were greenfield. The current design traces to constraints that have lapsed, and the "trace" becomes a demand to rebuild everything at once rather than to reconsider the specific pieces the lapsed constraints made.
What the move costs
  • Tracing every piece takes longer than drawing the diagram and is less fun; on a team that shares its constraints implicitly, much of the trace is already in everyone's head.
  • An architecture that cites its constraints is one that has to change when they do, and a team that wrote "monolith because two developers" has to revisit it when the third arrives — the reflex design would have quietly stayed.
  • Saying "your architecture is correct for different constraints" is more honest and less satisfying than winning; some colleagues hear it as being told their experience does not apply.
Misreads
  • "Constraints mean the monolith always wins." They mean the design that fits wins. The colleague's three services were correct for three teams and a launch partner; the monolith is correct for two developers and six weeks. A team that always concludes "monolith" has stopped tracing.
  • "Requirements decide the architecture." Requirements decide what the system does; constraints decide how it may be built. The same requirements produced two correct architectures in the worked example, and only the constraints told them apart.
  • "Once traced, the architecture is settled." It is settled until a constraint changes, and constraints change. The trace is what makes the next change a decision instead of an argument — it does not prevent the change.

Where this applies

Problem-solving advice is stated as universal far more often than it is. These labels say what each method is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view.

  • GENERALEvery piece of an architecture should trace to a requirement or a constraint, in any domain; for a data pipeline the constraints are data volume, latency to freshness and the platform, for a compiler they are the target and the team, and the trace is the same move.
  • STAGE-SPECIFICOn a greenfield project the trace runs forward from constraints to design; on an existing system it runs backward from the current design to the constraints that made it, and the interesting output is the list of pieces whose constraint has lapsed — those are the candidates for change, one at a time.
  • ILLUSTRATIVEThe two architectures, the colleague's previous project and the trigger thresholds are invented to show the trace; the seven constraints are real inputs and the mapping is the method.

Where the depth lives

This domain asks the question and hands the answer off by name.

Further
  • The architecture growth lab at /thinking/grow is the trigger list run as a simulation: raise the user count and see which piece the measurement justifies, and which it does not.