ReadingResearchRadarInvestment framework
Sign in / Sign up
← Back to reading
NewsMaterial3 min readDisconfirmAI Editorial

Antithesis Distinguished Engineer Sean Allen: Exhaustive Matching Turns Missed Branches into Compilation Errors, Catching Defects Earlier Than Testing

In an interview with The Pragmatic Engineer, Antithesis Distinguished Engineer and core contributor to the Pony language, Sean Allen argues that testing is the latest method for ensuring correctness. He advocates using type systems in ML-family languages to make illegal states unrepresentable and verifying distributed system invariants through repeatable workloads (such as the Bank Test), rather than relying on random unit tests.

2026-11-10 23:00 GMT+8

Sean Allen is a Distinguished Engineer at Antithesis and a core contributor to Pony, a programming language designed for concurrency. Previously, he worked on confidential computing at Microsoft. In an interview with The Pragmatic Engineer, he presented a counter-intuitive stance: for engineers who truly care about correctness, testing should be the lowest priority.

His core argument is that testing occurs late in the development process, and you should complete as much verification as possible before reaching that stage. Specifically, the type systems provided by ML-family languages (Standard ML, OCaml, F#, and Rust, which is influenced by them) can catch a large number of errors at compile time. He cited a key mechanism: when you have a sum type with five cases and use exhaustive pattern matching, extending it to six cases will cause the compiler to immediately report every location in the codebase that fails to handle the sixth case. Exhaustive matching turns every bug involving "forgetting to handle a new branch" into a compilation error.

The principle behind this is "making illegal states unrepresentable." A type system can express states and valid transitions; once these are established, the system cannot enter states you do not expect. You only need to test the logic that the type system cannot express, rather than the entire system.

Allen further distinguishes between testing and workloads. He believes that when performing property-based testing on distributed systems or databases, what matters most is not randomly generating inputs, but defining a workload: your inputs are the operations driving the code (such as GET, PUT, DELETE), and your validation consists of the rules used to confirm the system is functioning correctly. He cited the Bank Test as a specific example: if a system contains $10,000 distributed across ten accounts, a workload continuously transfers money between accounts while a checker component constantly queries the total balance. If isolation guarantees hold, the checker should always see exactly $10,000. This workload does not specify how much to transfer or when; it only describes how transfers occur, allowing invariants to expose problems on their own.

Sign in / Sign up
ReadingResearchRadarInvestment framework

He acknowledges the boundaries of this approach: in small systems, if you can fit everything in your head, you may indeed rely less on the compiler. However, as systems grow larger and teams expand, the ability to delete a class and have the compiler tell you exactly where things break becomes irreplaceable.

Gergely mentioned in the introduction to the interview that he is increasingly focused on software correctness—the volume of code produced by AI agents is unprecedented, meaning more defects have the opportunity to be deployed to production environments. Sean's stance—capturing issues through type systems and workload validation before testing even begins—directly addresses this concern.

Sources

  • newsletter.pragmaticengineer.com↗
Continue researching →