Learn DevOps & Production Engineering
How source code becomes a running production system, how it is changed continuously without breaking, and what an operator does when production behaves differently from the assumptions it was built on. Thirty-three modules, from what makes production different to operating agent systems.
Production Fundamentals
7 lessonsWhat makes production different from every environment you can reason about locally — real traffic, real data, real failure, real cost, and continuous change — and what DevOps actually means once it stops being a job title.
The discipline of making software operable under real traffic, real data, real failure and continuous change.
A set of practices for reducing the distance between building software and operating it — not a team, and not a job title.
Everything that makes production hard is absent from the environment where the code was written and reviewed.
Code to build to artifact to release to deploy to observe to incident to learn — and why it is a loop rather than a line.
Who is responsible for a service in production, and why that answer has to be a specific team rather than everyone.
The full path a change travels, as a model you can debug against when something in it goes wrong.
A catalogue of delivery failures, arranged by where in the chain they happen and what they look like from the outside.
Delivery Lifecycle
6 lessonsPlan, code, review, build, test, package, release, deploy, verify, operate, learn — each stage with its inputs, outputs, evidence and rollback story.
Plan through learn as a chain of stages, each with defined inputs, outputs, automation, evidence and a way back.
The decisions taken before and during writing — change shape, size, reversibility and coexistence — determine how safely it can ship.
Human review reliably catches some classes of defect and reliably misses others; treating it as a general safety net is how the missed classes reach production.
Build one artifact, address it by digest, promote it through environments, and make the release a recorded decision separate from the deployment.
A deploy reporting success says the orchestration worked; verification is comparing the new version against a baseline on signals that reflect users.
The stage that closes the loop: turning what production taught you into a merged change, rather than into a document and a resolution to be careful.
Source Control as Production
6 lessonsA commit is not history; it is a candidate for production state. Branching models, protected branches and required checks as delivery infrastructure rather than team preference.
When merging triggers delivery, the repository stops being a record of what happened and becomes the control plane for what production is.
Branching models are delivery constraints, not team preferences — and there is no universal winner, because they optimise for different release realities.
Small changes, integrated into one mainline at least daily, with main kept releasable at all times — which is a set of demanding requirements, not a branch naming convention.
Divergence has a cost that grows superlinearly with time, and the expensive part — semantic conflict — is invisible to every merge tool.
Rules on the branch pointer that delivery reads from — enforced server-side, because anything enforced on the developer's machine is advice.
Automated checks bound to a branch as a merge condition — useful exactly to the extent that they ran on the right code, mean something, and are trusted.
Continuous Integration
9 lessonsCI as a feedback system, not a task runner: what to check, in what order, how to parallelise it, what to cache, and why a slow pipeline changes engineering behaviour.
Merging everyone's work into a shared mainline often enough that divergence stays small, and proving the merged result actually works.
The product of a pipeline is a trustworthy verdict delivered while the author still has the change in their head; everything else is overhead.
Order checks by signal per unit of cost, gate on the cheap ones, and be explicit about which checks run on a branch, on trunk, and nightly.
Wall-clock time is set by the longest dependent chain, not by total work — so parallelism helps exactly as far as the graph and the shared resources allow.
A pipeline should be a DAG of real dependencies; stages, sequential steps and path filters are approximations of it, and each approximation has its own way of being wrong.
A cache key is a claim that two inputs are equivalent; when the claim is wrong the pipeline does not get slower, it gets wrong.
A red pipeline has four common causes with four different correct responses, and telling them apart quickly is a learnable procedure.
The pipeline is a privileged production identity that executes code from anyone who can open a pull request — and those two facts have to be kept apart.
A test that passes and fails on identical input destroys the verdict for every other test in the run, because it teaches people to re-run until green.
Build Systems
7 lessonsTurning source into an artifact you can trust: reproducibility, pinned inputs, environment isolation, and being able to prove where a binary came from.
A dependency graph of tasks with declared inputs and outputs, plus a rule for deciding what still needs doing — not a script that runs commands in order.
The same source plus the same declared inputs yields the same artefact — which requires pinned dependencies, deterministic actions and an isolated environment, in that order.
Six facts recorded at build time — commit, builder, inputs, toolchain, timestamp and artefact digest — that let you answer "where did this artefact come from" without guessing.
Most of what you ship was written by strangers, resolved by an algorithm you did not choose, and updated on a schedule you have to decide.
Pinning buys reproducibility and tamper-evidence, and hands you the update duty the range was performing on your behalf.
The machine a build runs on is an input to the build, and everything about it that is not declared is a source of drift, of irreproducibility and of shared-state compromise.
Builds are slow for three different reasons — repeated work, serialised work, and genuinely expensive work — and each has a fix that does nothing for the other two.
Artifacts & Registries
7 lessonsBuild once, promote many. Immutable outputs, digests versus tags, registries, retention, and why rebuilding per environment quietly destroys your evidence.
The immutable, stored, addressable output of a build — the unit that gets tested, promoted, deployed and rolled back.
One artifact is built, then promoted unchanged through every environment, and environment differences arrive as configuration rather than as a rebuild.
The store artifacts live in between build and deploy — and a piece of production infrastructure on the critical path of every scale-up.
A tag is a mutable human reference; a digest is content identity. Deploying by digest is what makes a rollout reproducible.
A version number is a compatibility promise to consumers who upgrade on their own schedule — and for a continuously deployed internal service there are none, so a build number is the honest answer.
Which artifacts you can delete, why "keep the last N" deletes the one you needed, and why retention policy is part of the rollback plan.
Moving one artifact forward through environments by changing what is claimed about it, never by changing its bytes.
Containers in Production
8 lessonsThe lifecycle from source to running process, layers and caching, what image size actually costs, and the process and signal model that decides whether deploys drop requests.
The full path from a build context to a process serving traffic, and back to a stopped container — with the failure that belongs to each hop.
Why one changed line rebuilds everything below it, why a deleted file is still in the image, and how instruction order decides both.
Size is paid on cold pulls and nowhere else — and an image with no shell is a real operational cost that nobody puts on the other side of the ledger.
Compile in one image, ship another — so the toolchain, the source and the build credentials never reach production.
An image is an immutable package; a container is a running instance of it with a throwaway writable layer — which is why nothing you change inside one survives.
The entrypoint becomes PID 1, PID 1 does not get default signal handling, and a shell wrapper in between is why your container ignores SIGTERM.
Signal, stop accepting work, drain what is in flight, release resources, exit — inside a hard timeout you do not control.
What survives a container's death, what does not, and the order to ask questions in when there is no shell and the evidence is being deleted on every restart.
Environments
7 lessonsStaging is not production. Drift, parity, preview and ephemeral environments, and the limits of pre-production evidence — including why more environments is not more safety.
Each environment is an instrument that measures some production properties and is blind to others — which makes an extra one a cost to justify, not a safety improvement to assume.
Environments diverge from each other continuously and silently, and a drifted environment does not stop answering questions — it starts answering them wrongly.
Parity means preserving the operational characteristics that matter for the change at hand — explicitly not identical scale, which is unaffordable and still insufficient.
A running instance per change, created from the pull request and destroyed with it — excellent evidence about wiring and product behaviour, no evidence at all about scale.
Environments created on demand and destroyed when done, which is only possible once infrastructure, configuration, data and secrets are all codified — and which turns environment count into a decision instead of an inheritance.
Copying real user data into a test environment moves it from your most controlled system to your least controlled one — use synthetic data, anonymised data or a controlled subset instead.
Promotion moves one immutable artifact forward and changes only its configuration — which is what makes the evidence from earlier environments mean anything at all.
Configuration
5 lessonsArtifact plus configuration equals a running service. What belongs in each, validating at startup rather than discovering at 3am, and treating config as a deployable with its own blast radius.
A running service is an immutable artifact combined with environment-specific configuration — and the configuration half is the one nobody versions, tests or reviews.
Check every configuration value when the process starts and refuse to serve if anything is wrong — rather than discovering an invalid value at 3am, on the first request that happens to need it.
Configuration changes reach production faster than code, apply to everything at once, are reviewed less, and frequently have no rollback story — which is why so many outages are config-only.
Configuration diverges between environments and between instances, and the divergence is invisible until a code path that only exists in one place runs for the first time.
When a value is fixed decides how you change it — build-time values need a new artifact and a full pipeline, runtime values change without one, and picking the wrong side quietly destroys build-once-promote-many.
Secrets
6 lessonsCredentials out of source and out of images: workload identity, secret managers, and rotation that applications actually survive.
Credentials, API keys, private keys, certificates and tokens must not live in source control or in images — because both are copied, cached and retained far beyond the systems you control.
A secret manager is a store with access control, versioning, audit and encryption at rest — and the product details differ enough between providers that a working design is not portable without re-verification.
The primitive that removes the first secret: the platform attests what a workload is, that attestation is exchanged for a short-lived credential, and no static key exists anywhere for an attacker to find.
Old, then new alongside old, then a transition window, then old revoked — and the application must tolerate the change, because one that reads a secret at boot and caches it forever breaks the moment you rotate.
CI holds credentials for everything and executes code that anyone can propose — which makes it the highest-value target in the delivery path and the one most often protected by conventions rather than controls.
The characteristic secret failure is a crash loop with an error that does not mention secrets at all — which is why secret resolution belongs in startup validation, where it can fail loudly and name what is missing.
Infrastructure as Code
8 lessonsDescribing infrastructure so it can be reviewed, reproduced and changed safely — plans, state, drift, and the destructive changes a rename can hide.
Describing infrastructure in reviewed, versioned files so it can be reproduced and changed with the same evidence as application code.
Describing the end state and letting a tool derive the steps, versus writing the steps yourself — and the cases where writing the steps is still correct.
A plan is a diff between what the code says and what exists, classified into create, update, replace and delete — and every destructive line in it needs a human.
The mapping between configuration addresses and real resources — why it must exist, why it goes stale, why it holds secrets, and what concurrent applies do to it.
Reality diverging from what the code says — how it happens, which of it is legitimate, and why the next apply is the dangerous moment.
Replacing servers instead of modifying them, so that what is running is a known function of an artifact rather than the sum of its history.
A useful metaphor about replaceability that becomes dangerous when treated as a rule — because some infrastructure genuinely is irreplaceable, and a database treated as cattle is a data loss event.
Renaming a resource in configuration is read as delete-then-create, because the tool identifies resources by their address — and on a database that is the end of the data.
Deployment Strategies
8 lessonsRecreate, rolling, blue/green, canary, shadow and flags — each with how it works, what it risks, what it costs, and how you get back.
Six ways to replace running code, compared on how they work, what they risk, what they cost, how you get back, and what each is actually for.
The simplest strategy, an outage by design — and the only honest answer when two versions of your system genuinely cannot coexist.
Replacing instances in batches keeps the service up — at the price of a window where old and new code run simultaneously against exactly the same state.
Two complete environments and a router between them: reversal in seconds, exposure of one hundred percent, and a database that is still shared.
Exposing a small share of real traffic to the new version and widening only while health holds — the strategy that bounds width rather than duration.
Duplicating production traffic to a candidate that serves nobody — strong evidence about crashes, load and resource use, and no evidence at all about writes.
Shipping code that is switched off, then turning it on for whom you choose — and the four ways a flag system quietly becomes the least reviewed part of production.
Combining a rollout strategy, an automated comparison and a release control into one idea — exposure that increases only while evidence supports it.
Rollout Safety
8 lessonsBlast radius as the organising idea: version coexistence, canary analysis against a baseline, rollback that is actually safe, and when rolling forward is the only option.
Any deploy without downtime runs two versions of your code against one set of state — and rollback runs them in the other order, which is the direction nobody tests.
Deciding whether a candidate is healthy by comparing it against a concurrent baseline on errors, latency, saturation and business outcome — and never on CPU alone.
Going back to the previous version is the fastest way to end user impact — until the change made the previous version invalid, at which point what you are doing is not a rollback.
Irreversible migrations, side effects already emitted and dependencies that moved on — the situations where the fix has to go forward, and how to ship one safely under pressure.
The organising question of the whole domain — one test, one user, one tenant, one percent, one zone, one region, everyone — and why the honest answer is usually larger than the intended one.
The techniques that move a change down the ladder — exposure control, partitioning, staging, privilege limits and reversibility — and the ones that appear to contain and do not.
Small changes make cause and effect legible, review effective and rollback cheap — but diff size and blast radius are different axes, and confusing them is how one-line outages happen.
The pipeline reports success when bytes moved and a process answered a health check — which is several layers short of the system doing what it exists to do.
Database Migrations
6 lessonsThe change most likely to cause an outage and least likely to be rehearsed: expand/migrate/contract, backfills, locks, and why a migration and a deploy are one coupled event.
Five distinct risks hide under the word "migration", and every one of them scales with data you do not have in staging.
The pattern that makes schema change safe: add the new shape, move to it, and only remove the old shape in a later deploy.
The techniques that let a schema change land while the service keeps serving — and the engine-specific rules that decide which ones are available to you.
Schema and code version separately but must be compatible continuously, which makes every schema change a two-artifact rollout with a compatibility window.
Moving or computing data across every existing row is a long-running production write workload, and it needs the properties of a job rather than of a migration.
Dropping, renaming, truncating and narrowing are the only changes with no rollback — and during a rolling deploy they break the instances that have not been replaced yet.
Kubernetes
8 lessonsWhat orchestration problems exist, which abstractions answer them, and how to decide whether you need any of it — taught as one implementation, not as what production means.
Kubernetes is a distributed workload orchestration platform. The first question is not how to use it but whether the orchestration problem it solves is one you actually have.
Five operational problems appear the moment you have many containers on many machines. Every Kubernetes object is an answer to one of them, and is only worth learning as such.
One model to debug against: a cluster is a control plane holding desired state and nodes running the workloads, with controllers continuously closing the gap between them.
A pod is one or more containers that share a network namespace, a lifecycle and a set of volumes — and it is the smallest thing the scheduler can place.
A Deployment is desired state — this many replicas of this image, with this rollout policy — that a controller works toward continuously, including after failures nobody scripted.
A ReplicaSet keeps N pods matching a template alive. It exists so that a Deployment can roll out by scaling two of them in opposite directions — and that is the only reason you should ever look at one.
Pod IPs change every time a pod is replaced. A Service is a name and address that keeps meaning "the currently ready pods for this workload", updated continuously as that set changes.
Internal Services are unreachable from outside. Something at the edge must terminate TLS, match hostnames and paths, and route to the right Service — and which object expresses that is currently in transition.
Kubernetes Runtime
9 lessonsReconciliation as the core mental model, plus the runtime behaviours that produce most real incidents: scheduling, requests and limits, OOM kills, throttling and probes.
You write desired state; a controller observes actual state; the difference is the instruction. That loop never stops running, which is the whole idea.
Accepted, scheduled, pulled, started, ready and receiving traffic are six different moments, separated in time — so desired state is never instant reality.
Placement is a filter-then-score decision made against declared requests. `Pending` is not a failure state — it is the scheduler telling you no node satisfied the constraints.
A request is a scheduling reservation; a limit is an enforced ceiling. CPU and memory behave completely differently when you reach the ceiling, and that difference is the lesson.
Four failure shapes come from two numbers being wrong in two directions each — and each shape has a distinct symptom that tells you which one you are looking at.
Memory cannot be taken back, so the only enforcement available is termination. Over the limit, the kernel kills the process — it does not slow it down or warn it.
Over a CPU limit the container is descheduled until the next period rather than killed. Nothing errors, nothing restarts, and the tail latency gets worse for reasons nothing in the application explains.
Readiness gates traffic, liveness restarts the container, startup covers a slow boot. Confusing the first two turns a dependency outage into a cluster-wide restart storm.
One decision tree covers most Kubernetes failures: is it running, is it ready, is it routed — and each "no" points at a different, small set of causes.
Kubernetes State
5 lessonsConfig, volumes and stateful workloads — why a database is not a stateless API with a disk attached, and where the abstraction stops helping.
Two objects that inject configuration into pods, one of which is named after a security property it does not, on its own, provide.
A container filesystem dies with the container. A volume is a way of saying which data outlives what — the pod, the node, or the cluster — and each answer has different failure modes.
A stateless replica is interchangeable and can be replaced at any moment. A database replica has an identity, a copy of the data, a position in a replication stream and an opinion about who is the leader.
The workload controller that gives each replica a stable name, its own volume and a defined position in startup and rollout — which makes running stateful systems possible, not advisable by default.
The recurring mistakes that produce most cluster incidents — each one reasonable at the moment it is made, and each one with a specific failure it eventually causes.
Production Networking
8 lessonsThe operational half of the network: service discovery, DNS behaviour under change, certificate lifecycles, load balancer health and draining connections without dropping work.
Instances appear and disappear continuously, so callers cannot hold addresses. Discovery is a registry plus a health signal plus a propagation delay — and the delay is where the incidents are.
A DNS change is not an action, it is an expiry schedule. TTL decides how long the old answer keeps being used, and several caches between you and the user do not necessarily obey it.
Issue, deploy, renew, rotate, revoke. A certificate is the only production component with a hard expiry date, which is why expiry remains one of the most common outages in the industry.
Certificate renewal is the textbook case for automation — predictable, recurring, error-prone by hand. It is also the textbook case for monitoring the automation, because silent renewal failure is how certificates expire anyway.
The algorithm matters less than the health check, the connection lifetime and the capacity that remains when a backend leaves. Most balancing incidents are about membership, not distribution.
Stop new connections, let active work finish, then exit. The whole difficulty is ordering — the instance must leave the routing layer before it stops serving, and those two events are not naturally sequenced.
The ingress is where everyone's traffic meets one shared configuration. It is the component with the widest blast radius per line of config, and the one most often changed by people who own only one route.
A catalogue: DNS, certificates, blocked ports, security group mistakes, connection exhaustion, NAT port exhaustion, packet loss and latency spikes — each with a symptom that identifies it.
Release Engineering
8 lessonsDeployment is not release. Versioning, promotion, release manifests, change management and the audit trail that lets you answer "what changed" during an incident.
Deployment means code reaches an environment. Release means functionality becomes available to users. Conflating them makes both riskier than either needs to be.
The practice of keeping software in a state where any commit on the main line could be released — whether or not you choose to release it.
Every change that passes verification reaches production automatically, with no human release step — which is a different and stronger claim than continuous delivery.
The path from commit to production as a designed system: ordered stages, each with an input, a verdict, evidence, and a defined behaviour on failure.
Someone has to own how software becomes a release: versioning, what a release contains, how it is assembled, who decides, and what record it leaves.
One record naming the version, commit, artifact digest, config version, migration version and flag state — so "what is production right now" is a lookup rather than an investigation.
Deciding which changes need what scrutiny, so that ordinary changes stay cheap and genuinely risky ones get attention — without a process people route around.
Who changed what, when, why — and what the previous state was. The last field is the one that turns a log into something you can act on.
Production Access
5 lessonsWho can touch production, with what privilege, for how long — and what to do about the emergency where someone genuinely must.
Who can reach production, what they can do there, and why the answer is a set of specific approved capabilities rather than a single administrator role.
The operational form of a security principle: permissions sized to the task, scoped to the resources, and bounded in time — with an honest account of what that costs during an incident.
Emergency elevated access that is explicit, audited, short-lived and automatically revoked — the answer to "but what if we need admin during an incident".
Sometimes an emergency requires acting by hand. The damage is not the manual change — it is the permanent, undocumented divergence between production and the code that is supposed to describe it.
The periodic check that the people and services with production access are the ones who should have it — a backstop for expiry, not a substitute for it.
Alerting & Operational Signals
6 lessonsUsing observability rather than building it: alerts that demand action, symptom-based paging, dashboards an operator can act on, and the cost of noise.
The operator's path from a page to a hypothesis: alert, dashboard, trace, logs — and what each hop is actually for.
The rule that decides what is allowed to page a human: if there is no action a person would take right now, it is not an alert.
"Users cannot check out" beats "CPU is 81%" — with the honest exception of infrastructure conditions that have a specific, immediate response.
Noise trains responders to ignore the pager, and the cost is paid on the one night the alert was real.
Built around the questions an incident asks, in the order it asks them — not around everything the system can emit.
The highest-signal overlay there is: a vertical line at each release, drawn across the error rate graph.
Incident Response
8 lessonsDetect, triage, mitigate, communicate, recover. Stopping user impact before understanding cause, and the roles that keep a severe incident coordinated.
Alert, acknowledge, triage, mitigate, recover, verify, learn — a defined sequence, so nobody has to invent one at 3am.
A shared shorthand for how much of the organisation to wake — and a local convention, not a fact about software.
The mandatory distinction: mitigation ends user impact, root cause analysis explains it, and they happen in that order.
Separating coordination from investigation so that neither starves the other — valuable at high severity, overhead at low.
An evidence-based sequence of changes, signals and actions — built from records, because memory reorders events with total confidence.
Different audiences need different things at different cadences — and none of them should have to interrupt the person fixing it.
Someone has to be reachable when production breaks. Done well it is the shortest feedback loop a team has; done badly it is the fastest way to lose people.
Load, frequency and recovery are properties of the system, and a rotation that cannot be sustained is a defect in the system rather than a shortcoming of a person.
Postmortems
5 lessonsBlameless but accountable learning: contributing factors over single root causes, and action items specific enough to change the system rather than the people.
The written reconstruction of an incident — impact, timeline, detection, contributing factors, what went well and what changes — done blamelessly and still accountably.
Why complex systems rarely have one cause, and why "human error" is a question rather than an answer.
One investigative technique for pushing past the first plausible answer — useful, widely over-applied, and structurally unable to represent multiple interacting causes.
"Be more careful" is not an action item. "Add migration validation", "add a canary", "reduce the permission", "automate the verification" are.
The learning that only exists in aggregate — patterns across incidents, near misses, and making the record something people actually read.
Readiness & Ownership
5 lessonsWhat a service owes before it carries traffic — an owner, a runbook that encodes understanding, dashboards, alerts, a rollback plan and a tested recovery path.
The conversation before a service carries real traffic: who owns it, how you will know it is broken, and how you get back.
Making the owner of a service retrievable at 3am by a stranger — the record, what it contains, how it decays, and how transfers actually work.
A document written for someone tired, under pressure, who did not build this: symptom, possible causes, checks, mitigation, escalation, and how to verify recovery.
"Restart the service" is ritual. "Restart only after checking X, because Y indicates Z" is understanding — and the difference decides what happens when reality does not match the entry.
Status per dimension with evidence — READY, PARTIAL, MISSING, UNKNOWN — and deliberately never a number, because a number invites optimising the number.
Capacity & Cost
11 lessonsWhat saturates first, how much headroom failure and deploys require, and cost as a first-class trade-off against reliability and performance.
Knowing how much load a system can carry, which resource runs out first, and what the moment of saturation looks like from outside.
Turning request rate, CPU, memory, connections, queue throughput, network and storage into one defensible statement of safe capacity.
Why critical systems are never run at their limit, and the four separate claims on the reserve you hold.
Deciding in advance what to drop when demand exceeds capacity, so the system fails in the shape you chose.
If two regions each serve half the traffic, either one must be able to serve all of it — and most teams find that out during the failover.
Treating spend as an engineering property with a feedback loop, rather than as a finance report that arrives after the decisions are made.
What infrastructure spend is actually made of, expressed as what each component scales with rather than what it costs.
Infrastructure cost divided by successful requests — the unit that lets you compare architectures instead of comparing bills.
The difference between reserve you decided to hold and capacity you bought because nobody knew the right size.
Resources that are running, billed, and doing nothing — and how to tell them from the reserve that is doing nothing on purpose.
The operating practice around cloud spend — allocation, visibility, budgeting and optimisation — kept at the level engineers actually act on.
Autoscaling
6 lessonsScaling on the signal that reflects the actual constraint, and the lag, cold starts, oscillation and downstream bottlenecks that make autoscaling a capacity tool rather than a capacity answer.
A control loop from a metric to a policy to more or fewer instances — with lag and warm-up as first-class properties rather than details.
Scaling too late, on the wrong signal, into a downstream bottleneck, or against itself — the six failures that produce most autoscaling incidents.
One concrete implementation of the control loop — how Kubernetes does it, and what a VM autoscaling group or a serverless platform does instead.
For workers, queue depth and message age describe the constraint far better than CPU ever will.
Running nothing when there is nothing to do — and paying for it with a cold start on the next request.
The metric you scale on decides whether autoscaling works at all — and CPU is the wrong one for most APIs.
Backup & Disaster Recovery
7 lessonsBackups you have restored, recovery objectives connected to real runbooks, region failover as an operational procedure, and the capacity question failover always raises.
Schedule, retention, encryption, access and verification — the six properties that decide whether a backup is protection or a green checkmark.
The only evidence a backup works: restore it into a real target and verify the application against it. Backup success is not a signal.
A disaster is a class of event, not a size of one. DR is the standing capability to reach a known-good state, chosen per failure class.
Two business objectives that only mean something when they are traced to an architecture, a runbook and a measured drill.
Five questions decide whether a failover works: is the data there, can traffic move, is there capacity, are config and secrets present, are dependencies reachable.
Two regions is not two copies of one system. Deploys, migrations, config, secrets and data all become distributed problems you now operate every day.
Most real data loss is partial and logical. Restoring the whole database over a live system is usually the wrong tool and often makes it worse.
Supply Chain Security
6 lessonsEverything between a dependency and a running artifact is attack surface: pinning, scanning with context, signing, provenance and SBOMs.
Every hop between a line of source and a running process is something that can be substituted, and each hop needs a control and a way to verify it held.
A scanner tells you which known-vulnerable components are present. Whether any of them is exploitable in your system is a separate question, and conflating the two destroys the practice.
A trusted builder signs the artifact it produced, and the deployment refuses anything whose signature it cannot verify — the verification is the control, not the signature.
A machine-readable inventory of what is actually inside an artifact, generated at build time — the thing that turns "are we affected" from an investigation into a query.
CI is the most privileged system in the delivery path and the least reviewed — it can read every secret, write to the registry, and deploy to production.
Every downstream control attests to whatever the builder produced — so if the build environment can be influenced, signatures, SBOMs and provenance all faithfully describe a compromised artifact.
Platform Engineering
8 lessonsInternal products that make safe delivery the easy path: golden paths, self-service with guardrails rather than gates, policy as code, and developer experience as an operational metric.
Building reusable internal products that make safe delivery the easy path for the teams that ship on them.
Turning "create a service" into one standardised workflow that produces a repository, a pipeline, a deployment, observability, secrets, infrastructure and documentation.
A recommended, supported route to production that removes toil without removing engineering judgement — and stays a path rather than becoming a cage.
Time to first deploy, feedback time, build time, local setup, deployment friction and incident discoverability — measured, because each one changes what engineers do.
Letting teams provision what they need without a ticket, by constraining what can be asked for rather than by reviewing every request.
A gate is a human approving everything; a guardrail is automation that makes the invalid action impossible. A gate scales as a queue, a guardrail scales as code.
Encoding organisational rules — no public buckets, required tags, resource limits, deployment constraints — as machine-evaluated checks that run on every change.
The production-readiness checklist expressed as a template, so a new service starts with health checks, signals, shutdown, config validation, alerts, a runbook and an owner already in place.
Automation & Toil
5 lessonsReducing manual, repetitive, automatable work — and the trap of automating something you do not understand, which scales mistakes faster than it scales work.
Repeated manual task, then understand, then standardise, then automate, then monitor the automation — in that order, because skipping a step moves the failure rather than removing it.
Do not automate what you do not understand. Bad automation does not make mistakes less likely — it makes them faster, wider and more confident.
Manual, repetitive, automatable operational work that scales with the service and leaves nothing behind — and the "scales with the service" part is what makes it toil rather than just work.
Six failure modes that scheduled work has and request handling does not: duplicate execution, missed execution, overlap, timezones, long-running jobs, and no observability at all.
Five questions that decide whether scheduled work survives real infrastructure: can it run twice, can it overlap, what if the machine dies, can it retry, is it idempotent.
Operating Dependencies
8 lessonsThe day-to-day of running databases, queues, caches and scheduled jobs: connection budgets, dead letters, hot keys, and why production time is always UTC.
The standing duties around the one component you cannot restart your way out of: connections, locks, bloat, replication, and change discipline.
A database accepts a finite number of connections. Every instance, worker, job and console session spends from the same pool — so the pool sizes have to add up.
Depth, oldest message age, consumer throughput, failure rate and dead letters — plus the clock-driven cousin, where duplicate and missed runs live.
A DLQ needs an alert, an inspection path, a replay strategy and an owner. Without those four it is a place failures go to be forgotten.
Hit rate, memory, evictions, hot keys and latency — plus the planning question that decides your real architecture: can the system survive losing the cache?
Machine timelines, logs, storage and schedules in UTC; local time only at the edges where a human reads it. The conversion belongs in one place.
The hour that happens twice, the hour that never happens, the billing cutoff in the wrong zone, and the incident timeline nobody can reconcile.
Machines need reasonably synchronised clocks for logs, certificates, tokens and scheduling — reasonably, because perfect synchronisation is not available.
Production Debugging
6 lessonsWorking from symptom to cause under time pressure, starting from the highest-signal question there is: what changed?
A method for narrowing from symptom to cause under time pressure, using six questions in a fixed order rather than intuition.
The highest-signal habit in the domain: when an incident begins, ask what recently changed before asking what is wrong.
Deployments, config changes, alerts, error rate and latency drawn on one shared axis, so causal order is read rather than argued about.
Four categories of change — deploy, config, infrastructure, dependency — plus traffic, and the discipline of checking all of them rather than only code.
The practices that reliably produce incidents — each with why it is tempting, because a list that only says "do not" teaches nothing.
Seven pipeline habits that quietly convert a feedback system into a bottleneck you cannot trust, and the pressure that produces each.
Operating Agent Systems
5 lessonsPrompts, models and tool definitions are deployable production inputs. Versioning, evaluation before rollout, canaries judged on quality and cost, and a kill switch that does not need a redeploy.
Agent code, prompts, models and tool definitions all go through CI and an evaluation gate before they become an artifact, a deployment and then traffic.
Prompts, model identifiers, tool definitions and policies are versioned production inputs with a blast radius — not settings someone edits live.
Roll a behaviour change to a small share of traffic and judge it on quality, cost, latency and safety — where quality is the one that is not a threshold.
Disable a tool, disable the agent, or fall back to a simpler mode — all without a redeployment, because a redeploy is too slow when an agent is doing something harmful.
Per-request cost is a variable the system chooses at runtime, not a constant you can capacity-plan around — so budget ceilings become an operational control.