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. The debate took weeks. The implementation took hours. The reasoning lasted about as long as it took 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. Rewriting a parser is easy enough. Choosing the keyword is the part that stays difficult after the merge.
Should this feature exist at all? Should explicitness win over convenience? Should an inconsistency stay, because fixing it breaks something that was never supposed to depend on it?
None of those have a single correct answer. 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. None of that is hard the way a type checker is hard. All of it made the collection worse every time it slipped.
Eventually the workflow itself was 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. Often the opposite happens. The code stays readable. 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. Because the system had forgotten why the abstraction was there.
Software gets evaluated on correctness, performance, maintainability. Continuity rarely gets the same weight, though it should. A system worth keeping has to preserve more than behavior. It has to preserve enough of its own account of why the behavior looks that way.
Source alone does not carry that. Documentation alone does not either, 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 did not expect.
The hard part was never deciding how it should work.
The hard part is making sure that in ten years, someone can still find out why.
