Part 01 · The Backend Mindset

What Is a Backend System?

Backend

The jobs a backend quietly does behind every screen: storing, deciding, computing and protecting.

⏱ 1 hours · Station 3 of 153

You tapped "Send". What actually happened?

You type a message to a friend and tap Send. A second later, it shows up on their phone, in another city, even though their phone was asleep in a pocket when you sent it.

Your phone didn't find their phone. It doesn't know where it is. It didn't wait for it to wake up. Something else did all of that: it checked that you were really you, decided you were allowed to message this person, stored the message so it wouldn't be lost, and delivered it when their phone came back online.

That "something else" is the backend. You never see it, and it touches almost everything you do in an app. This lesson is about what it actually does.

The problem: the screen can't do it alone

Last lesson drew the line between the client and the server. So why not let the client do everything? Try it, and four walls appear.

What the app needsWhy the client alone can't do it
Remember things after the app closes, on every deviceA phone can be lost, wiped or swapped. Your laptop can't see what's on your phone
Enforce rules like "free plan: 3 notes" or "one vote per person"Anything the client checks, the user can change (lesson 2)
Do heavy or shared work: search a million products, run a payment, send an emailA phone has little battery, little memory, and no access to other people's data or the payment network
Know who's who, and keep each person's data privateA client can claim to be anyone

A backend system is the part of the software that lives on machines you control and does exactly those four jobs for every client, all the time.

Think of a bank branch

At a bank, you stand at the counter: that's the client. Behind the counter is everything that makes a bank a bank.

  • The teller checks your ID before anything else. (protect)
  • They check the rules: is there enough money, are you over the daily limit? (decide)
  • They work out the new balance and the fee. (compute)
  • They write it into the ledger, which will still be there tomorrow, at every branch. (store)

You never see the vault or the ledger, and you don't need to. You see a counter and a receipt.

every request passes the same four jobsprotectwho is it?decideallowed?computework it outstoreremember itno token401 who are you?note #4403 plan limitbuy milk201 saved (2 words)
Three requests take the same road. One has no token and stops at protect. One breaks the plan's rule and stops at decide. One passes every check, gets worked out, and is stored.

Where the analogy stops working. A teller serves one person at a time and goes home at 5 pm. A backend serves thousands of clients in the same second, never closes, and is usually many identical copies running side by side. It also has no eyes: "checking your ID" means checking a token that arrived with the request.

The building blocks

Every backend, from a hobby project to a bank, does four jobs. Most requests touch all four, in this order.

  1. Protect: who is asking? Every request carries some proof of identity (a session cookie, a token). The backend checks it before doing anything else, and refuses strangers. (Module 9.)
  2. Decide: is this allowed? The business rules: plan limits, permissions, stock, opening hours. This is the logic that makes your product your product. (Lesson 8.)
  3. Compute: work something out. Totals, word counts, search results, recommendations, a resized photo. Sometimes tiny, sometimes the expensive part.
  4. Store: remember it. Save the result somewhere that survives restarts and is shared by everyone: a database, a file store, a cache. (Module 6.)

On top of those four, real backends also talk to other systems: payment providers, email and SMS services, other backends. To the backend, those are just more servers it is a client of.

The whole backend can be described as one function:

response = handle(request, everything the backend remembers)

The client sends the request. The backend brings the memory.

Predict first

A free-plan user already has 3 notes. Their app is old and still shows the 'Add note' button. They tap it. What should happen?

Behind the scenes: one note, four jobs

Alice adds a note that says "buy milk". Here is everything the backend does with that one request.

Step through it

One request through the backend

Alice's appProtectDecideComputeStore

Step 1/6 The app sends the request

The request carries three things: Alice's token, the action (add), and the text. Nothing else: no user id, no count of her notes.

token
t-alice
action
add
text
buy milk

The picture to keep in your head

Picture the backend as a short corridor with four doors. Every request walks it from left to right:

protect → decide → compute → store → response

  • A request can be turned back at any door, and the earlier the better: refusing a stranger at the first door costs nothing, while refusing them after an expensive computation wastes work.
  • The cheap checks (who, allowed) come before the expensive work (compute, store).
  • Only the backend holds the keys to the last room. Clients never write to the store directly.

When you read any backend code, try to find the four doors. They're often spread across middleware, handlers, services and repositories (Module 5), but they're always there.

Try it: which job is this?

Each card is something a real backend does. Which of the four jobs is it?

Try each case

Protect, decide, compute or store?

401 token expired
works: Protect. The backend can't trust a request until it knows who sent it, so this check comes first.

Code from first principles

A whole backend in one function, with no network and no database yet. handle takes a request (a token, an action, some text), does the four jobs, and returns a response. Its memory is two maps: which token belongs to whom, and everyone's notes.

The program then sends it eight requests, the way eight different clients might, and prints which job had the final say on each.

package main

import (
	"fmt"
	"strings"
)

const freeLimit = 3 // the free plan keeps at most 3 notes

// The backend's memory: who each token belongs to, and everyone's notes.
var (
	tokens = map[string]string{"t-alice": "alice", "t-bob": "bob"}
	notes  = map[string][]string{}
)

// handle is the whole backend: one request in, one response out.
// It returns the status, the reply, and which of the four jobs had the final say.
func handle(token, action, text string) (int, string, string) {
	user, ok := tokens[token] // protect: who is asking?
	if !ok {
		return 401, "who are you?", "protect"
	}
	switch action {
	case "add":
		if len(notes[user]) >= freeLimit { // decide: is this allowed?
			return 403, fmt.Sprintf("free plan keeps %d notes", freeLimit), "decide"
		}
		words := len(strings.Fields(text))      // compute: work something out
		notes[user] = append(notes[user], text) // store: remember it for next time
		return 201, fmt.Sprintf("saved note %d (%d words)", len(notes[user]), words), "store"
	case "list":
		total := 0
		for _, n := range notes[user] { // compute over what was stored
			total += len(strings.Fields(n))
		}
		return 200, fmt.Sprintf("%d notes, %d words", len(notes[user]), total), "compute"
	}
	return 400, "unknown action", "decide"
}

