Everyways · how-to

How Software Is Built

Behind every screen you have ever tapped is a set of buildings that a small number of people chose, arranged and now maintain. Here is what those parts are, what each one is for, how they fail, and how to decide which of them you actually need.

The campus behind this page is the system, and it follows along as you read. Drag the margins to move it — or use Hide the article, up in the corner, to push the words out of the way and have the whole thing to yourself.

01The shape almost everything has

Systems differ enormously in detail and barely at all in outline. Something runs near the user and cannot be trusted. Something runs on machines you control and makes the decisions. Something remembers. And there is a boundary between the first and the rest which is the single most important line on the map.

That is why the campus behind this page is drawn with a moat and exactly one bridge. Everything to the left runs on hardware you did not choose, on a network you cannot predict, in an environment a determined person can modify. Everything to the right is yours. Nothing that arrives from the left may be believed without being checked again on the right.

The one idea to keep

Architecture is the set of decisions that are expensive to reverse. Which language you use is not usually one of them. Where the trust boundary sits, what the source of truth is, and whether a piece of work happens inside the request or after it — those are, and they will still be shaping the system in five years.

Most of the buildings on the map exist for one of three reasons: to make something faster (the edge, the cache), to make something safer (the gateway, identity, the vault), or to stop something slow from blocking something quick (the queue, the workers). A system with none of them is not wrong — it is just one where none of those pressures has arrived yet.

A useful discipline when reading any architecture diagram: for every box, ask what would break if you deleted it. If the answer takes more than a sentence, that box is doing more than one job.

02The client: the only part anyone sees

The frontend is the product, as far as every user is concerned. It is also the part of your system you have the least control over: it runs on a phone from 2019 on a train, in a browser with four extensions injecting scripts, on a connection that will disappear halfway through a form.

Modern frontend work is mostly the management of three things — the state the user can see, the state the server has, and the gap between them. Nearly every hard bug in a client is somewhere in that gap: a stale list, a double-submitted form, a spinner that never resolves because nobody wrote the failure branch.

Rendering on the server

HTML arrives complete, so the first paint is fast and search engines can read it. Costs a server round trip for every interaction that needs new markup.

Rendering on the client

The browser downloads an application and builds the page itself. Interaction is instant afterwards; the first load is heavier, and it is dead without JavaScript.

The hybrid everyone lands on

Server-render the first view, hydrate it, then fetch as you go. This is what most frameworks now do by default, because it is the only option that is good at both ends.

Native and mobile

Better access to the device, worse deployment story: your users update when they feel like it, so old versions of your client will be calling your API for years.

Two properties matter more than the framework argument. How long until something appears, which is mostly a question of how many bytes have to arrive before anything can be drawn. And whether the thing that appears can be used — a page that renders in 400 ms and then blocks the main thread for two seconds is a page that feels broken.

Validation in the client is a courtesy, not a control

Checking the email field before submitting is good manners: it saves a round trip and tells the user sooner. It defends nothing. The request can be sent by anything, with any body, in any order. Every rule that matters has to be enforced again on the other side of the moat — and the ones that only exist in the interface are the ones that end up in incident reports.

Accessibility belongs in this section rather than in a box at the end. Semantic elements, focus order that follows the visual order, contrast you can read in sunlight, and everything reachable from a keyboard. It is the difference between a product some people cannot use and one they can — and in a lot of jurisdictions it is also the law.

03The edge: names, distance and the copy nearby

Before a request can be made at all, a name has to become an address. DNS does that, and it is cached at every level between the browser and the root — which makes it very fast and makes changes to it slow to take effect. The number attached to a DNS record, its time to live, is how long you have promised the internet it may keep believing an old answer.

Then there is distance. Light in fibre crosses the Atlantic in about sixty milliseconds each way, and no amount of clever code will beat physics. The fix is to stop making the round trip: put copies of anything that is the same for everybody in a few hundred locations, and answer from whichever is nearest. That is a content delivery network, and it is the highest-leverage thing on this entire map.

