I promised myself that starting this week I'd switch to lighter topics. But on Monday, my JSNation adventure officially came to an end, and I reali...
For further actions, you may consider blocking this person and/or reporting abuse
Excellent article! This reminded me of one of my own migrations.
My last migration was from an old PowerBuilder desktop application. In our case, migration was no longer optional: the only developer who truly understood the app had already retired, there was almost no documentation and the codebase was a mess. ๐
We tried to follow the Strangler Fig pattern, but the business logic was so tightly coupled that we had to take a more waterfall-like approach and migrate large features end to end. It was not necessarily the safer approach, but without it, we would have ended up with hundreds of feature flags and an even harder system to manage.
That made the risk very real and it showed exactly why waiting only makes legacy systems harder and, in some cases, ultimately much more expensive to replace.
That's so true. We all love talking about patterns and best practices, and then reality shows up. ๐
Sometimes the textbook solution simply doesn't fit the constraints of the project, and you have to adapt. In the end, getting the migration done is more important than following a pattern perfectly.
And honestly, your story reinforces what might be the main message of the article: don't postpone migrations. The longer you wait, the fewer options you have, and the more expensive and risky everything becomes.
Exactly. As always in software development, it is all about trade-offs.
I agree, but at the same time, I understand why migrations get postponed, a running product still needs to generate revenue and migrating a legacy system can require a significant investment.
Maybe the better approach is to continuously maintain and modernize the product before a full migration becomes unavoidable. That also requires budget, but in the long run, it can be much cheaper and less risky than being forced into a large migration later.
Exactly! These things are never easy.ย
But I've seen migrations postponed even during relatively quiet periods because they were considered annoying and disruptive. Product owners would complain that they were a burden for developers, testers, and everyone involved. That's when my favorite argument came into play: security. ๐
I'd scare them a little, and later they'd thank me when customers started running security audits. What a surprise. ๐
And yes, continuous maintenance is definitely the best approach. A migration from Angular 7 to 21 is a nightmare, but going from 21 to 22 is almost trivial. That's the beauty of keeping things up to date: future migrations become boring, which is exactly what you want.
That "temporary" adapter joke hurt ๐ We had one of those bridge solutions hanging around for three years before someone finally killed it. Nobody even remembered what it was for anymore. Thanks for writing this.
Hahaha, exactly! ๐ That's how those "temporary" adapters usually end up.
And honestly, the only thing worse than finding one after three years is realizing that it's still needed after three years. ๐
And nobody dares to touch it because 'it still works' ๐ until it doesn't.
Hahaha, exactly! ๐ Or some nasty security vulnerability shows up and suddenly everyone is shocked. ๐
Every legacy system has that one file named
utils.js,helpers.java, orfinal_final_v2.cs.Nobody knows who wrote it.
Nobody knows what it does.
But everyone agrees touching it requires a change request, a rollback plan, and a prayer. ๐
Hahaha, exactly! ๐ Every legacy system has one of those files. Even the coding agent takes one look at it and submits its resignation. ๐
๐ Somewhere inside that file is a comment from 2018 that says:
// temporary fix
And everyone is too afraid to ask temporary for whom.
๐คฃ
Hahaha, exactly! ๐ Maybe they meant temporary on a cosmic scale. ๐
Like, "temporary" for the remaining lifetime of the Universe.ย ๐คฃ
Sylwia, this brought back memories ๐
I've worked on legacy systems before, and one thing I've learned is that they usually look much simpler from the outside than they actually are. Once you start digging, you realize how many decisions, dependencies, and business rules have built up over the years.
A lot of the time, there is a reason things ended up the way they did, even if it isn't obvious at first.
Exactly! ๐ And until you've spent enough time in the project, you usually don't know what those reasons are.
People often assume that legacy code exists because somebody was incompetent. Then you dig into the history and discover that, six years ago, half the team left and two juniors were left on their own for six months, doing the best they could under the circumstances. ๐
Most of the time, there is a story behind the mess. And understanding that story is often harder than understanding the code itself.
First of all, it is always reassuring to learn that other developers face similar challenges in their projects and that I am not the only one who regularly ends up in impossible situations ๐
In my experience, front-end migrations pose an additional non-technical challenge: they directly affect the user experience. The moment anything looks even slightly different than before, screenshots have to be retaken, manuals have to be updated, and users have to be retrained. It is even possible that UI changes touch on legal issues, and you need approval from a governance body first. Accessibility is another topic I will not even get into now.
Back-end migrations are easier in this respect, but on the other hand, the customer is far more afraid that you will break the business. Shortly before the advent of AI, I was asked to consult on a COBOL migration project. The last of their developers was about to retire. After a long and winding road, the project decided to post a job advert for a new programmer. You should never underestimate how many red flashing warning lights humans can ignore for how long ๐
Oh yes, absolutely. ๐ Frontend migrations almost always end up changing something in the UI, even if you're using a standard component library like Material. Fortunately, my experiences have generally been positive. Customers were happy because things looked cleaner and more modern. Of course, that's only true as long as the changes are relatively small. God forbid you change something significant, even for the better, because then everyone suddenly starts missing the old version. ๐
And I love that COBOL story. What resonates with me most is the part about humans being able to ignore red flashing warning lights for years. I've seen that so many times.
To be honest, I consider myself a fairly average senior developer in terms of pure technical skill and architecture. But I do have one thing that often pushes me into tech lead roles: social skills. ๐ Sometimes I'm actually able to convince the business to listen to reason and deal with problems before they become catastrophes. Not always, of course, but often enough to make a difference. ๐
I wonder if simply showing the article's title image would be enough to convince stakeholders to migrate to a new stack. It looks surprisingly convincing! ๐
Hahaha, exactly! ๐ We all prefer living in the shiny city of the future rather than in a gloomy industrial landscape that feels like Eastern Europe in the 90s. ๐
Great read! You make a lot of excellent points about the psychological and technical friction of migrations, especially on the front end, where frameworks move at lightning speed.
But your post also made me think about a completely different tier of "legacy" code, the kind that doesnโt just predate modern frameworks, but actually predates the public internet entirely.
Iโm talking about the deeply buried back-end bedrock, like COBOL systems or AS-400 applications. These are the quiet, invisible giants running our global financial institutions, municipal supply chains, airlines, and government agencies every single second of the day.
In those ecosystems, "the longer you wait, the worse it gets" takes on a terrifyingly literal meaning. It's not just that the codebase grows sprawling; it's that the pool of engineers who actually understand the business logic and syntax is literally aging out of the workforce. When a critical corporate ledger or transaction system relies on logic written in the 1970s or 80s, a migration isn't just a refactor; it's high-stakes digital archaeology where a single misstep can halt critical infrastructure.
It really puts the definition of a "legacy system" into perspective. Working on those deep back-end monoliths feels less like maintaining tech debt and more like defusing a bomb made of decades-old logic.
Have you ever had to bridge the gap between a modern front-end layer and one of these deep, ancient enterprise back-ends?
Thanks for this comment! And yes, I completely agree. The scale of some of these systems is truly mind-blowing.
Someone in the comments here mentioned that they once joined a COBOL project as an intern and discovered that part of the code had actually been written by their mother, who had long since retired. ๐ That really puts things into perspective.
Personally, I've never had to build a frontend on top of a COBOL or AS/400 system, but I can absolutely imagine the challenges because I once worked with a Java backend that had originally been created as a proof of concept about 15 years earlier. Then the project kept growing and growing, and eventually people discovered that making even simple changes had become a nightmare. Adding a single form meant touching more than 80 files. ๐
And I don't think that was necessarily because the original developers were incompetent (although, like in every project, that probably played some part). More likely, nobody expected the project to reach that scale when it started. There were discussions about fixing the architecture, maybe splitting it into microservices, but deadlines kept coming, priorities shifted, and eventually I moved on. I honestly don't know how that story ended.
Which, I guess, is exactly how legacy systems are born in the first place.ย
I remember that I had a former friend where his father used to work with Cobol system.
Hahaha, from what I've heard, that's basically a gold mine these days. ๐
I mentioned COBOL to my father and he burst out laughing. He learned it back in the 1960s. Meanwhile, the Canadian government is finally moving away from those legacy systems and leaning into AI these days.
Hahaha, I always say that if AI has made its way into government systems, then it's officially everywhere. ๐
Governments are usually among the most conservative organizations when it comes to technology, so when they start embracing AI, you know it's no longer just hype. The future has already arrived. ๐
hahaha. Yeah, my current premier minister is huge in technology. He want to modernize the public civil serve and make productive like the private industry. He is a business man in most of his career.
Hahaha, that's nice. ๐ Unfortunately, ours is more of a career politician. ๐
Very Very Great Article Sylwia๐ The longer you wait, the worse it gets this is the most honest truth in software We had a 2,000-line process() function that no one touched for years We called it The Heart of Darkness. When we finally had to change it, we learned more about the codebase in one week than in two years of avoiding it.
The code wasn't scary because it was complex. It was scary because we didn't understand it. And the only way to understand it was to touch it.
Thanks for the reminder. ๐
Hahaha, I love "The Heart of Darkness"! ๐ Every legacy application seems to have one of those.
And you're absolutely right. Sooner or later, somebody has to touch it. The code itself usually isn't scary because it's inherently complex, but because nobody understands it anymore. And unfortunately, the only way to understand it is to dive in and start changing things.
Which is exactly why I'd rather do it sooner than later. ๐
Few years ago I was involved in migrating a oracle forms app to a React app. It was a total mess. Before us one of the leading tech company has tried to do it and failed. We, the in house team started the migration on top of that code base. When I read this article I understand why it was a mess. Learned so many things that I shouldnt do in a migration, from that project.
Thank you! ๐ And that's exactly how I see it too. When it comes to architecture and migrations, I often catch myself realizing that people have already encountered most of these problems before us. There are patterns, best practices, and lessons learned, and it's usually much better to learn from other people's mistakes than from our own. ๐
Of course, reality always finds ways to surprise us, but having those battle-tested ideas in the back of your mind makes things much easier. If my article helped you put some of those experiences into perspective, then I'm really happy to hear that. ๐
Hey Sylwia!
When I read the title, I was already hooked โ which is hardly surprising... you've done it again. I absolutely loved your article; it captures the pain of a migration so well!
Personally, I hate migrations. Every single time, they turn into a nightmare โ regardless of how good the existing codebase is.
In fact, I recently completed one myself, both frontend and backend, and even for a relatively small application it took weeks of work. And that's without having to maintain two versions in parallel.
In my case, there was a v1, and the v2 introduced so many changes that the only thing worth keeping was the customer data; everything else had to be thrown away. I don't even want to imagine what an incremental migration would have looked like. Working on my own, I simply couldn't have pulled it off โ or what took weeks would probably have turned into months of transition.
This really resonated โ especially the "temporary" adapter joke, because we all know temporary in software engineering means forever ๐
The point about migrations being an iceberg is so accurate too. From the outside it always looks like "just upgrade the framework," and then you open the codebase and realize the real problem was never the framework itself โ it was the entire ecosystem that grew around it over the years.
The house renovation analogy at the end is perfect. The only truly bad strategy is doing nothing, and waiting until a production incident forces your hand. Saving this one for the next time I need to convince someone that migration debt is real. ๐ธ
I think I prefer the big band approach because of how I am wired, it's even exactly the approach I am using now for a clients real estate website. I built it with pure PHP, and now want to rewrite the whole thing in Laravel in 2 months ๐ , wish me luck ๐ฉ. But it's good to know that refactoring too is a good choice, you can't just break your entire app if your business heavily depends on it.
Lovely article!