Learn Backend Engineering

Design, build, scale, secure, debug and operate the service behind the contract. Twenty-eight modules, from what a backend actually is to debugging one in production.

RequirementAPI ContractApplication LogicData AccessExternal DepsConcurrencyFailureSecurityObservabilityDeploymentScale

Backend Fundamentals

7 lessons

What a backend actually is once the framework is removed: the request lifecycle end to end, which responsibilities belong to the server because they cannot be trusted to the client, and why every input from outside the process is untrusted.

HTTP Servers

7 lessons

What a server does between a socket and a response: accept, parse, build a request object, route, execute, serialize, write bytes. The part frameworks hide most completely.

Anatomy of an HTTP Server
▶ lab

The seven things every HTTP server does between a listening socket and the last byte written, whatever framework sits on top.

Q · What does an HTTP server actually do between a listening socket and the last byte of a response?
Accepting Connections

A connection is not a request. Listen, backlog, accept and file descriptors decide what happens to traffic before your code exists.

Q · What happens to a request between the client's TCP handshake and the first line of my server code?
Parsing HTTP

Turning a byte stream with no message boundaries into a request — and why the parser is a security component, not a formality.

Q · How does a stream of bytes become a request object, and what decisions does the parser make on my behalf?
Request and Response Objects

What `req` and `res` really are: a mutable view over a socket, with a body that has not been read and a response that has a point of no return.

Q · What is the `req` object my handler receives, and why does the response sometimes refuse to be changed?
Status Codes From the Server's Side

A status code is an operational signal: it decides who gets paged, what retries, and whether the number is counted against you.

Q · Which status code should this failure return, given that the code decides retries, alerts and blame?
Keep-Alive and Connection Reuse

Reusing a connection removes a handshake from every request — and introduces a timeout you must coordinate with every hop.

Q · What does reusing a connection actually save, and what new failure does it create?
Request Bodies and Streaming

A body is bytes arriving over time at a rate the client controls, which makes buffering a memory decision and limits a survival requirement.

Q · Should this body be buffered into memory or streamed, and what does either choice cost me under load?

Backend Runtime Models

7 lessons

Event loops, threads, workers and processes — the runtime model decides what "slow" means for your service. Taught as concurrency models rather than framework slogans.

Backend Runtime Models
▶ lab

Four ways a server serves many requests at once, and what each one makes cheap, expensive and dangerous.

Q · While one request is waiting on the database, what is my server doing with the other two hundred?
The Node Event Loop

One thread runs your JavaScript, a small pool runs some of the I/O, and knowing which is which explains most Node production behaviour.

Q · If Node is single-threaded, how does it serve thousands of concurrent requests — and what is it actually single-threaded about?
Blocking the Event Loop

One function that does not yield holds the only thread that makes progress, so every concurrent request pays for it.

Q · Why did latency rise on every endpoint at once when only one of them changed?
Python Runtime Models

Sync workers, threads, async and processes are four different services with the same source code — and the GIL explains which is which.

Q · Which Python concurrency model does my service actually use, and what does the GIL stop it from doing?
Worker Processes

Running N copies of your service in one machine buys cores and isolation, and multiplies every per-process resource by N.

Q · What actually changes when one process becomes eight, on the same machine?
C++ Backend Services

When a backend is infrastructure, no garbage collector and direct control of memory buy predictable tail latency — at a price paid in engineering time and safety.

Q · When is a backend service worth writing in C++, and what does that choice actually buy?
Choosing a Runtime

A decision made once, changed rarely and paid for daily — decided by workload shape, ecosystem and who is on call, not by benchmarks.

Q · How do I choose a runtime for a new service without arguing about benchmarks?

Routing & Handlers

6 lessons

How a method and a path become a function call, how precedence resolves ambiguity, and what a handler should and should not be responsible for.

How a Route Becomes a Function Call

A route table is a lookup structure over method and path; everything else about routing follows from which structure your framework chose.

Q · What happens between `POST /orders/42/items` arriving as bytes and your handler function being invoked?
Path Parameters

A path parameter is an attacker-supplied string that happens to be positioned where you expected an identifier.

Q · A path segment is a variable. What has to happen to it before a handler can use it?
Query Parameters

The least standardised part of an HTTP request, parsed differently by every stack, and the usual entry point for unbounded work.

Q · The query string has no schema and no agreed parsing rules. How do you accept one safely?
Route Precedence

When two routes can match one path, something decides which wins — and in half of all frameworks that something is the order of lines in a file.

Q · Two routes could match the same request. Which one runs, and did you choose that or inherit it?
Running Two API Versions in One Service

API Design decides the versioning policy; this is what the policy costs inside a running process, and how to pay it without forking the codebase.

Q · The contract has to change and old clients cannot be upgraded. How does one service serve two versions without becoming two services?
What a Handler Is Responsible For

A handler is an adapter between HTTP and one application operation — parse, resolve caller, call, map, return — and everything else it does belongs somewhere it can be reused and tested.