What the edge handlesWhy it belongs there
Static assetsScripts, styles, images and fonts never change per user, so they should never be computed per user.
TLS terminationThe handshake is several round trips; doing it near the user removes most of that cost.
Cached pagesA page that is the same for everyone can be served entirely from the edge, at which point your servers never learn the request happened.
Absorbing floodsA volumetric attack hits a network built for it rather than your one origin.
Edge functionsSmall pieces of logic — redirects, A/B assignment, auth checks — run near the user rather than after the ocean crossing.

The interesting design question is not "should we use a CDN" but what fraction of your traffic can be made cacheable. Splitting a page into a shell that is identical for everyone and a small personalised fetch is often the difference between eighty-six per cent of requests never reaching your servers and none of them being cacheable at all.

04The gateway: one door, and it is watched

Everything that reaches your own machines arrives through one place. That is a deliberate choice, not an accident of topology: a single entrance can be instrumented, rate limited, patched and reasoned about, and twelve entrances cannot.

  • TLS. Encryption ends here, so certificates live in one place and get renewed automatically. A certificate that expires on a Sunday is a rite of passage nobody needs twice.
  • Load balancing. Requests are spread across whichever instances are currently healthy, which is also how a deployment happens without anyone noticing.
  • Health checks. An instance that stops answering is taken out of rotation. This is the mechanism that turns "a server died" into a non-event.
  • Rate limiting. A per-client budget. It is the cheapest security control that exists and it removes most of what the internet throws at you.
  • Request filtering. Obviously hostile shapes — injection patterns, absurd payload sizes, known-bad clients — refused before any of your code runs.

A word about timeouts, because they belong here and almost nobody sets them until after their first incident. Every hop on this map should have a deadline. A request with no deadline does not fail; it waits, holding a connection, until the thing waiting on it also gives up. That is how one slow database becomes a total outage.

Deployments are a load balancer trick

Releasing a new version usually means starting instances running the new code, waiting for them to pass their health checks, moving traffic across, and stopping the old ones. Blue-green, rolling and canary releases are all variations on who moves when. It is worth knowing that the machinery of "zero downtime" is mostly this one building being careful about who it points at.

05Identity: two questions that are not the same

Authentication asks who is making this request. Authorisation asks whether they may have what they are asking for. They are answered by different code, they fail in different ways, and treating them as one thing is the most common serious security bug in applications that are otherwise well built.

Authentication is largely a solved problem you should not solve again. Sessions with a server-side store, or signed tokens with a short life, or — best of all for most products — delegating the whole thing to an identity provider so that you never store a password at all. Password storage in particular has exactly one correct answer, and it is a purpose-built hashing function that you did not write.

Sessions

A random identifier in a cookie, with the real state on the server. Easy to revoke instantly, because the server is the one remembering.

Tokens

Signed claims the server can verify without a lookup. Scales beautifully and is genuinely hard to revoke before it expires — so keep the life short.

OAuth & OIDC

The protocols behind "sign in with…". You get identity without holding credentials, at the cost of a redirect dance worth reading carefully.

Second factors

A password can be phished, reused or guessed. A passkey or an authenticator app moves the attack from "at scale, from anywhere" to "targeted, and difficult".

Authorisation is where the bugs live, because it is specific to your product and cannot be bought. The rule that saves you is simple and tedious: check ownership on every path, at the point of use. Not in the interface that hid the button. Not once, in the controller everyone remembers, while three other routes reach the same record. The classic failure is an endpoint that carefully verifies you are signed in and then hands you object number 9107 because you asked for it.

06The backend: where your product means something

This is the only building that knows what a customer, an order or a subscription is in your particular business. Everything else on the map is generic machinery you could swap for a competitor's. The services are not.

A request handler does roughly four things, in this order: work out who is asking, validate what they sent, apply the rules, and persist or fetch whatever that implies. Most codebases go wrong by letting those four blur into each other until the business rules are spread between a route handler, a database trigger and a piece of the frontend.

