InterfacesGENERALTEAM-SPECIFICILLUSTRATIVE

Where Does My System End?

The boundary of the system is the line between what you can change and what you can only call. Finding it — payment provider, email, image storage, the customer's browser — tells you which interfaces are contracts with a stranger and which are conversations with yourself.

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

Which parts of the store are inside your system, which are outside, and how does knowing the difference change what you build at each edge?

The situation

I keep drawing the store as boxes and I keep putting the payment provider in the same kind of box as the cart. Someone asked "what happens when the provider changes their API?" and I realised I do not know which of my boxes I control and which I merely call.

The reflex

Draw everything the store touches as components of the store. The provider, the email sender and the image store go on the diagram next to the cart and the catalog; the diagram is complete, every box is a thing to build or configure, and completeness feels like understanding.

Why it stalls

The diagram makes no distinction between a box you can fix at midnight and a box that can change its behaviour without telling you. So the provider gets the same error handling as the cart — none — and the first time it is slow the checkout hangs.

What the reflex produces — and fails to produce
  • The diagram makes no distinction between a box you can fix at midnight and a box that can change its behaviour without telling you. So the provider gets the same error handling as the cart — none — and the first time it is slow the checkout hangs.
  • The browser is drawn inside the system because "we wrote the frontend". But the customer can close it, refresh it, send an old request twice, or run a modified copy; the backend that trusts it as if it were internal has put its boundary in the wrong place.
  • The questions that only make sense at a boundary — what if it fails, what if it is slow, what if it changes, who is authoritative — are not asked, because nothing on the diagram says where the boundaries are.
  • When the provider's API does change, the provider's types are found in the order table, the email template and the admin page. The boundary existed all along; nobody drew it, so nothing protected it.
ProblemUnderstandRequirementsConstraintsUnknownsDecompositionSmallest StepModelExperimentObserveDebugLearnIterate

The move

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

  • A boundary is the line between what you can change and what you can only call. Find it by asking, for each component on the diagram: if this misbehaves at three in the morning, can my team change its code? If yes, it is inside. If the answer is "we can open a support ticket", it is outside.
  • Apply the same test to the customer's browser and get an uncomfortable answer: you wrote the code, and you still cannot control what runs. The browser is outside. Anything that arrives from it is an input to validate, not a fact to trust.
  • For each thing outside, write down what it can do to you that an inside component cannot: fail without notice, be slow, change its contract, rate-limit you, send the same message twice, send messages out of order. That list is what the interface at the boundary has to survive (Treating External Systems as What They Are).
  • Then redraw the diagram with the boundary as a line. Every edge crossing it is an interface with a stranger and gets a contract, an adapter and a failure plan. Every edge inside it is a conversation with yourself and can stay informal until a second team or process makes it otherwise.

The line, drawn

The same store as before, redrawn with the boundary as the thing that matters. The kinds say which side each box is on: services and the database are inside; the provider, the email sender and the object store are external; the browser is a client, which for the purposes of trust is the same thing.

Every edge that touches an external node is one the reflex drew as an ordinary arrow. Each of them now carries a question the inside edges do not: what happens when the far side does something we did not plan for?

The store and what is not the store
untrusted inputcan fail, stall, changecan repeat, arrive earlymust not block an ordercatalog must survive itCustomer's browserStore backendStore databasePayment providerEmail senderImage storage
UserLLMAgentToolDataDecisionHumanGuardrail

Inside or outside is a decision as often as a fact

Some components are outside because they belong to someone else. Others are outside or inside depending on a choice you have not made yet, and the choice should be made knowing what it does to the edge. The decision below is that choice for the pieces of the store where it is open.

Neither answer is correct in general. The criteria are what you are choosing between: control and operational burden against someone else's reliability and someone else's contract.

Which side of the line?

For a capability the store needs, should we run it (inside) or rent it (outside)?

Inside — we run it

when The capability is core to what the store is, or its failure modes must be ours to fix, or the outside option imposes a contract we cannot live with. Image storage as a folder in V1 is a legitimate example.

cost We own uptime, backups, scaling and every bug. The edge is informal, which is cheap until a second process needs it.

Outside — we call it

when The capability is not our differentiation and someone does it better than we will — payments, email delivery. Nearly always right for money movement, because the regulatory surface is theirs.

cost A contract we do not control, a failure list we must handle, an adapter to keep their types out of ours, and a change we did not choose arriving on their schedule (The Build-vs-Buy Questions).

Outside for now, with a seam

when Not sure, and the cost of being wrong is asymmetric. Rent it, but talk to it only through an interface you own, so moving it inside later is one adapter, not a rewrite.

cost The seam is a small abstraction paid for up front; if the component never moves, it was cost without return.

What the boundary makes you ask

Drawing the line turns one vague worry — "the provider" — into questions with experiments. The board below is what checkout's boundary edges look like after the move; every unknown is something a person could go and find out this afternoon.

Boundary edges of checkout
known
  • The provider, the email sender and the browser are outside; the database is inside.
  • Prices and totals are computed inside; the browser sends ids and intent only.
