Coding tactics: the series
Over the summer I published a series on coding tactics: the everyday craft of ifs, loops, and the reasoning behind them. Eight posts, one thesis, best read in order. This is the map.

The thesis
Plenty is written about design: databases, queues, services, where the boxes go. Far less about tactics: the coding itself, line by line. It borders on style but reaches past it: a line of code is where complexity compounds. Programming is building and managing complex systems , and this series is that claim at its smallest scale.
The series was not about formatting, naming conventions, or how to split a problem into components. Formatting is a job for a tool: I use prettier and live with the 15% I dislike, because the whole team gets one style for free. Naming conventions and decomposition are design questions with a literature of their own. What is left, the lines themselves, is the part no formatter and no pattern catalog does for us.
The series runs on one idea: dealing with complexity is a long-tail discipline, not a search for one-time major wins. No single technique here saves a project; the last post covers the one partial exception. The habit of applying all of them, across every line written and read, is what keeps the mess from growing faster than the code.
The posts
The series is about ifs and loops: how to reshape them, how to check that they are right, and when to break the usual rules. Each post stands alone, but they build on each other.
Code linearization
The first post is about making code logically simpler by linearizing it. Less indentation, more readability, exit early.
Logical optimizations
The second post is about the conditions themselves. Merge nested ifs, test each condition once, and drop the checks that do no useful work.
Boolean algebra
The third post is about the logic inside a condition. De Morgan’s laws and a few other rules untangle an expression, and a truth table spells out a function of a few booleans in full and doubles as its test suite.
TDD as religion
The fourth post is about the belief that a green suite makes code correct. Tests sample behavior and cannot prove it, yet the process treats green as proof, and an AI agent takes green as gospel.
Loop and if invariants
The fifth post is about proving code right instead of sampling it. An invariant is a fact that holds every time control reaches a line, every block leaves one behind, and stating it is the cheapest proof available. No formal methods needed.
break/continue is the new goto
The sixth post is about structured jumps. Dijkstra’s paper was about the unrestricted goto; break, continue, and labels keep code flat and skip work, and the flags and nesting that replace them are usually worse.
Exotic goto: generators and exceptions
The seventh post is about two more jumps. yield and throw reach farther than break and decide what happens to the code after the jump, they flatten code that would otherwise be a state machine, and each belongs behind a small boundary so both ends stay in view.
“Premature” optimization
The last post is about when optimization is premature, and when “premature” is the excuse. Knuth’s whole quote, the big win that rarely comes, and the long tail of small optimizations that are cheapest to take while the code is written.
Companion posts
Three posts from the same summer are not installments, but they belong to the same family:
- Cheating as a programming discipline — knowing enough about the problem, the machine, and the people on the other side to skip the work the situation does not require.
- Duff’s device in JavaScript
— loop unrolling with a fall-through
switch, and a verdict that flips with the engine, its version, and the CPU underneath. - Death by a thousand reasonable decisions — how bad code accretes from reasonable decisions, and what to do about it.
What it adds up to
None of this is new. Guard clauses are in Fowler’s catalog, and De Morgan’s laws are nearly two centuries old. The invariant is Floyd and Hoare, the structured jump is what structured programming kept of goto, and the quote about optimization is Knuth’s. What the series adds is the combination and the habit: the same few moves, applied in order, on every function. The payoff is code that follows the decision it encodes, with a correctness argument that fits in one head.
Reading it back, the thread is tighter than I planned. Flat flow makes conditions simpler. Simpler conditions make invariants cheap to state. A stateable invariant is what makes a jump safe. And the same simplicity keeps the long tail short, which is most of the optimization question. The series grew while I wrote it, too. The opener promised break and continue as the next post; four posts got in the way. Verification turned out to need a pair of posts, the critical one and the constructive one. The goto argument needed a second installment for the jumps that do not look like jumps.
In one sentence: write the simple version, argue it correct, and take the trivial optimizations on the way. Do it every time: no single move matters on its own, and all of them matter together.
This was the first face of complexity-taming, the one that lives in ifs and loops. Other faces lie further out: dependencies, API design, data layout. Same discipline, larger units.