# one request, by the millisecond GET /orders/8814 ├─ tls + routing edge → gateway 3 ms ├─ authenticate verify token 1 ms ├─ authorise owner check 0.2 ms ├─ cache lookup MISS 0.4 ms ├─ db query SELECT … LIMIT 1 6 ms ├─ serialise json 0.6 ms └─ response 200 · 4.1 KB 41 ms total

The perennial argument is one service or many. Splitting a system into services buys independent deployment and independent scaling, and it costs you a network between things that used to be a function call — which means latency, partial failure, versioned contracts and a distributed transaction problem you did not previously have.

Start with one, and keep the seams

A well-organised single application with clear internal boundaries is easier to change than three services with unclear ones, and it can be split later along the seams you already drew. Almost nobody regrets starting with one deployable. A great many people regret starting with nine, and the ones who were right to did it because their teams needed to deploy independently — which is an organisational reason, and the honest one.

Whatever the shape, the interface between the client and the backend is a contract that outlives both. Version it, document it, and remember that old versions of a mobile app will be calling it long after you have forgotten the endpoint exists.

07Data: the part you cannot rebuild

Every other building on this map can be reconstructed from a repository in an afternoon. The database cannot be reconstructed from anything except a backup you have actually restored. That asymmetry should govern how much care each part gets.

For most products the correct default is a single relational database, and it will remain correct for far longer than the internet suggests. Relational databases give you transactions, constraints that make certain wrong states impossible, and a query language that answers questions you had not thought of when you designed the schema. Those are not legacy features; they are the reason the category has outlived four waves of replacements.

KindGood atThe cost
RelationalRelated records, transactions, ad-hoc questions, being correctYou must decide the shape up front and migrate it deliberately
DocumentNested records read and written whole; a schema that movesJoins and multi-record consistency become your problem
Key-valueEnormous volume, one access pattern, very low latencyAnything you did not design the key for is a full scan
Search indexRanked text, facets, typo toleranceA second copy of the truth that can drift from the first
Vector storeRetrieval by meaning rather than by keywordApproximate by design, and embeddings must be regenerated when the model changes
Object storeFiles: uploads, exports, backups, mediaNo transactions, and the bill is per request and per byte on the way out

A transaction is the promise that a group of changes either all happen or none do. It is what stops money leaving one account without arriving in another, and it is worth understanding properly rather than trusting by default, because the isolation level your database ships with probably permits more strangeness than you expect.

Migrations are the risky deploys

Changing code is reversible in seconds. Changing the shape of data is not — a dropped column is gone, and a rewrite of a large table can lock it long enough to count as an outage. The safe pattern is to expand, then migrate, then contract: add the new thing, write to both, backfill, switch reads, and only remove the old thing once nothing has referred to it for a while. It is four deployments instead of one, and it is why the database is still there.

Backups deserve one blunt sentence. A backup you have never restored is not a backup; it is a file with a hopeful name. Restore one on a schedule, to a real environment, and time how long it takes — because that number is your actual worst case, and you will only ever discover it under pressure otherwise.

08Caching: the cheapest speed, at a price

A cache is a bet that the answer you worked out a moment ago is still good enough to hand to the next person who asks. It is the most effective performance tool available — a hit costs a fraction of a millisecond where the real work cost twenty — and it introduces an entire category of bug where the system is confidently, quickly wrong.

There are more caches in a running system than most people count. The browser holds one. The CDN holds one. Your application holds one in memory, and probably a shared one as well. The database holds a page cache. The same value can exist in five places, each with its own idea of how long it is valid.

Time to live

Expire after n seconds. Simple, robust, and means someone gets a stale answer for up to n seconds. Usually the right first answer.

Invalidate on write

Delete the entry when the underlying thing changes. Correct and precise, until you find the fourth code path that writes without telling the cache.

Key by version

Put a version or a content hash in the key, so a new value simply has a new address. Nothing to invalidate — this is how asset files are done.

Stale while revalidating