Q · What belongs inside a request handler, and what is it borrowing from layers that should own it?

Middleware

6 lessons

The pipeline every request passes through, why its order is a correctness decision and not a style one, and how cross-cutting concerns compose without leaking into handlers.

The Middleware Pipeline

Middleware is function composition around a handler, with a phase on the way in and a phase on the way out — not a list of things that run first.

Q · What is middleware actually, once the framework's `next()` is taken away?
Middleware Ordering Is a Correctness Decision

The chain is a dependency graph flattened into a list; reordering it does not tidy the same behaviour, it produces different behaviour.

Q · Why does the same set of middleware behave differently when you change the order?
Authenticate First, or Rate-Limit First?

Authenticating first means an unauthenticated flood still costs you crypto and a user lookup; rate-limiting first means your key is an IP, which is coarse and evadable. Both are true, so you do both, with different keys.

Q · Should rate limiting run before or after authentication?
The Error Boundary

One place that turns any failure below it into a response the client can act on and a log line you can investigate — plus the specific failures it will not catch.

Q · When something below fails, what turns that into a response, and what decides which response?
Request Context Propagation

Getting the correlation id, principal, tenant and deadline from the outermost middleware to a log line five layers down — without an extra argument on every function, and without a global that lies.

Q · How does per-request state reach code deep in the call stack without being threaded through every signature?
What Belongs in the Pipeline

A concern belongs in middleware if it is uniform, transport-level, needed even when no handler runs, and cheap — which rules out several of the things most often put there.

Q · Which concerns belong in the middleware pipeline, and which ones only look like they do?

Application Layering

7 lessons

Service layers, repositories and the transport/application/domain/infrastructure split — including when each is genuine structure and when it is ceremony that adds indirection without behaviour.

The Service Layer

A use case expressed as a plain function that knows nothing about HTTP — which is what lets a job, a CLI and an endpoint share it.

Q · Where does business logic go once more than one caller needs it?
The Repository Layer

A named place for the queries your domain asks, so the definition of "active subscription" lives once instead of in eleven call sites.

Q · What does a repository buy you that calling the ORM directly does not?
When the Repository Is Just Indirection

A repository whose methods are one-line passthroughs to the ORM adds a file, a name and a hop, and removes no decision from anyone.

Q · When does wrapping the ORM cost more than it buys?
Transport, Application, Domain, Infrastructure

Four layers, one rule that matters — dependencies point inward — and a scale at which the whole thing is overhead.

Q · What are the layers of a backend service, and which rule about them is load-bearing?
Alternatives to Layering

Vertical slices, transaction scripts and hexagonal are not lesser versions of layering — they optimise for different changes, and one of them probably matches yours.

Q · If layered architecture is not the only option, what are the real alternatives and what does each optimise for?
Fat Controllers

The 300-line handler is a real production problem for a specific reason: it puts a payment call inside a database transaction and nobody can see it.

Q · What actually goes wrong when the handler does everything, beyond it being hard to read?
Dependency Management Without the Container

Passing a dependency in instead of importing it is the whole idea; a container is one way to do the wiring and is not the idea.

Q · How should code get hold of the things it depends on, and who decides which implementation it gets?

Validation & Trust

7 lessons

Three different validations that are routinely confused: is this well-formed, is this allowed by the business, and is this consistent with what the database already holds.

The Three Validations

Well-formed, permitted, and consistent are three different questions with three different enforcement points — and only the last one survives a race.

Q · When someone says "we validate that", which of three completely different checks do they mean?
Transport Validation

The only check that needs no state: is this payload the right shape, the right types, and small enough to look at?

Q · What can a schema at the edge actually guarantee, and what does it silently let through?
Business Validation

Rules that need loaded state and an actor — and the fact that every answer they give is already stale.

Q · Where do rules that need to look something up belong, and what is the guarantee they give you?
Database Constraints

The only check evaluated inside the write — which is why it is the only one that survives two requests arriving at the same instant.

Q · Why is "email must be unique" a database problem rather than an application one?
Parse, Do Not Validate

A check that returns a boolean throws away what it learned; a check that returns a typed value hands the knowledge to every line below it.

Q · Why does validation keep happening more than once, in more than one place, with slightly different rules?
Every Input Surface

Body, query, path, headers, cookies, files, webhooks, external responses — and the second-order case where your own database hands back something a request wrote.

Q · Which surfaces carry untrusted input, and what is the specific check each one needs?
Reporting Validation Failures

Three layers reject for three reasons, so one 400 with a sentence in it is the wrong answer to all three.

Q · What should a rejected request actually return, and how much can you safely say?

Serialization & DTOs

5 lessons

Turning runtime objects into bytes and back, what that costs in CPU and allocation, and why the database row is the wrong thing to hand a client.

Authentication

7 lessons

Establishing who is calling: credentials, sessions, tokens, OAuth and API keys, from the backend's side of the problem rather than the protocol's.

Authentication in a Backend

Turning an untrusted credential into an authenticated principal, once, early, in one place — and nothing more than that.

