A story from earlier in my career about an internal framework that never reached production, and the architectural lessons it left behind.

Image generated with AI
Years ago I worked at a large consulting company, as a frontend developer on the core team of a big AngularJS application. Real product, real clients, real deadlines. This is the story of how one clever idea emptied that team one resignation at a time, until the only frontend developer left in the building was me, watering the plants.
Here is the part that still amazes me. The idea never reached production. It never even reached a development environment. It died as an alpha that nobody wanted to touch, and it did all that damage anyway, which is a very impressive body count for software that never ran.
I am telling it now because I keep watching new versions of the same movie: a team decides the framework cannot be trusted, builds a layer on top of it, and slowly discovers that the layer costs more than the problem it was supposed to solve. If your company is flirting with an internal framework right now, consider this story an intervention.
The Idea Sounded Completely Reasonable
First, the setup. Our application had a core, which my team owned, and a separate area called delivery. Delivery took the product and customized it for each client, changing screens, flows and business rules on top of our code.
That structure created real pain. Every framework upgrade, every breaking change, every library bump had to be coordinated between core and a pile of client versions. Upgrades were slow, scary and political, in that order.
So a senior colleague came up with a plan, and I want to be fair with him, because on the whiteboard it was elegant. We would never touch Angular directly again. We would build a wrapper, our own layer of components and services, and write the entire application against that layer instead.
The promise was seductive. If Angular changed, we would update the wrapper and everything above it would keep working. Angular versions would become an implementation detail. The application would be, in theory, immortal. Software architects love the word immortal, and software loves proving them wrong.
He considered himself the frontend reference of the place, so he did not wait for consensus. He got the blessing of one boss and went at it largely alone. Every part of the application was going to be its own NPM package, built and published by him, everything assembled from his internal registry like Lego bricks.
If you have been in this industry a while, you can probably hear the alarm bells already. We could not, or at least not loudly enough. It sounded like architecture. It sounded like the responsible, long term thing to do. Most disasters in this industry start by sounding like the responsible, long term thing to do.
A Framework on Top of the Framework
Working with it was another story, because the wrapper had a fundamental problem. You were not really working with Angular anymore. You were working with one man’s opinion of Angular.
You could not touch the framework directly. You had to learn his APIs, his abstractions, his way of composing a screen.
Angular was somewhere underneath, muffled, like a good engine inside a car with the hood welded shut. You could hear it running in there. You just were not allowed to speak to it.
And this new framework had to be learned without help. The documentation was thin, and I am being generous, the way you call a studio apartment cozy. Stack Overflow was useless, because no answer on the internet knew our wrapper existed. Every question had exactly one valid source, the author himself.
Remember that this was years before AI coding assistants. Today you can paste an undocumented mess into a chat window and get a decent explanation in seconds. Back then, if the author had not written it down, the knowledge simply did not exist. Our knowledge base was one human being with his own tickets to close and a finite tolerance for questions.
The NPM side made everything heavier. Since each piece of the application lived in its own package, simple tasks turned into ceremonies: install this, link that, bump versions across half a registry, and then, if the build gods were merciful, watch one button change color. Things that take five minutes in plain Angular took an afternoon, and some things simply could not be done, because the wrapper had not anticipated them.
The wrapper did not anticipate a lot of things. Foreshadowing.
There is a name for this pattern. The inner platform effect, a term popularized by The Daily WTF, describes a system built to be so flexible and so generic that it turns into a worse copy of the platform it sits on.
We had built a private, undocumented, alpha quality copy of Angular, on top of Angular. The original was free and had a community of millions. Ours had a README.
And under all of it there was a quieter issue that never made it into any slide. Learning this thing added nothing to your career. Angular skills travel with you anywhere. Skills in an internal wrapper that exists in one building are worth exactly zero the day you walk out of that building, and people were about to start walking.
The Quiet Exodus
Here is the twist I did not see coming. The first person to abandon the wrapper was its author.
He never finished it. He migrated a handful of screens, sketched the core of the framework, and resigned. What he left behind was not a platform, it was an unfinished alpha with ambitions, and a boss who had fallen in love with it. Of the two, the boss was the bigger problem.
Because the boss did not let the dream die with its creator. We were still on AngularJS, the old 1.x line, and Google had already announced it would end support, which it eventually did on December 31, 2021. The migration to modern Angular, something like Angular 8 at that point, had to happen. And he decided it would happen through the orphaned wrapper.
So the remaining frontend developers were asked, one by one, to pick up another man’s unfinished framework and carry it forward. One colleague tried, advanced a little, and resigned. Then the next one inherited it, pushed it a bit further, and resigned too. It became a relay race where every runner dropped the baton, walked out of the stadium, and got a better paying job at a stadium that used normal batons.
Hiring replacements was hopeless for the same reason. You cannot recruit someone with experience in a framework that exists in exactly one office. Imagine the job posting: “Required: five years of experience in a technology only four people have ever seen, three of whom quit because of it.”
In engineering we call that a bus factor of one. Ours was not even one anymore. It was zero, and the plan was still to bet the entire migration on it. At that point it stops being a bus factor and becomes a ghost story.
Eventually I was the last frontend developer standing, and I got named frontend referent. The same title the wrapper’s author had claimed for himself, which sounds like a promotion until you notice there was nobody left to refer. I was the referent of an empty room. The boss’s request was simple: finish the framework, and migrate the whole application to it.
A Year Alone With a Dying Framework
I spent my last stretch there, close to a year, in a strange position. My day job was keeping a deprecated AngularJS application alive. My personal mission was pushing, in every meeting where anyone would listen, for a real migration to modern Angular without the wrapper. Plain Angular, the one with documentation, a community and a future.
I made slides. I made arguments. I probably made enemies.
I failed. Not for lack of arguments, I think, but because I was one person, the delivery pressure never stopped, and the wrapper still had gravitational pull in the org chart even with its author long gone. Sunk cost is a hell of a drug, and that project was on the strong stuff.
That year taught me what it feels like to maintain software past its expiration date. Every security notice about AngularJS felt personal. Every hiring conversation was awkward, because who joins a team to learn a framework Google already scheduled for the graveyard, with a mandatory secret framework waiting behind it as a surprise?
At some point I accepted that the migration was not going to happen with me inside, and I resigned. I went to write modern Angular at another company, and working with normal components and normal documentation felt like coming up for air. The first time I googled an error and found an actual answer, I nearly cried.
The epilogue reached me later through former teammates. The company never migrated to Angular, wrapped or otherwise. They eventually rebuilt the frontend in Blazor, Microsoft’s framework where the UI is written in C#. Read that again: after years of building a shield to protect the app from Angular’s changes, the final decision was to stop using Angular entirely.
The wrapper never got past a handful of half migrated screens that no user ever saw. Its first real migration was straight to the trash, and honestly, that was its smoothest deployment.
What I Would Say to That Team Now
I have had years to digest this story, and I keep coming back to the same handful of conclusions. None of them are really about Angular.
One: an internal framework is a product, not a side project. It needs documentation, onboarding, a roadmap, and at least one person paid to maintain it. If the company is not willing to fund all of that, it is not building a platform, it is building a trap with good intentions and a nice logo.
Two: attrition is an architecture cost, and nobody measures it. The wrapper never crashed in production, because it never got there. Its cost showed up in a different dashboard, the one owned by HR.
When a technical decision forces people to learn things with zero market value, your best people will quietly choose the market. They will not fight you in the meeting. They will nod, open LinkedIn, and set their profile to open to work.
Three: protecting yourself from a framework usually means marrying something worse. Angular has thousands of contributors, years of documentation and a global hiring pool. Your wrapper has one author and a dream. The layer you build to reduce your dependency on a giant creates total dependency on a single coworker, and coworkers, unlike frameworks, can resign.
Four: an abstraction that has never survived contact with production is not architecture yet, it is a hypothesis. Ours stayed a hypothesis for years and still directed real decisions, real hiring and real careers. The alpha label should have ended every one of those conversations, and instead we treated the thing as inevitable, like weather.
The strangest part is that the original diagnosis was correct. Upgrades really were painful, coordinating core and delivery really was hard, and betting years of product on the roadmap of a framework you do not control is a real risk. Smart person, real problem, elegant solution, dead team. Being right about the problem buys you nothing if the cure needs more maintenance than the disease.
So if someone in your company is sketching a wrapper that will turn the framework into “just an implementation detail”, I will not tell you it can never work. Some companies pull it off, with dedicated platform teams and real budgets. But ask the uncomfortable questions first.
Who maintains this in five years? What happens when the author leaves? Would anyone learn this voluntarily, if they were not forced to?
In our case the honest answers were nobody, exactly what happened, and absolutely not. We just never said them out loud while it still mattered.
Have you survived your own internal framework story? Tell us in the comments, especially if yours made it further than alpha. We collect these, like scars.