Serve the old answer immediately and refresh in the background. Excellent for feeds and dashboards; wrong for anything that must be current.

Two failure modes are worth knowing by name. A stampede is what happens when a popular entry expires and a thousand requests all miss at once and all recompute the same thing — which usually takes down the very database the cache was protecting. And a poisoned cache is what you get when something user-specific is stored under a key that is not, so one person's data is served to everybody. The second one is a data breach, and it is more common than it should be.

The discipline that avoids most of this: cache derived things, not authoritative things, and be able to say out loud how stale any given answer is allowed to be. If you cannot answer that for a cache, you do not yet know what it is for.

09Queues: getting the slow part out of the way

Some work cannot happen while a user waits. Generating a report takes ninety seconds; sending an email depends on a third party having a good day; resizing a video is measured in minutes. Doing any of that inside a request means holding a connection open and losing everything if the browser closes.

So you write down the intent, put it on a queue, and answer immediately. A separate pool of workers pulls jobs off, does the slow thing, and records the result. The request that took ninety seconds now takes eleven milliseconds, and the ninety seconds happen somewhere nobody is watching a spinner.

What you have bought is responsiveness and the ability to survive a dependency being down. What you have paid is that "did it work?" is now a question with a delayed answer, and your users need to be told the ending somehow — a notification, an email, or a row that changes state when the page next asks.

Assume every job runs twice

Queues promise to deliver a message at least once, and the honest ones say so. A worker can crash after doing the work and before recording that it did, and the job will be retried. Everything a worker does therefore has to be safe to repeat — carry a key, check whether this exact job already happened, and make the second run a no-op. Idempotency is the whole discipline of this building, and skipping it produces the bug where a customer is charged three times and nobody can explain how.

Retries with backoff

Try again, waiting longer each time. Retrying immediately, in a loop, is how a small failure becomes a self-inflicted denial of service.

Dead letter queue

Somewhere for jobs that have failed too many times to go, so that they are visible rather than silently gone. Check it; it is where the truth is.

Queue depth

The single most useful number here. Rising depth means workers are losing; it is a leading indicator, unlike almost everything else you measure.

Ordering

Most queues do not guarantee it, and most designs quietly assume it. If order matters, say so explicitly and pay for it.

10Putting a model in the product

A language model is a new kind of building on this map, and the useful way to think about it is as a dependency with an unusual profile: very slow by the standards of everything else here, expensive per call, and non-deterministic — the same input can produce a different output tomorrow.

That profile dictates the architecture. Two seconds is a good latency for a model call and fifty times the budget of every other hop on the map, so the answer has to stream and the interface has to be designed for text arriving progressively. The cost is per token, so caching is not an optimisation but part of the design. And the non-determinism means you cannot test it with assertions the way you test everything else.

PieceWhat it isWhy you need it
InferenceA call to a model, usually someone else's APIThe generation itself; the slow, expensive part
EmbeddingsText turned into a vector of numbersLets you find things by meaning rather than by keyword
RetrievalFetching the relevant records and handing them to the modelThe model answers from your data instead of from memory
ToolsFunctions the model may call, with real effectsTurns "write about it" into "do it" — and raises the stakes accordingly
EvalsA fixed set of inputs with judged outputsThe only way to know whether a change made it better or worse

Retrieval is most of what makes this work. Do not ask the model to remember your data; find the eight relevant rows yourself, put them in the prompt, and instruct it to answer only from those. A model given the facts is a summariser, which is a job it is genuinely excellent at. A model asked to recall facts is guessing, and it will guess fluently.

The output is untrusted input from your own system

Anything the model produces has to be checked before it reaches a user or a database: did it cite records that exist, did it stay inside this user's data, is the JSON actually valid. And if the model reads anything a user can influence — a document, a web page, a support ticket — then that text can carry instructions. Prompt injection has no complete fix; you contain it by never letting the ability to read something imply the authority to act on it, and by keeping the model's tools narrow and its credentials short-lived.