Q · What is the backend actually doing when it authenticates a request?
Credentials and Password Handling

Store passwords with a slow, salted, purpose-built hash from a maintained library. Everything else in this lesson is a consequence of that sentence.

Q · What does a backend have to do with a password, from the moment it arrives to the moment it is verified?
Session Authentication

The server keeps the state and the client carries an opaque handle. Revocation is a delete; the cost is a lookup on every request.

Q · What does a backend actually hold when a user is "logged in" with a session?
Where Sessions Live

Process memory, a database table, a shared cache or a distributed store — four answers with different scale ceilings and different things that happen when they fail.

Q · Where should session state actually be kept, and what breaks at each choice?
Token Authentication and the Revocation Problem

A self-contained token removes the lookup by carrying its own claims — and removing the lookup is exactly what makes immediate revocation hard. That is the trade, and it is the whole lesson.

Q · What do you give up when a token can be verified without asking anyone?
OAuth and OIDC From the Backend Side

Three roles, two very different tokens, and one rule: use a maintained library, because the parts you would get wrong are the security parts.

Q · What does your backend actually do in an OAuth flow, and which role is it playing?
API Keys

A long-lived secret that identifies an application rather than a person — cheap to verify, easy to leak, and revocable only if you designed for it.

Q · When is a long-lived static key the right credential, and what does it take to run one safely?

Authorization

8 lessons

Deciding what the caller may do — role-based, attribute-based, and the object-level check whose absence is the most common serious backend vulnerability there is.

Authorization in Backends

Every request carries a claim about what the caller may do. The backend is the only place that claim can be tested.

Q · Who decides whether this specific request is allowed, and where does that decision actually live?
Authentication vs Authorization

"Who are you" and "may you do this" are different questions with different answers, different failure modes and different blast radii.

Q · Why is conflating authentication and authorization the most common serious backend security mistake?
Where the Check Belongs

A hidden button is not a control. Middleware, handler, service and query each enforce something different — and only one of them is a guarantee.

Q · At which layer should an authorization check run, and what does each layer actually guarantee?
Role-Based Access Control

Roles group permissions so people can be granted a job, not a list. What roles cannot express is anything about the object.

Q · When is "what role are you" a sufficient authorization model, and what does it fail to say?
Attribute-Based Access Control

Rules over attributes of the principal, the resource and the context — more expressive than roles, and correspondingly harder to reason about.

Q · When do roles stop being enough, and what does moving to attribute rules actually cost?
Object-Level Authorization

A user can be perfectly authenticated, hold exactly the right role, and still have no business touching project 123.

Q · Who checks that this authenticated user may act on this particular object, and where does that check have to happen?
Multi-Tenancy

One deployment serving many customers, where the worst possible bug is showing one of them another one's data.

Q · What changes in a backend when one deployment serves many customers who must never see each other?
Tenant Isolation

The tenant comes from the authenticated principal. Any other source — header, subdomain, path, body — is an authorization bypass with extra steps.

Q · Where does the tenant identifier come from, and how do you make it impossible to forget?

Database Access

9 lessons

ORM, query builder or raw SQL as an engineering decision with consequences, plus the query patterns and pool limits that decide how a backend behaves under load.

Choosing a Data Access Layer

ORM, query builder, raw SQL and stored procedures as four points on a spectrum, chosen per query rather than per project.

Q · ORM, query builder, raw SQL or stored procedure — which one, and on what evidence?
What an ORM Actually Does

Object method to generated SQL to database, plus the identity map, unit of work and lazy proxies that decide when statements are issued.

Q · When I call a method on an object, what SQL runs, and when?
What an ORM Buys and What It Costs

An honest ledger: real productivity on entity-shaped work, real opacity on query count, plans and complex reads.

Q · What do I actually gain from an ORM, and what am I paying for it?
The N+1 Query Problem
▶ lab

One query for the list, one more for every row: 100 users become 101 statements, and the source code shows none of it.

Q · Why does an endpoint that reads one table issue a hundred queries, and how do I see it before production does?
Eager Loading and Batching

The two general fixes for per-row queries — load the relation up front, or collect the ids and fetch once — and what each one over-fetches.

Q · How do I load related data in a bounded number of queries without fetching things nobody asked for?
Query Builders

Composing SQL structurally in the host language: dynamic filters without string concatenation, and no mapping layer to explain.

Q · How do I build a query whose shape depends on runtime input without concatenating strings?
Raw SQL in Application Code

When to write the statement yourself, how to keep it parameterized and findable, and what you take on when you do.

Q · When is hand-written SQL the right call, and how do I keep it from becoming an unmaintainable pile of strings?
Schema Migrations from the Application Side

Schema change as a deployment problem: two code versions run at once, and some `ALTER TABLE` statements take a lock that stops the service.

Q · How do I change the schema of a database that a running service is using right now?
Connection Pools
▶ lab

The pool is what actually bounds your concurrency: 1,000 requests against 20 connections means 20 running and 980 waiting, silently, until they time out.

