You can add a word. You can't change what one means.
There is no codebase per customer at GoodBarber. What defines an app is a description — which sections exist, how they're arranged, what they look like, how they behave — read by an engine that all apps share. When we improve the platform, we're improving the engine that reads those descriptions, and the changes every app inherits at its next build. That architecture has a consequence we think about every single day, and it's the least visible thing we do. Two clocks The back office ships continuously. A fix this morning, a feature this afternoon; by the time you read this, it has probably changed again. The binary doesn't. An app's binary ships when its owner decides to ship it — for the next release, in six months, or never. Some of the apps talking to our servers right now were built years ago and haven't been rebuilt since. So the two halves of the system never ship together. The description sitting between them — written by today's back office, read by a binary from whenever — is a grammar both sides have to keep speaking. And a grammar shared with speakers you cannot call back to class obeys hard rules. What the grammar forbids You can't rename a word. You can't change its type. Above all, you can't change what a word means: somewhere out there is a binary that learned it three years ago and will keep understanding it the old way for as long as it lives. Our configuration files carry encodings from another era — formats we would never choose today. They stay, and they stay readable, because the day they were written they became part of the contract. Old link formats still resolve. Older request parameters are still accepted alongside their modern replacements. None of this is debt we haven't found time to pay down. It's commitments we've chosen to keep — the difference being that debt you plan to retire someday, and these will outlive most of the code that reads them. What the grammar demands Inside the engine, every read of a setting states what happens when the word isn't there. The accessor's signature won't let you skip the question: you don't get the value without declaring the fallback. And a house rule forbids inventing that fallback on the fly — it gets decided, not guessed, because it is the answer to a real question: what did apps do before this option existed? The behavior a customer had yesterday must be the behavior they have after our next deploy, option or no option. The data follows the same regime. The schema grows by addition — new words, new optional fields. What it almost never does is take something back. Old forms don't die. They retire. There's a pattern in our engine that new code isn't supposed to use anymore. It isn't deleted, it isn't wrapped in warnings — it simply stopped being what we write. The historical form keeps working next to the modern one, because ripping it out would mean breaking descriptions that have no reason to change. That's the practical shape of an additive grammar: modern code and old commitments in the same codebase, neither pretending the other doesn't exist. Cleanup is the one luxury a shared grammar doesn't grant you — what it grants instead is that nobody's app stops working because we got tidy. The other half of the conversation The grammar isn't only additive on the way in; it's negotiated on the way out. A client tells the platform who it is — and the platform knows what a binary of that generation understands. New capabilities are served to the apps that can speak them. Everyone else keeps receiving the language they know, for as long as they keep showing up. That's the part that makes the whole thing livable. If every improvement had to be understood by the oldest binary still alive, we could never move. Because the server adapts to who's asking, the newest apps get the newest platform, and the oldest ones get something better than an upgrade: the absence of a surprise. The filter All of this has a price, and the interesting thing about it is when it gets paid. Every word added to the grammar is a word we'll be reading for years — parsed by the engine, honored by the servers, defaulted correctly for every app that predates it. That cost doesn't arrive after shipping; it arrives at the design table. Some features don't get built, not because they're hard to write, but because their compatibility burden would outlive their usefulness. It's the least satisfying kind of engineering decision — nothing ships, nothing breaks, nobody sees it — and it's the one that keeps the grammar speakable. Changing everything without breaking anyone doesn't mean moving carefully. It means knowing which promises you're no longer free to take back — and making every new one on purpose.
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to