Finally, decide in advance what happens when the model is unavailable, slow, or returns something unusable — because all three will happen this month. An AI feature with no defined behaviour for "no answer" is a feature that will occasionally show a user a blank box and a spinner forever.

11Security: layers, not a wall

Security is not a feature you add near the end. It is a property of decisions made throughout — and the useful mental move is to stop asking "is this secure?" and start asking what would this let someone do, and how much would it cost?

That question has a name. A threat model is one honest page: what you hold that is worth taking, who might want it, how they would try, and what you have decided not to defend against. It is worth more than any tool, because it is what tells you which of the following actually matter for you.

FailureWhat goes wrongThe control
Broken access controlA signed-in user reaches another user's recordsCheck ownership at the point of use, on every path
InjectionInput is treated as code — SQL, shell, HTMLParameterised queries and contextual escaping; never string concatenation
Leaked secretsA key in a repository, a log line, an error pageA secrets store, short-lived credentials, automatic scanning
Vulnerable dependenciesMost of your code was written by strangersLocked versions, automated scanning, an upgrade habit
Too much privilegeOne compromised component can reach everythingScope every credential to one job and expire it
No recordYou cannot tell what an intruder did, or whenAudit logs for sensitive actions, kept where the app cannot edit them

Secrets get their own building on the map for a reason. Database passwords, API keys and signing keys should be issued by a store rather than configured by hand, scoped to a single job, given a short life, and rotated on a schedule that runs whether or not anyone remembers. The point is not that leaks become impossible; it is that a leaked fifteen-minute read-only credential is an inconvenience rather than a company-ending event.

Encryption, in the two places it matters

In transit is TLS, everywhere, including between your own services — the inside of your network is not a safe room. At rest is the disk and the backups, which mostly protects against hardware walking out of a building. Neither does anything about an attacker with valid credentials, which is why the access control rows above sit at the top of the table.

One more, because it is where a lot of real compromises now begin: the pipeline that builds and deploys your software holds the credentials that can change production. Treat it as production infrastructure, because to an attacker it is the most valuable machine you own.

12Observability: finding out before your users tell you

Once software is running, most of the truth about it only exists in production. Observability is the ability to answer questions about a live system that you did not think to ask in advance — which is a higher bar than "we have some dashboards".

Metrics

Cheap numbers over time: request rate, error rate, latency percentiles, saturation. Excellent at telling you that something is wrong.

Logs

Discrete records of what happened. Structured, they are searchable evidence; unstructured, they are an expensive diary nobody reads.

Traces

One request's path across every building it touched, with timings. Usually the fastest way to find where it is wrong.

Alerts

Rules that wake a human. They should fire on symptoms a user would feel, not on every twitch a machine makes.

Measure the things users experience, not the things machines report. CPU at ninety per cent is not an incident if every request is still returning in eighty milliseconds; a healthy-looking fleet returning errors to one per cent of people absolutely is. And use percentiles rather than averages — an average latency of 90 ms can comfortably hide a p99 of four seconds, which is a real group of real people having a bad time.

Teams that do this well write down a service level objective — say, 99.9% of requests succeed within 300 ms over thirty days — which converts an argument about whether things feel slow into arithmetic. The failure the objective permits is an error budget: spend it on shipping while there is budget left, and spend it on reliability when there is not.

The one thing to instrument first

If you do nothing else, propagate a request id from the gateway through every building and put it in every log line and every error the user sees. It costs an afternoon, and it turns "a customer says something broke at about four o'clock" from an archaeology project into a search.

13Hosting: where all of this actually runs

Every building on this map is, in the end, a process on a computer that someone is paying for. The platform is the set of choices about which computers, how the processes get onto them, and what happens when one of them dies at three in the morning.