Q · How many database queries can my service really run at once, and what happens to the rest?

Transactions

7 lessons

Which operations belong in one atomic unit, why a network call inside a transaction is a resource problem, and what to do when a commit and a message must both happen.

Transactions from Application Code

BEGIN, COMMIT and ROLLBACK as things your code controls: bound to one connection, ended by an error you did not expect, and retried when the database says so.

Q · What does a transaction actually give my handler, and what do I have to do to get it?
Where the Transaction Boundary Goes

Which operations must commit together, which merely happen nearby, and why "the whole handler" is almost never the right answer.

Q · Which of these operations belong inside the same transaction, and which are just adjacent in time?
One Transaction or Two

Splitting a unit of work trades an atomicity guarantee for shorter locks — and buys you an intermediate state you now have to design.

Q · Should this be one long transaction or two short ones, and what do I owe the state in between?
External Calls Inside a Transaction

A five-second payment call between BEGIN and COMMIT holds a pooled connection and every lock the transaction took, for five seconds, on every request.

Q · What does it actually cost to call another system while a database transaction is open?
The Dual Write Problem

The commit succeeds and the publish fails, or the publish succeeds and the commit rolls back. Two systems, no shared transaction, and no ordering that fixes it.

Q · How do I make a database write and a message publish either both happen or neither?
The Transactional Outbox

Write the event as a row in the same transaction as the state change, then publish it from a background reader — at-least-once, by design.

Q · How do I guarantee that an event is published for every committed change, exactly as reliably as the change itself?
Deadlocks in Application Code
▶ lab

Two transactions take the same two locks in opposite orders, each waits for the other, and the database kills one of them — with an error your code has to expect.

Q · Why does one of my transactions get aborted with "deadlock detected", and whose fault is it?

Caching

7 lessons

Cache-aside, invalidation, stampedes and the local-versus-distributed decision — including the cases where a cache adds a consistency problem and buys nothing.

Caching in Backends

A cache trades correctness-in-time for work avoided; everything else in this module is about controlling that trade.

Q · What does a cache actually buy a backend, and what does it cost that a faster query would not?
Cache-Aside

Read the cache, miss, read the database, write the cache — and the four things that go wrong in those four steps.

Q · What is the standard read-through pattern, and where exactly does it leak?
Cache Invalidation

The database changed. How does the cache find out? Four answers, each with a different failure when it does not.

Q · When the underlying data changes, how does the cached copy learn about it — and what happens when that message is lost?
TTL and Expiry

A TTL is a staleness budget written as a number, plus the only invalidation mechanism that cannot fail.

Q · How long should an entry live, and why is a round number almost always the wrong answer?
Cache Stampede

One popular key expires, every in-flight request misses at the same instant, and all of them run the same expensive query at once.

Q · A single key expires and the database falls over. How does one missing entry become an outage?
Local vs Distributed Cache

In-process is faster and per-instance; shared is consistent and one more thing that can be down. The choice is about invalidation, not speed.

Q · Should the cache live inside the process or in a shared store, and what does each choice do to correctness?
When Not to Cache

A cache buys you a consistency problem and an availability dependency. Sometimes it does not buy anything back.

Q · When is adding a cache the wrong answer, and what should be tried first?

Background Jobs & Queues

10 lessons

Work that does not belong in the request path: deciding what to defer, the queue lifecycle from enqueue to dead-letter, and what happens when producers outrun consumers.

Background Jobs

Work that outlives the request that asked for it — and the four guarantees you give up to move it there.

Q · What does moving work out of the request path actually change, beyond making the response faster?
Request or Background?

Five questions that decide where work runs — and the reminder that deferring is a cost, not a default.

Q · How do I decide whether this piece of work belongs in the request or in a queue?
Job Queues

Enqueue, claim, process, ack, retry, dead-letter — the six-step lifecycle every queue implements, however it spells them.

Q · What happens to a message between being enqueued and being finished with, and which step is the one that loses work?
Queue Semantics

Ordering, duplicates, retries, visibility timeouts and poison messages — the five properties that differ between every broker you will use.

Q · What does my queue actually guarantee about order and delivery, and what is my code responsible for instead?
Job Idempotency

Delivery will repeat, so the effect must not. How to make a worker safe to run twice, including concurrently.

Q · The same message is delivered twice. How do I guarantee the effect happens once?
Scheduled Jobs

Cron in a single process is a timer. Cron on three instances is three timers, and the job runs three times.

Q · How does recurring work run exactly once when several identical instances are all convinced it is their turn?
Dead-Letter Queues

Somewhere for work that will never succeed, so that one poison message cannot consume the fleet — and a human who is expected to look.

Q · What happens to a message that fails every time, and who finds out?
Backpressure

When producers outrun consumers, something has to give. Backpressure is choosing what, instead of letting memory choose for you.

Q · Work is arriving faster than it can be processed. What should the system do about it?
Worker Scaling