func main() {
	requests := [][3]string{
		{"", "add", "buy milk"},
		{"t-alice", "add", "buy milk"},
		{"t-alice", "add", "call mom tonight"},
		{"t-alice", "add", "fix the bike"},
		{"t-alice", "add", "learn go"},
		{"t-bob", "list", ""},
		{"t-alice", "list", ""},
		{"t-eve", "list", ""},
	}
	fmt.Printf("%-8s %-5s %-17s %-6s %-26s %s\n", "token", "do", "text", "status", "reply", "job")
	for _, r := range requests {
		status, reply, job := handle(r[0], r[1], r[2])
		token := r[0]
		if token == "" {
			token = "(none)"
		}
		fmt.Printf("%-8s %-5s %-17s %-6d %-26s %s\n", token, r[1], r[2], status, reply, job)
	}
}

Output (the same in all five languages):

token    do    text              status reply                      job
(none)   add   buy milk          401    who are you?               protect
t-alice  add   buy milk          201    saved note 1 (2 words)     store
t-alice  add   call mom tonight  201    saved note 2 (3 words)     store
t-alice  add   fix the bike      201    saved note 3 (3 words)     store
t-alice  add   learn go          403    free plan keeps 3 notes    decide
t-bob    list                    200    0 notes, 0 words           compute
t-alice  list                    200    3 notes, 8 words           compute
t-eve    list                    401    who are you?               protect

Reading the output:

  • (none) and t-eve: stopped at protect. No known token, so nothing else ran. The backend didn't even look at the text.
  • The first three notes from Alice: they pass every door and end in store. Notice the counter, saved note 1, 2, 3: the backend remembers between requests. The client never sends how many notes Alice has.
  • "learn go": stopped at decide. Alice is real, and the request is well formed, but the free plan keeps 3 notes. The rule lives here, not in the app.
  • Bob's list: 0 notes. The same memory holds Alice's notes, but the backend only ever hands Bob his own. Keeping users apart is part of protect.
  • Alice's list: 3 notes, 8 words (2 + 3 + 3). That number was computed from what was stored, by the backend, on demand.

Nothing here touched a network. Lesson 2 put a server around a function like this one; Module 4 shows what happens inside that server when thousands of these calls arrive at once.

Real engineering

  • Order the doors by cost. Authentication first, then cheap validation, then rules that need a database read, and only then expensive work. Rejecting early protects the backend from wasted effort and from abuse.
  • The four jobs become layers. In real code they usually live in different places: auth in middleware, rules in a service layer, storage in a repository. That separation is what Module 5 is about.
  • Store is the hardest part to change. You can rewrite a handler in an afternoon. Changing how millions of saved rows are shaped takes careful migrations. Teams think hardest about the data.
  • "Backend" is often many programs. An API server, background workers, a database, a cache and a queue, all working together. Lesson 10 takes one apart.
  • Backends are clients too. Payments, email, maps and AI models are other companies' backends. Every call to them can be slow or fail, which is a large part of Module 7.

When it breaks

Each failure below is one of the four jobs missing or in the wrong place.

Try each case

Pick a failure

GET /notes?user=alice
returns Alice's notes to anyone
breaks: Someone added a new endpoint and forgot the auth check. Fix it by making protect the default, applied to every route, with explicit exceptions for public ones.

Think before you read on

The example program keeps notes in a map inside the process. It works perfectly in the output above. What are two things that would go wrong if you put exactly this program on the internet for real users?

Reveal
  1. Restarts lose everything. The map lives in memory, so every deploy or crash wipes all notes.
  2. Two copies disagree. Run two copies of the server to handle more traffic, and each has its own map: Alice's note saved by copy A is missing on copy B.

(Also: the tokens are hard-coded and never expire.) Both main problems point to the same fix: store has to move out of the process into a shared database. That's exactly where this module goes next.

Check yourself

1. Name the four jobs of a backend, in the order a request usually meets them.

Answer

Protect (who is asking), decide (is it allowed), compute (work it out), store (remember it).

2. Why should "free plan keeps 3 notes" be checked by the backend even if the app already hides the button?

Answer

Because any client can be old, modified or replaced with curl. Only the backend sees every request, so only the backend can guarantee the rule.

3. Why is it cheaper to check the token before resizing an uploaded photo?

Answer

Checking a token is a quick lookup; resizing a photo costs a lot of CPU and memory. If you resize first, anyone can make your server do expensive work for free.

4. When your backend calls an SMS provider, which side of the client-server line is it on?

Answer

It's the client. For that call, your backend is just another program sending requests to someone else's server, with all the same risks: slow answers, errors, and limits.

Your challenge: add a fifth door

Add a rule to handle: a note may be at most 5 words long. A longer note gets 422 note too long (N words).

Before you write it, decide: does this check belong before or after the plan-limit check? Does it matter which error a user over the limit with a long note sees first?

You've succeeded when sending "t-bob", "add", "one two three four five six" prints status 422 with note too long (6 words), Bob's note count stays at 0, and every other line of the output is unchanged.

The mental model

A backend is the program on your side of the line that every client relies on. For every request it does four jobs, in order of cost: protect (who is it), decide (is it allowed), compute (work it out), store (remember it). The client brings the request; the backend brings the memory and the rules.

Station stamp

Finish the chapter

Done reading? Press Complete to save your progress. XP is Pro-only — on Pro this chapter is worth +10 XP.

Go Pro to earn XP →