OptionSuitsWhat you give up
A single serverSmall products, prototypes, anything with one team and modest trafficNothing until it falls over — which it will, on a Sunday
Managed platform (PaaS)Most teams, most of the time: push code, get a running serviceControl over the details, and money once you are large
Containers + orchestrationMany services, many teams, genuinely variable loadA permanent operational surface that needs people who understand it
Serverless functionsSpiky, event-shaped work; glue; things that are idle most of the timeCold starts, execution limits, and a local development story that never quite matches

Two ideas underpin all four. The first is that a running service should be disposable: killable at any moment, replaceable by an identical copy, holding no state of its own that matters. That is what makes scaling a matter of arithmetic and deployment a matter of starting new ones. It is also why "stateless" is worth the inconvenience it causes everywhere else.

The second is that the arrangement should be written down as code. Infrastructure defined in files, in the repository, reviewed like anything else — so that the answer to "why is staging different from production?" is a diff rather than an investigation, and so that rebuilding the whole thing is a command rather than a memory test.

Environments, and the honest thing about staging

You want at least a local one, a shared production-shaped one, and production. Staging catches configuration and wiring faults that no test will, and it lies reliably about anything involving scale, real data, or the peculiar things real users do. Treat a green staging run as evidence, not proof — and put the effort you save into making production changes small and reversible instead.

14What breaks, and what to do about it

Everything on this map fails. Machines stop, networks partition, disks fill, certificates expire, third parties have incidents on your busiest day. Resilience is not the absence of failure; it is the property that a failure in one building stays in that building.

The most instructive failure is not something dying — that is easy to detect and easy to route around. It is something getting slow. A slow dependency means every caller still starts, still waits, and still holds a connection, so the damage spreads upstream to buildings that are working perfectly. That is how one unhappy database becomes a total outage.

Timeouts

Every call gets a deadline. This is the one that turns a slow dependency into a fast failure, which is a far better thing to hold.

Circuit breakers

After enough failures, stop calling for a while. It protects the struggling thing from you, and lets it recover instead of drowning.

Bulkheads

Separate pools per dependency, so the one slow integration cannot consume every connection the service has.

Graceful degradation

Decide in advance what a reduced version of the product looks like. A stale basket with a banner beats a blank page.

That last one is a product decision disguised as an engineering one, and it should be made calmly, in advance, rather than at 02:00 by whoever is on call. Which features may disappear? What may be shown stale, and how stale? What must never be wrong even if it means refusing the request? Write it down once and the incident becomes an execution rather than a debate.

Restore service first, understand afterwards

Debugging in front of affected users is a decision to make the outage longer. Roll back, fail over, turn the feature off — then investigate with the evidence you collected. The corollary is that the reversal path has to be routine and rehearsed: a rollback nobody has ever executed is not a plan, it is a paragraph.

15What it costs, and what it costs later

Every architectural choice has a bill attached, and the bill has two halves. There is the invoice — machines, storage, bandwidth, tokens — and there is the part nobody puts in the diagram: how much of your team's finite attention the arrangement will consume every week from now on.

The invoice half is usually dominated by a small number of surprising lines. Bandwidth leaving a cloud provider is priced far above bandwidth arriving. Object storage is cheap to hold and priced per request to read. Model calls are per token, in both directions, and a feature that quietly includes a large document in every prompt can cost more than the rest of the system combined.

Egress

Data leaving the provider. The line that surprises people, and the one a CDN in front of your origin removes most of.

Idle capacity

Machines sized for the peak, running at the trough. Autoscaling is mostly a cost control that happens to also handle spikes.

Tokens

Prompt plus completion, per call. Cache aggressively, retrieve narrowly, and use the smallest model that passes your evals.

Operational load

The real price of nine services and a bespoke platform: it is paid in attention, weekly, forever.

The second half is the one worth being most careful about, because it compounds. Every component you add is a thing to patch, monitor, upgrade, understand and explain to the next person who joins. A system a small team can hold in their heads is faster to change than a technically superior one they cannot — and speed of change is, in the end, what almost every business is actually buying.

16Choosing: how to end up with less of this