More workers help until the shared dependency saturates, at which point they make everything worse — including the requests still in the path.

Q · How many workers should there be, what signal decides that, and when does adding more stop helping?
Queue Backlog

The queue is growing. Four possible causes, and the recovery that is right for one of them makes two of the others worse.

Q · The backlog is climbing. What is actually wrong, and what should I do in the next ten minutes?

Events

6 lessons

Commands ask for something to happen; events state that it did. What that distinction changes about coupling, naming, consumers and the consistency of everything downstream.

Commands vs Events

A command asks for something to happen and has exactly one handler; an event states that something happened and has any number of consumers.

Q · What actually changes when I stop telling a service what to do and start telling it what happened?
Event-Driven Backends

Publishing a fact instead of calling the next step, what that actually buys, and the honest list of what it costs.

Q · What does my backend gain, and pay, by publishing an event instead of calling the next step directly?
Naming Events

Past-tense domain facts decouple; procedural names smuggle the consumer's behaviour into the producer.

Q · Why is `OrderCreated` a better event name than `ProcessOrderEvent`, and what breaks when I get this wrong?
Writing Event Consumers

A consumer is a program that will see every message twice, some out of order, and one that poisons it.

Q · What does a correct event consumer have to handle that a request handler does not?
Keeping a Search Index in Sync

Database change to event to indexer to search engine — and the fact that when it breaks, nothing errors and search is quietly wrong.

Q · How does a search index stay consistent with the database, and how would I even know that it had not?
Eventual Consistency in Practice

Once work happens after the response, some reads are stale — and the engineering is in bounding it, showing it honestly, and knowing when it has stopped converging.

Q · My write returned 200 and the next read does not reflect it. Is that a bug, and what do I owe the user?

External Dependencies

9 lessons

Every call leaving your process can be slow, wrong or absent. Timeouts, retries, backoff, circuit breakers, bulkheads and the rate limits you both enforce and obey.

Calling Something You Do Not Control

Eight questions every outbound call has to answer, and the fact that a dependency's availability becomes yours the moment you await it.

Q · What do I have to decide before my code calls a system I do not operate?
Timeouts

Never assume an external dependency returns. A call with no timeout is a resource leak waiting for a bad day.

Q · How do I decide how long to wait for something outside my process — and what happens if I never decide?
Retries

"Retryable" and "safe to retry" are different properties, and confusing them is how a transient error becomes a duplicate charge.

Q · When should I retry a failed call, and what has to be true before retrying is safe?
Backoff and Jitter

Waiting longer between attempts stops you hammering a struggling dependency; randomising the wait stops every client from hammering it in unison.

Q · How long should I wait between retries, and why does adding randomness matter so much?
Circuit Breakers

After a dependency has failed enough, stop calling it: fail fast, protect your own capacity, and probe carefully for recovery.

Q · When a dependency has been failing for a while, why is continuing to call it worse than refusing to?
Bulkheads

Give each dependency its own bounded slice of your resources, so one slow dependency cannot consume every worker you have.

Q · Why does a slow recommendation service take down endpoints that never call it?
Rate Limiting

Deciding which caller has had enough, along which dimension — and why the counter's atomicity is the part that makes it correct.

Q · How do I stop one caller from consuming capacity that belongs to everyone, and what exactly am I counting?
Rate Limit Algorithms

Fixed window, sliding window, token bucket and leaky bucket — what each one allows, what it refuses, and the burst each permits.

Q · Which counting algorithm should enforce my limit, and what does each one actually allow through?
Email and Notifications

The integration everyone builds first and treats casually: an external provider, at-least-once delivery, and a side effect that cannot be taken back.

Q · Why is sending an email harder than calling an API that sends an email?

Webhooks

5 lessons

Inbound HTTP you do not control: signature verification on the raw payload, duplicate delivery as the normal case, and ordering you cannot assume.

Idempotency

6 lessons

The property that makes retries safe. Keys, storage, scope and expiry — and the difference between a queue delivering once and your business logic acting once.

Backend Concurrency

7 lessons

Two requests, one row. Optimistic versioning, pessimistic locks, atomic operations, and the bounded-resource thinking that keeps a burst from becoming an outage.

Backend Races

Two requests, one row: where concurrency bugs actually live in a backend, and why they never appear in development.

Q · Two requests read the same row, both decide it is fine, and both write. Which one is wrong?
Optimistic Concurrency

Read a version, write only if it has not changed, and treat zero rows updated as a conflict — never as success.

Q · How do I let two users edit the same record without one silently overwriting the other?
Pessimistic Locking

SELECT ... FOR UPDATE serialises access to a row — and holds a lock, a connection and a transaction while you do it.

Q · When is it right to stop other requests from touching a row rather than detecting that they did?
Atomic Operations

Do it in one statement the database evaluates indivisibly, instead of reading, deciding and writing from application code.

Q · Can the database make this decision for me, so there is no window for anyone to write into?
Unbounded Concurrency

