Most programming languages are remembered for their syntax. Almost none are remembered for the decisions that produced it.
Every keyword exists because someone decided one approach was better than another, usually after weeks of debate. Writing it took an afternoon. The reasoning behind it lasted about as long as it took everyone to move on.
I've been building BigTalk from the ground up: memory model, effects, regions, verification. I expected the hard part to be parsing and semantics. Instead I kept running into the same quieter problem.
Version control gives us perfect recall, but imperfect memory. Any change can be inspected, compared, blamed. You can find the line that introduced a bug. What git will not tell you is why that line was written that way instead of three other ways that were discussed and discarded, or never written down because they seemed obvious at the time.
Those conversations live in chat threads, calls, whiteboard photos nobody keeps. They are surprisingly hard to recover exactly when you need them most.
Designing a language makes this hard to ignore.
A language is little more than decisions wearing syntax.
Adding a keyword is easy, and rewriting a parser is easy enough. Choosing the keyword is the part that stays difficult after the merge.
Should this feature exist at all? Does explicitness win over convenience here? An inconsistency might have to stay, too, if fixing it breaks something that was never supposed to depend on it.
Those questions don't have single correct answers. They have a context, and context is usually the first thing a project loses. Without it, the next argument is often the old argument again, held by people who do not know it already happened.
There's a habit of treating architecture as structure, as if the diagram were the thing. In practice, architecture is also memory. A system's quality depends not only on the decisions inside it, but on whether it can still explain those decisions to whoever finds them later.
This matters more the longer a project is meant to live. The people deciding today are unlikely to be the people maintaining it in ten years. Even if they are the same people, memory is a poor dependency.
An undocumented decision eventually becomes indistinguishable from an arbitrary one. Nobody trusts an arbitrary decision, so they change it. Then the problem it was quietly solving comes back under a different name.
RFCs get treated as a large-project affectation. Something Rust does. Something a standards body does. Overkill for anything smaller. The value has never had much to do with size.
An RFC captures intent before that intent gets flattened into a diff. A useful one records the problem, the constraints, the paths not taken, and why those paths lost. Implementation detail can live in the code. The logic the implementation is downstream of usually cannot.
Writing RFCs for BigTalk was never the friction. Managing a growing pile of them consistently was: assigning numbers, tracking status, keeping the fortieth document under the same conventions as the first. That kind of upkeep never rivaled the difficulty of a type checker, but it made the collection worse every time it slipped, until the workflow itself became the thing I was fighting.
So I built a small CLI to stop fighting it: rfcman. It shipped under the BigTalk name ahead of the compiler. It does not do anything clever. It manages RFC lifecycles and keeps their relationships stable through UUIDs, so a document can change shape without losing the reasoning attached to it.
It exists to remove friction, the same reason a build system exists. Nothing about it was meant to be the interesting part of the project. It just turned out to be the part that let the interesting parts stay honest.
There's a common belief that systems rot because the code gets more complicated. Usually the code stays readable just fine. What disappears is the reasoning that used to hold it together.
Someone finds an odd abstraction, decides it is unnecessary, and removes it. Months later the problem it was preventing comes back, not because anyone was careless, but because the system had forgotten why the abstraction was there.
Software gets evaluated on correctness and performance. Continuity rarely gets the same weight, though it should. A system worth keeping has to preserve why its behavior looks the way it does, not merely what that behavior is.
Source alone doesn't carry that, and neither does documentation once it drifts. What has to survive is the link between decision and implementation: checkable, not merely remembered.
Building a language taught me something I didn't expect: deciding how it should work turned out to be the easy part. What's hard is making sure that in ten years, someone can still find out why.
Top comments (0)