Almost every building on this map was added because something hurt. The mistake that costs teams the most is adding them in advance, on the assumption that the pain is coming — and then paying for all of it for years while serving four hundred users.

  1. Start with the smallest thing that could work. One deployable application, one relational database, one managed host. That configuration will comfortably serve more traffic than most products ever see, and it leaves you the option of anything else.
  2. Add a building when you can name the pain. Not "we will need a queue eventually" but "this endpoint takes ninety seconds and users are closing the tab". The named pain also tells you what "fixed" looks like.
  3. Prefer boring, widely-used technology. Its failure modes are documented, its bugs have been found by strangers, and you can hire people who already know it. Spend your novelty budget on the part that is actually your product.
  4. Let the trust boundary be the one thing you never compromise. Every rule enforced on the far side of the moat, every time, whatever the client already checked.
  5. Make the source of truth obvious. For each piece of data, one place is right and everything else is a copy. Systems become unmaintainable when nobody can say which is which.
  6. Instrument before you optimise. Guesses about what is slow are wrong at a remarkable rate. A trace costs an afternoon and settles the argument.
  7. Write down the decisions and the reasons. A short record of what you chose, what you rejected and why. It is what stops the same argument recurring every eighteen months, and it is the best thing you can hand a new joiner — or an AI agent working in the codebase.
  8. Keep it small enough to hold in your head. The best architecture is not the most capable one; it is the most capable one your team can still reason about at three in the morning.

What the map is really showing

Look at the campus behind this page. Fifteen buildings, one bridge, and a single request touching six of them to answer a question. None of it was designed at once, none of it is required to begin, and every piece of it exists because somebody could name what hurt. Build the town first. The campus comes later, and only as far as you need it.

Glossary

TermIn one line
APIThe contract by which one program asks another for something.
Trust boundaryThe line past which nothing may be believed without being checked again.
CDNA network of caches near users, holding copies of anything that is the same for everybody.
TLSThe encryption behind the padlock; what makes the s in https.
Load balancerThe thing that spreads requests across healthy instances — and quietly performs your deployments.
AuthenticationEstablishing who is making a request.
AuthorisationDeciding whether they may have what they asked for. A different question.
StatelessHolding nothing of its own between requests, so any copy is as good as any other.
TransactionA group of changes that either all happen or none do.
MigrationA deliberate, versioned change to the shape of stored data.
IdempotentSafe to do twice: the second attempt changes nothing.
QueueA durable list of work to be done later, by somebody nobody is waiting on.
Cache invalidationGetting rid of a stored answer once it stops being true.
EmbeddingText turned into numbers, so that similar meanings sit close together.
RetrievalFinding the relevant records and handing them to a model so it answers from facts.
Prompt injectionHostile instructions hidden in content a model reads, aimed at making it act against its operator.
EvalA fixed set of inputs with judged outputs, used to tell whether a change helped.
ObservabilityMetrics, logs and traces good enough to answer new questions about a live system.
SLOA written reliability target, and the budget of failure it implies.
Circuit breakerStopping calls to a failing dependency for a while, so it can recover.
Infrastructure as codeThe arrangement of machines and services, described in files and reviewed like any other change.
EgressData leaving a provider's network, and the line on the bill that surprises people.

Go deeper

  • MDN Web Docs — the reference for everything that happens in the client.
  • OWASP Top Ten — the recurring shapes of application security failure, with the access-control ones first for good reason.
  • OWASP Cheat Sheet Series — short, practical guidance on authentication, session management, secrets and the rest.
  • Google SRE Books — service level objectives, error budgets, overload and incident response, free online.
  • Use The Index, Luke! — how database indexes actually work, which is the highest-value thing most backend developers are missing.
  • The Twelve-Factor App — dated in places, still the clearest statement of why services should be disposable and configured from the environment.
  • OpenTelemetry — the vendor-neutral way to emit traces, metrics and logs.
  • How Software Gets Made — the companion to this page: how a change gets from an idea to running here.
  • How the Internet Works — what is happening in the wires between the client district and the bridge.
1

Loading… Starting the simulation.