unknown → question → experiment
  1. ? What if the provider is slow?

    becomes How long will the backend wait for a charge before telling the customer something, and what does it tell them if the outcome is still unknown?

    experiment Call the test-mode endpoint with an artificially short client timeout and write down, in one sentence, what the customer should see.

  2. ? Email failing.

    becomes If the receipt email cannot be sent, is the order still placed, and who retries the email later?

    experiment Point the email adapter at a dead address, place a test order, and check whether the order exists.

  3. ? The browser lying.

    becomes Which fields in the checkout request does the backend currently take at face value, and which of them could change money?

    experiment Send the checkout request by hand with a lower total and see whether the order records it.

How to do it

Most important first.

  • For every component, ask the midnight question: can we change its code? Write inside or outside next to each.
  • Put the browser outside. Then decide which of its inputs you trust (none) and which you validate (all), and where prices and totals are computed (inside) (Source of Truth).
  • For each outside component, list what it can do to you — fail, be slow, change, rate-limit, repeat — and which of those the store would notice today.
  • Mark every edge crossing the line. Those edges are the ones that need a contract (Interfaces Emerge From Boundaries) and a failure model (External Systems Fail).
  • Check whether anything from outside has leaked inside: provider types in your tables, provider error codes in your UI. Each leak is a place where their change becomes your change (Anti-Corruption Layer).

Worked on a concrete problem

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

  • The store, with the midnight test. Catalog, cart, checkout, orders, inventory, admin: inside. Database: inside — we run it, we can change its schema. Payment provider: outside. Email sender: outside. Image storage: outside if it is an object store we rent, inside if it is a folder on our server — the same feature lands on different sides of the line depending on a decision, which is the point. The customer's browser: outside.
  • Edges crossing the line: browser → backend (untrusted input), backend → provider (may fail, be slow, change), provider → backend (may repeat, may arrive before our own request returns), backend → email (may fail; nobody should lose an order because the receipt did not send), backend → image store (may be slow; the catalog should still render). Five boundary edges, each of which now has a failure list. The inside edges — checkout → cart, checkout → inventory — get none of that, on purpose.
  • The AI assistant that answers questions about company documentation: the model is outside (we call it, we cannot fix it, it changes), the document store is inside, and the user's question is untrusted input that may contain instructions aimed at the model. Drawing the line puts the prompt-injection question exactly where it belongs — on the boundary edge from user to model.

How you know it worked

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

  • The diagram has a line on it, and you can say for each box why it is on the side it is on.
  • The browser is on the outside, and at least one thing the backend used to trust from it — a price, a total, a user id — is now computed or checked inside.
  • Each outside component has a list of what it can do to you, and each item on the list has a place in the code where it is handled or a note saying it is not yet.
  • Provider-specific names appear only at the boundary edge, not in the order table.

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
  • ?If this component misbehaves at midnight, can my team change its code?
  • ?What arrives from outside that I am currently treating as a fact rather than an input?
  • ?For each thing outside the line, what can it do to me that an inside component cannot?
  • ?Where have another system's types or error codes leaked across the line into mine?

What can go wrong

How the move itself fails
  • Everything becomes a boundary. The cart module is treated as an external system with a versioned contract and an adapter, and the team spends its time on ceremony between components it owns. The move is about finding the real line, and inside it informality is a feature.
  • The boundary is drawn and then not used. The provider is marked outside and still gets a bare call with no timeout, because the failure list was written and not acted on.
  • The line is drawn where the org chart is instead of where control is. Another team's service in the same company is "inside" if a call to them gets it fixed and "outside" if it takes a quarter; the test is control, not employment.
  • The browser is put outside and then everything from it is rejected. Untrusted means validated, not refused; the cart id the browser sends is still the cart id.
What the move costs
  • Every edge marked as a boundary is an edge that now needs a contract, an adapter and a failure plan. Drawing the line honestly creates work; drawing it loosely hides it.
  • Treating the browser as outside means computing on the server what the browser already computed — duplicated logic in exchange for not trusting the copy you cannot see.
  • Keeping provider types out of the domain means a translation layer that has to be maintained as both sides change; on a system with one provider forever, it is cost without a visible return until the day it is not.
Misreads
  • "Outside means unreliable, so I should avoid depending on outside systems." Outside means uncontrolled. The provider is more reliable than your checkout; the point is that its reliability is not yours to fix, so the edge needs a plan.
  • "The boundary is the network." A library you vendored is inside despite running in your process; a service your company runs that you cannot get changed is outside despite sharing a data centre. The test is control.
  • "Once drawn, the boundary is fixed." Moving image storage from a folder to an object store moves it across the line, and every edge to it changes character. Redraw when a component moves.

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.

  • GENERALControl — can we change its code — is the boundary test in any system; for a library the boundary is the callers you do not know, for a data pipeline it is the upstream you do not run.
  • TEAM-SPECIFICOn a solo project everything you wrote is inside. In a company of many teams, another team's service is inside if a message gets it changed this week and outside if it takes a planning cycle; the same service moves across the line as the organisation changes.
  • ILLUSTRATIVEThe store, its provider and the midnight test are invented to show the shape of the line; no real provider or team is described.

Where the depth lives

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

Further
  • The manifesto's "What Are You Delegating?" cards at /manifesto/delegating are a boundary exercise in disguise: each card is something outside the line that you still have to understand.