Work that starts without a limit does not fail gracefully — it consumes memory, connections and downstream capacity until something breaks.

Q · What stops my service starting more work than it can finish?
Request Coalescing

When N concurrent requests need the same expensive result, do the work once and share it — the in-process answer to a stampede.

Q · A thousand requests all miss the cache for the same key at the same moment. Do I really run that query a thousand times?
Resource Limits

Every finite resource needs an explicit limit, or the system discovers its own — at the worst possible moment, in the worst possible way.

Q · Which limits does my service have, and which of them did I actually choose?

Errors & Observability

9 lessons

An error taxonomy that maps causes to responses, boundaries that stop internals leaking, and the logs, metrics and traces that let you answer questions you did not anticipate.

An Error Taxonomy That Maps Cause to Response

Eight kinds of failure, each with a different status, a different caller action and a different owner — instead of one 500 for everything.

Q · When something goes wrong in a handler, how do I decide what the caller should be told and what they should do about it?
Error Boundaries: Three Translations, Not One

A driver error becomes an application error becomes an API response — and each translation adds context while removing internals.

Q · Where should an error be caught, and what should it look like at each layer it passes through?
Not Leaking Your Internals

Stack traces, SQL fragments, internal hostnames and library versions in an error response are free reconnaissance for an attacker.

Q · What is safe to put in an error response, and what am I giving away without noticing?
Correlation Ids That Survive Every Hop

One identifier that follows a request through services, queues and workers — including the hop into a background job, which is where it is usually dropped.

Q · A customer reports a failure at 14:32. How do I find every log line, in every service, that belongs to that one request?
What a Backend Should Actually Log

Six questions every log line should help answer, and the one category of data that must never appear in one.

Q · What do I log, at what level, so that a production question can be answered without redeploying?
Structured Logging

Log events as typed key-value records rather than sentences, because the consumer is a query engine, not a person reading a terminal.

Q · Why does it matter whether a log line is a sentence or a JSON object?
The Metrics a Backend Must Emit

Request rate, error rate, latency, in-flight requests, pool usage, queue depth, cache hit rate and dependency latency — eight numbers that make a service legible.

Q · Which numbers does a backend have to publish for anyone to know whether it is healthy?
Tracing From the Backend's Side

What a service must emit and propagate so one request's path across processes becomes a single readable timeline.

Q · A request takes three seconds and touches five services. Which one spent the time, and what do I have to emit for that question to be answerable?
Health Checks: Startup, Readiness, Liveness

Three different questions with three different consequences — and a liveness check that fails on a dependency outage turns a bad hour into a much worse one.

Q · What should a health endpoint check, and what happens when it says no?

Files & Object Storage

6 lessons

Uploads that do not go through your process, the bucket/key/object primitive underneath every provider's SDK, and what still has to happen after the bytes land.

File Uploads Through the Backend

The obvious path — client to backend to storage — makes your request handler a bandwidth-bound file mover, and it is still the right answer sometimes.

Q · What actually happens when a user uploads a file to your API, and what does routing those bytes through your process cost?
Presigned URLs

Your backend issues a signed, expiring permission slip; the client uploads directly to storage; your process never sees a byte — which is the benefit and the cost.

Q · How can a client write to your private storage bucket without holding your credentials, and what do you give up by never seeing the bytes?
Object Storage

A bucket holds objects addressed by a key. That primitive — not any provider's SDK — is what you are actually programming against.

Q · What is the storage primitive underneath every cloud file API, and how does it differ from the filesystem you are picturing?
Choosing an Upload Path

File size, privacy, scanning, processing and serving decide the architecture. There is no default that is right for all five.

Q · Given this specific file feature, should the bytes go through my backend, straight to storage, or somewhere else entirely?
What Happens After the Bytes Land

Stored is not ready. Scanning, transcoding and thumbnailing are background work with a state machine, and skipping the state machine is how unscanned files get served.

Q · A file is in the bucket. What still has to happen before anyone should be allowed to use it?
Serving Files

Private files need a check on every read; public files need a CDN. Serving both through your API is the one option that is wrong for both.

Q · How does a stored object get back to a user, with authorization enforced and without your service moving every byte?

Configuration & Testing

8 lessons

What belongs in code versus runtime configuration, why secrets are a separate problem, and a test strategy chosen by what each layer can actually prove.

Configuration: Separating Code From Environment

The same artifact must run in dev, staging and production — so everything that differs between them is input, not source.

Q · What belongs in the code, what belongs in runtime configuration, and how does a value actually reach the process?
Secrets Are Not Configuration

Credentials need a different storage, a different access path and a lifecycle — and rotation is the part every team skips.

Q · Where do database passwords, API keys and signing keys actually live, and how do they change?
Validate at Startup, Fail Loudly

Check everything the process needs at boot and refuse to start — rather than discovering the missing value at 3am on the first request that needs it.

Q · What should a process verify before it declares itself ready, and what should it do when a check fails?
Feature Flags: Rollout, Kill Switches and Debt

