software-engineering
23 free lessons tagged software-engineering across Programming, AI, Computer Science. Each one is a short sequence of focused steps with narration and a five-question quiz at the end — take them in any order, no signup required.
Benchmarks That Hold Up, and Knowing When to Stop
A benchmark is an experiment, and most are badly designed enough to produce confident wrong answers. This lesson covers what a measurement must control to mean anything, the ways microbenchmarks lie including code the compiler deletes, how to catch regressions in continuous integration despite noisy machines, and how to recognise the point where optimising stops paying.
Measure First: The Arithmetic That Decides What to Optimise
Most optimisation effort is spent on code that was never the problem, and the reason is that intuition about where time goes is reliably wrong. This lesson covers why guessing fails, the arithmetic that caps what any optimisation can buy, the difference between latency and throughput, and how to set a target that tells you when to stop.
Making Rollback Possible: The Changes That Cannot Be Undone
Every deployment strategy assumes you can go back, and that assumption is the one most often false when it matters. This lesson covers what actually makes a rollback work, the database migration pattern that keeps schema changes reversible, the one-way doors that no amount of tooling can undo, and how to tell which kind of change you are about to ship.
Feature Flags: Separating Deploy From Release
A feature flag turns shipping code and exposing behaviour into two independent decisions, which is what lets a team deploy continuously while releasing on someone else's schedule. This lesson covers the four kinds of flag and their very different lifespans, the debt they accumulate, and the discipline that keeps a flag system from becoming untestable.
Flakiness, Coverage, and Suites That Survive
A test suite is a product with a maintenance cost, and two forces decide whether it stays useful: flakiness, which destroys the signal, and the metrics teams use to judge it, which mostly measure the wrong thing. This lesson covers where flakiness comes from, the arithmetic that makes it fatal at scale, what coverage research actually found, and what to measure instead.
Property-Based Testing: Assert the Law, Not the Example
An example-based test checks the cases you thought of, which is exactly the set that excludes your bugs. Property-based testing inverts it: state a law the code must obey for all inputs, let the machine hunt for a counterexample, and let it shrink that counterexample to something you can read. This lesson covers the property patterns, generators, shrinking, and where the technique stops fitting.
Test Doubles: Isolation and What It Costs
Replacing a real dependency with a stand-in is what makes a unit test fast, deterministic, and able to reach states you cannot otherwise produce. It is also how a suite ends up green while the system is broken. This lesson covers the five kinds of double, when each is right, and the two failure modes that follow every team who reaches for mocks by reflex.
What Is Worth Testing, and the Shape That Follows
Every test costs time to write, time to run, and time to maintain when the code moves. This lesson works out what that budget should buy: what each level of test can and cannot catch, why the pyramid has the shape it does, why some teams invert it, and the arithmetic that decides both questions before anyone argues about it.
Why ML Systems Rot
A trained model is a small box inside a large system, and the system is what decays. This lesson covers the failure modes that are specific to machine learning: why changing one feature moves every weight, why hidden consumers break silently, and why data dependencies cost more than code dependencies.
Building Something That Holds Up
Given that the tradable-signal path is narrow and hard to evidence, the systems worth building are the ones the first lesson identified: extraction at scale. This lesson covers the engineering that makes them survive audit, the evaluation that does not depend on returns, and the governance obligations that apply once a model touches a regulated process.
The Failure Modes the Design Creates
Reconciliation buys robustness and charges for it in a specific currency: nothing is ever definitely finished, commands succeed without meaning anything worked, and manual fixes are silently undone. This lesson covers the failures that come from the model rather than from bugs, how to debug them, and when the whole thing is the wrong tool.
Reconciliation: Declare the End State, Not the Steps
Kubernetes is often taught as a pile of object types. Underneath it is one idea repeated: store a description of the desired state, and run loops that continuously compare it to reality and act on the difference. This lesson builds that loop, explains why it is level-triggered rather than event-driven, and shows what the design buys and costs.
Images: A Filesystem You Can Address by Hash
The kernel gives isolation for files already on the machine. The image format is what turned a directory tree into something you can build once, name by digest and run anywhere. This lesson covers layers and the union filesystem that stacks them, why the build cache behaves as it does, and the content addressing that makes it all work.
Undo: Reset, Revert, Restore, and Getting Work Back
Git's undo commands are notoriously confusing because they are usually memorised as recipes. Read against the object model they separate cleanly: each acts on a different one of the three places content lives. This lesson maps them, covers recovery from the accidents that feel unrecoverable, and states what genuinely cannot be undone.
Merge and Rebase: Two Answers to Divergence
Every operation so far moved a pointer. Merging is the first that has to decide something: two branches changed the same project and one result must come out. This lesson covers the three-way merge and the merge base it depends on, what a conflict actually is, and why rebase produces different commits rather than moving them.
Refs: A Branch Is a File Containing a Hash
Hashes are unusable by hand, so Git names them. A branch is not a copy of anything, not a directory, and not a container for commits: it is a forty-character file. Once that is clear, checkout, reset, detached HEAD and the reflog stop being separate concepts and become one operation on one kind of file.
The Object Database: Git Is a Content-Addressed Store
Git is usually taught as a set of commands. Underneath it is a key-value store where the key is a hash of the content, and four object types built on that one idea. This lesson derives the hash by hand, shows what a commit actually contains, and explains why the design makes history tamper-evident.
The Design Philosophy: What Go Left Out
Go is unusual for what it refuses to include. Errors are values, not exceptions. Interfaces are satisfied without declaring it. Formatting is not a choice. This lesson works through the omissions, the reasoning behind each, and the real costs, because every one of them trades expressiveness for something else.
Goroutine Leaks: Who Stops This Thing
Starting a goroutine is one keyword; stopping one is a design decision nothing forces you to make. A goroutine blocked forever is never collected and holds everything it references, which is the most common Go-specific bug. This lesson covers how leaks happen, the cancellation mechanism that prevents them, and how to detect the ones already there.
Unsafe, and Where the Guarantee Actually Ends
The borrow checker rejects some correct programs, so Rust provides ways out: runtime-checked cells, reference counting, and unsafe blocks. This lesson covers what each escape hatch turns off, what it does not, and the encapsulation discipline that keeps a small unsafe core from voiding the guarantee for everything above it.
What Has Actually Been Verified, and What It Cost
Two landmark systems carry machine-checked proofs of real code: a C compiler and an operating system kernel. Their published effort figures give the honest price of full verification, and their trusted computing bases show exactly what a proof still leaves unproved. This lesson uses both to decide where verification pays.
Model Checking: Exhaustive Search Instead of Proof
The third tradition supplies no invariants and writes no proofs. It builds the set of states a system can reach and checks the property against all of them, which is decidable when that set is finite. This lesson covers what it buys, the state explosion that limits it, and the techniques that made it usable anyway.
What a Proof of Correctness Actually Is
Testing samples inputs; a proof covers all of them. The machinery is a logic in which programs are statements about how they change what is true. This lesson builds Hoare triples, works a proof by hand, and identifies the one step that cannot be automated and is therefore where the work is.

