underlay
module 056–8h

Backend Engineering

Servers, databases, caches, jobs

A backend is a kitchen: the server is the chef taking orders (requests); the database is the pantry (everything stored); the cache is the fridge (things you use constantly, kept close); background jobs are the prep cook working ahead of the rush so the chef never blocks.

You don't need to build every part from scratch — you need to know which parts are dangerous. Auth, money, and data loss are dangerous. Everything else is plumbing.

FastAPI: types in, docs out

FastAPI generates validation AND interactive docs from your type hints. Declare the shape of a request with a Pydantic model, and the framework rejects bad input with a 422 before your code runs:

pythonmain.py — run with: uvicorn main:app --reload
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str          # type = validation, for free
    price: float

ITEMS: dict[int, Item] = {}   # in-memory; real DB in a moment

@app.post("/items", status_code=201)
def create_item(item: Item):
    id = len(ITEMS) + 1
    ITEMS[id] = item
    return {"id": id, **item.model_dump()}

@app.get("/items/{item_id}")
def get_item(item_id: int):
    if item_id not in ITEMS:
        raise HTTPException(status_code=404, detail="Item not found")
    return ITEMS[item_id]

# Open http://localhost:8000/docs — live Swagger UI, try-it buttons

SQL: the 20% that does 80% of the work

Databases answer questions. The questions you'll ask 90% of the time are: create a table, insert rows, join two tables, and find rows fast. The index is the database's shortcut — without one, `WHERE user_id = 42` reads every row:

sqlthe core four — and how to prove the index works
CREATE TABLE users (
    id         BIGSERIAL PRIMARY KEY,
    email      TEXT NOT NULL UNIQUE,
    name       TEXT NOT NULL,
    plan       TEXT NOT NULL DEFAULT 'free',
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE orders (
    id         BIGSERIAL PRIMARY KEY,
    user_id    BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    amount     NUMERIC(10,2) NOT NULL CHECK (amount > 0),
    status     TEXT NOT NULL DEFAULT 'pending'
);

-- the #1 pattern: JOIN orders with their user
SELECT o.id, o.amount, u.name, u.email
FROM orders o
JOIN users u ON u.id = o.user_id
WHERE u.plan = 'pro';

-- without this index, the JOIN scans every row
CREATE INDEX idx_orders_user_id ON orders (user_id);

-- prove it: Seq Scan = bad, Index Scan = good
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 42;

Migrations and caches: change safely, serve fast

Migrations are version control for your database schema. Alembic diffs your code models against the live database and generates the ALTER TABLE for you — and `alembic check` fails CI when they drift, so an AI-written change can't silently break production:

bashalembic — the migration loop
pip install alembic && alembic init alembic
# set sqlalchemy.url in alembic.ini to your DATABASE_URL

alembic revision --autogenerate -m "add orders table"   # diff models vs DB
alembic upgrade head                                     # apply it
alembic check    # CI gate: fails if models and DB drifted apart
pythoncache-aside with Redis — the pattern behind every fast API
import redis, json

r = redis.Redis(host="localhost", port=6379, decode_responses=True)

def get_pricing(device: str) -> dict:
    cached = r.get(f"price:{device}")          # 1. fridge first
    if cached:
        return json.loads(cached)
    price = query_database(device)             # 2. pantry if miss
    r.setex(f"price:{device}", 300, json.dumps(price))  # 3. restock, TTL 5min
    return price

test yourself

01EXPLAIN ANALYZE shows Seq Scan on your hot query. The fix:

02Why SQLite in dev and Postgres in prod?

03What does alembic check do in CI?

the real check

alembic check passes in CI. EXPLAIN ANALYZE shows an Index Scan on the hot query. A background job survives an app restart.

0 stamps earned·streak: 0 days

Signed out: progress lives in this browser. to carry it everywhere.

vibe-coder payoff

Agents build backends fast — you must know which parts are dangerous (auth, money, data loss) and which are plumbing.