This is a perspective piece, drawn from two decades of building production software: the alarm around AI replacing engineers gets the story backwards. AI has not created a new problem for the discipline. It has ended a decades-long exemption from a problem every other engineering discipline has always had to manage — components that do not behave the same way twice.
For most of software's history, the components developers reasoned about were predominantly deterministic by design. Given controlled inputs and state, the same code was expected to produce the same result — not because nondeterminism didn't exist (distributed systems, race conditions, clocks, and hardware faults are all real), but because it stayed at the edges of the system — the network, the hardware, the clock — rather than sitting inside the core application logic itself. That was a design choice, and it made an entire discipline possible: reproduce the bug, write the failing test, fix the code, watch the test go green and stay green. Software could treat its own materials as predominantly well-behaved — an assumption almost no other engineering field gets to make.
Every Other Engineering Discipline Already Lives With Uncertainty
Electrical engineers design around transistor beta — current gain — varying by a factor of three or more between two units cut from the same wafer, let alone two different batches. A circuit that only works at one exact gain value is a broken design, not bad luck. Mechanical engineers design around material stresses that shift unpredictably with weather, temperature cycling, and years in the field — the same alloy doesn't behave the way its datasheet promised after a decade of that. Civil engineers design bridges and floodwalls to a number that is explicitly a probability, not a guarantee: built for the '100-year flood.' Tolerance, margin, failure-mode analysis, and spec-driven development are not exotic specialties or new concepts. They are the baseline.
Software was never exempt from this because it earned an exemption. It was exempt because, until recently, almost nothing in the critical path needed to behave probabilistically. Put a genuinely nondeterministic component — a model, not a function — into that same critical path, and the exemption ends whether or not the discipline is ready for it.
What Actually Breaks: The Agile Assumption
Agile's commercial advantage was never maximum rigor. It was reducing the cost of being wrong early enough to capture market share and make a product the de facto standard before it had fully earned that position. That advantage rests on an assumption: iteration converges — each round of feedback reliably narrows the gap between what got built and what was actually needed. That trade held only as long as a few things stayed true:
- Unknown unknowns are acceptable: identifying known unknowns was never required.
- Iteration is the primary mechanism for exposing and validating assumptions.
- A fix, once verified, stays verified: green today means green tomorrow.
- The implementation is deterministic enough that the same input and state produce equivalent results.
The first two assumptions still hold: Agile handles uncertainty about requirements extremely well. It does not inherently solve stochastic behavior inside the implementation, and that is exactly where the other two break down once a probabilistic component sits in the critical path. A test suite that passed yesterday can fail today with no code change behind it. A verified fix can silently shift behavior on a different input. “The tests are green” stops meaning what it used to, and a team still treating it that way is debugging ghosts. Code was never the limiting factor here — comprehension was, and comprehension doesn't scale by shipping faster.
The goal is not to eliminate nondeterminism. It is to bound its consequences. The practical answer isn't exotic: quantitative controls wherever a property can actually be measured, qualitative controls — explicit human review — around whatever can't be measured yet, and layered review agents in between, checking work the way a second engineer would rather than a fixed threshold. That's exactly the kind of scaffolding this discipline specializes in. The mistake isn't picking one of these. It's not understanding the tradeoff between trust and comprehension: trusting a metric past what it actually validates, or falling back to manual review for exactly what a metric would catch faster.
The Discipline Was Always Available. It Just Was Not Required.
None of this is a knock on the developers and programmers who built extraordinary systems under the old assumption. That assumption was real, and building well inside it was and is a genuine skill. What is changing is the floor underneath everyone, all at once, faster than we can adapt: statistical validation alongside pass/fail certainty, explicit tolerance and error budgets alongside exact specifications, production monitoring treated as load-bearing infrastructure rather than an afterthought.
Every other engineering discipline built that muscle memory because their materials demanded it from day one. Users are starting to demand the same standard from software that they've always demanded from a bridge or a power plant. The world was never fully deterministic to begin with; AI is simply the reason software can no longer pretend otherwise. The title of Engineer has always meant thriving in exactly this kind of environment. It is simply becoming possible, for the first time in a long while, for Software Engineers to grow all the way into it.