Separating deploy from release, buying an instant off-switch — and accumulating a combinatorial mess if nobody removes them.

Q · When is a runtime toggle the right tool, and what does having one cost after the launch is over?
A Test Strategy Chosen by What Each Layer Can Prove

Business logic to unit tests, database behaviour to integration tests, contracts to contract tests, and only the critical flows to end-to-end.

Q · Which kind of test should cover which part of a backend, and what does each kind actually prove?
Test Against the Real Database

A substitute engine with different SQL semantics gives you a green suite and a broken production — the failure the substitute exists to prevent.

Q · When does it matter that a test runs against the same database engine as production?
Contract Tests Between Services

Verify that a producer and its consumers still agree on the wire format, without running both systems at once.

Q · How do I know a change to my API will not break a service I do not control and cannot run?
Performance Testing a Backend

Latency, throughput, concurrency, CPU, memory, database load and dependency load are seven different dimensions — a single "requests per second" number answers almost none of them.

Q · How do I find out how this service behaves under load before production finds out for me?

Deployment

10 lessons

Shipping a running service without dropping requests: containers, graceful shutdown, health checks, rolling deploys and migrations that survive two versions at once.

Deployment Models

VM, container, managed container, function, PaaS and Kubernetes compared by the engineering problem each one is solving, not by the marketing category.

Q · What am I actually choosing between when I choose where my backend runs?
Containerizing a Backend

An image is a frozen filesystem plus an entrypoint; the interesting part is what your process must do once it is PID 1 with no shell around it.

Q · What does putting my backend in a container actually change about how it runs?
Graceful Shutdown
▶ lab

SIGTERM arrives, and the process has one job: stop taking new work, finish or cancel what it holds, release everything, and exit before it is killed.

Q · What must a backend process do between receiving SIGTERM and exiting, so that no request and no job is lost?
Rolling Deployments

Replacing instances a few at a time keeps the service up, and guarantees that two versions of your code run against one database at the same time.

Q · What must be true about my code for it to be safe to replace instances gradually?
Expand and Contract Migrations

Five steps that let a schema change survive a rolling deploy, because for the length of that deploy two versions of your code share one database.

Q · How do I change a database schema when old and new code will both be running against it?
Canary Deployments

Send a small slice of real traffic to the new version, compare it against the old on the same signals, and only then commit the fleet.

Q · How do I get evidence that a new version is good under real traffic before it serves all of it?
Blue-Green Deployments

Run two complete environments, cut traffic from one to the other, and cut back if it is wrong — while remembering that the database was never duplicated.

Q · When is it worth paying for two full environments to make rollback instant?
Mapping Services Across Cloud Providers
▶ lab

A translation table for the eight things a backend needs from a cloud — with the column that matters most being what the analogy gets wrong.

Q · My service needs compute, storage, a database, a cache and a queue. What is the equivalent of each on the provider we actually use?
Running a Backend on Kubernetes

What the application must do to be a well-behaved workload: honest probes, a termination sequence that races endpoint removal, resource requests that match reality, and no local disk.

Q · What does my application code have to get right for Kubernetes to run it well?
Serverless Backends

A per-invocation execution model that removes supervision and adds cold starts, execution limits and connection pressure — excellent for some workloads and wrong for others.

Q · What changes about writing a backend when the platform creates and destroys the process around each request?

Scaling Patterns

7 lessons

Statelessness, load balancing, autoscaling signals, pagination, batching and streaming — the specific techniques, and the problem each one is a response to.

Making an Existing Service Stateless

The inventory, the migration order and the verification — turning a service that works on one instance into one where any instance can serve any request.

Q · I have a service that assumes it is the only instance. What is the actual sequence of changes that makes it safe to run several?
Horizontal vs Vertical Scaling

A bigger machine is simpler and has a ceiling; more machines have no ceiling and require statelessness, a load balancer and coordination you did not have before.

Q · The service is at capacity. Do I make the machine bigger or add more of them?
Load Balancing, From the Backend's Side

What your application owes the thing distributing traffic to it — an honest health signal, aligned timeouts, and no assumption about which instance gets what.

Q · What does my backend have to do to be distributed across correctly, and what can the load balancer not fix?
Sticky Sessions

Pinning a client to one instance buys cache locality and hides instance-local state — and it costs you failover, rebalancing and clean scale-down.

Q · When is it right to send a user's requests to the same instance every time, and what does that cost?
Autoscaling a Backend

Choosing a signal that actually reflects load — and understanding why CPU is the wrong one for a service that spends its time waiting.

Q · What should the number of instances be a function of, and how fast can that number honestly change?
Read Replicas From the Application

Routing reads to a replica multiplies read capacity and introduces a window where the application can read data that is older than what it just wrote.

Q · Which reads can safely go to a replica, and what breaks when they go to the wrong one?
Pagination That Survives a Large Table

Offset pagination is easy and gets quadratically more expensive with depth; keyset pagination is cheap at any depth and gives up random access to page N.

Q · How do I let a client walk a large result set without the last page costing more than the first?

