We Are Basically Still Using Punch Cards
It’s a bit depressing that in 2026 we still manage code as a bunch of text files. Every change to a program relies on humans carefully editing text files by hand, even though humans are really bad at accurately doing the same thing over and over again. We make syntax errors. We misread code. We copy/paste one too many times. We mess up git merges. AI is a bit better at modifying code, but pays the same costs and makes the same mistakes humans do.
Our engineering toolchain is basically a highly evolved version of punch cards.
On small programs, this cost is manageable, but becomes a millstone on large codebases. Trivial changes such as retyping a variable, introducing a smart pointer, or removing a global become prohibitively expensive. There’s just too much typing, too much to review, and too much risk. Even trivial changes become non-trivial investments.
If your product is successful, this will eventually become a real problem. Your legacy code — your most important asset — starts to ossify. The more it grows, the harder it is to move forward. Keeping up with your competitors gets harder. Adopting new security standards turns into a serious cost. Rewrites become tempting, but distract the engineering team from responding to customer demands for months or years (and frequently fail). Usually by the time you’ve successfully rewritten, you’ve either lost the market to your competitors or recreated all the complexity you hoped to escape.
We can do so much better.
Get Ben Ross’s stories in your inbox
Join Medium for free to get updates from this writer.
Source code has structure, and our tooling should understand that structure. Engineers (and AI) should not need to hand-edit dozens of source files with our error-prone fingers and fuzzy eyesight. It should be trivial to ask questions like “what are all of the functions that modify this variable”, or “find all functions that take a parameter of this type”. Languages like Rust should not need lifetime annotations because they can be computed. Whole-program analysis should be trivial, no matter how big the program is. Safely making trivial changes to the program should be trivial, no matter how many places it needs to be done.
We (the industry) have taken baby steps in the right direction. Static analysis tools exist. Clang tidy and similar tools have fixers. IDEs have tools to perform some trivial tasks in some languages (e.g. renaming a variable). AST grep is crazy fast and fairly powerful. They are all useful in some way, but have serious flaws; they are generally too slow, don’t provide whole program analysis, don’t understand precompilers, or don’t provide read/write capabilities.
We need a tool makes it trivial to programmatically understand and modify code. It needs to be crazy fast. It needs to support 10s of millions of lines of code. It needs to be easy for an engineer to get started with. It needs to understand the structure of the code.
During my last few years at Microsoft, I wrote such a tool for refactoring Word. Word is written in C++, which is (to understate the point) a complex language. We called the tool Maskin (Norwegian for “machine”).
Using Maskin completely changed how I refactored code. I stopped hand-editing code — that was too dangerous. Instead, I wrote C# scripts that used Maskin to evaluate predicates about Word’s code and then modify it appropriately. The Maskin script could update one function or 1000 functions in Word and determistically do the same thing every time. If I found a bug in my logic, I could fix the bug, git restore, and rerun my script. It ran locally on my dev machine with no token costs or IP leaks. Code reviews became trivial. I changed how I refactored from vertical changes to horizontal changes (more on that in the future). It improved my productivity while refactoring by around 10x. It was magic.
Even better, another engineer on the team taught Claude to write Maskin scripts. This dramatically reduced his token costs vs. asking Claude to make the same change to Word directly, and resulted in a deterministic change to Word. The determinism was a key cost savings — because the Maskin script is guaranteed to run the same logic everywhere, code reviewers didn’t need to worry about AI-induced hallucinations or misunderstandings. This in turn made code reviews much cheaper and more accurate. The combination was pretty mind blowing.
Now that I no longer work at Microsoft, I’ve started rewriting Maskin as an open source project in Rust. I’m new to Rust, so it’s slow going. Future posts will cover this journey. Stay tuned!
Next in series: Representing Source Code as a Graph