Backend Security

7 lessons

The checklist every service owes: injection, SSRF, dependency risk, secrets discipline and defence in depth, from the implementer's side rather than the attacker's.

The Backend Security Checklist

The controls every service owes no matter what it does, and the layer each one has to live in.

Q · What does every backend service owe, independent of what it is for?
SQL Injection

Parameterized queries solve injection completely — and do nothing whatsoever for authorization.

Q · How does user input reach a query safely, and what does making it safe still not fix?
Command Injection

The shell is a parser you did not intend to invoke. Pass an argument array, or do not spawn a process at all.

Q · When a backend shells out, what turns a filename into code execution — and what removes the possibility?
SSRF — When the Backend Fetches a URL

A fetch your server makes on a caller's behalf runs from inside your network with your identity. Blocklists lose; egress control holds.

Q · What happens when a user supplies a URL and the backend requests it?
Dependency Security

Most of your running code was written by strangers. The controls are reproducible installs, a known time-to-patch, and a build that does not hand out credentials.

Q · What do you owe for the code you did not write but do ship?
Secrets in Logs

Logging a request object, an auth header or a webhook payload copies a credential into every system your logs reach.

Q · How do credentials end up in log storage, and why is deleting them not the fix?
Defence in Depth

Design as if each control has already failed, and prefer controls that work when someone forgets.

Q · If one control fails, what is left — and is the next layer actually independent of the first?

Backend Architecture

7 lessons

Monolith, modular monolith, microservices and event-driven, compared honestly — with the distributed-systems costs that arrive the moment a function call becomes a network call.

The Monolith

One deployable, in-process calls, real transactions across the whole domain — and costs that arrive at team boundaries, not at request volume.

Q · What does a single deployable actually give you, and what specifically takes it away?
The Modular Monolith

One deployable with boundaries the build enforces: most of what services give you, without the network.

Q · Can you get real internal boundaries without paying for distribution?
Microservices

Independent deployment and independent failure, bought with every cost that arrives when a function call becomes a network call.

Q · What do you actually get for splitting into services, and what arrives with it whether you wanted it or not?
Synchronous vs Asynchronous Communication

HTTP couples availability and returns an answer; messaging decouples availability and returns a promise. Neither is inherently more scalable.

Q · Should this component call that one and wait, or publish a message and move on?
Failure Propagation

A slow database becomes timeouts, becomes exhausted workers, becomes an outage in endpoints that never touched the database.

Q · How does one degraded dependency take down parts of the system that do not use it?
Cascading Failure

The feedback loops that turn a recoverable degradation into a system that cannot come back up.

Q · Why does a system that was only slightly overloaded fail completely — and then fail again the moment you restart it?
Comparing Backend Architectures

Monolith, modular monolith, microservices, serverless and event-driven — when each is useful, what each costs, and how each fails.

Q · Given a real system, how do you choose between these five, and what makes the choice wrong later?

Production Debugging

8 lessons

The API was 100 ms and is now 3 s. Working from symptom to cause through deploys, queries, pools, dependencies, the event loop and the queue.

Debugging a Backend in Production

Turning "the API got slow" into a named cause by narrowing the search space with evidence instead of guessing at fixes.

Q · An endpoint that answered in about 100 ms is now taking about 3 s at p99. How do you find the cause rather than guess at fixes?
Why Is My API Slow?

The decision flow from "slow" to a named bottleneck: split the time first, then follow the branch the evidence selects.

Q · Given only "the API is slow", what sequence of checks leads to the actual bottleneck instead of a plausible story?
The Common Backend Failures

Thirteen failures that account for most backend incidents, each with the symptom that identifies it and the first diagnostic to run.

Q · When production breaks, what is it usually, and what is the first thing to check for each?
Backend Code Smells

Ten patterns that predict production trouble — and, for each, the situation where the same pattern is the right answer.

Q · Which patterns in backend code reliably predict incidents, and when is each of them actually fine?
Deploys Are the First Suspect

The highest prior probability for a sudden change in behaviour belongs to the thing that just changed — usually yours.

Q · Why should a deploy be the first hypothesis in almost every sudden production incident, and how do you make it cheap to check?
Memory Leaks in Backend Services

Distinguishing a leak from ordinary heap growth, finding the reference that retains, and doing it on a live process.

Q · Memory climbs steadily until the process restarts. Is that a leak, and how do you find what is holding the references?
Retry Storms

How a reasonable retry policy turns a dependency's brief degradation into a sustained outage, and what bounds it.

Q · A dependency got slow and now it is completely down, with our request rate against it several times normal. What did we do?
Connection Pool Exhaustion

The endpoint is slow, the database is calm, and the pool has waiters — the most commonly misdiagnosed backend incident.

Q · Why is the API slow when every database query is fast and the database itself is barely working?

Agent-Enabled Backends

5 lessons

A model choosing a tool is a client choosing an endpoint. Authorization, budgets, timeouts and audit still belong to the backend, not to the prompt.