Modernizing an application is easy to argue for when the old system has completely failed but it is a harder situation is when it still works.
When I joined ReelWorld Productions, I inherited an application built primarily with PHP and AngularJS. It was functional and supported the business, but years of accumulated technical debt had made development increasingly difficult. Problems in the existing codebase consumed much of our time, leaving little room to improve the architecture or rethink how we built the product.
Replacing technology because something newer exists isn’t a compelling business argument. The existing application represented years of investment, the team understood it, and customers depended on it. So, if I wanted the organization to consider a different direction, I needed to do more than advocate for newer tools. I needed to prove that changing direction would make the product—and the team building it—better.
Starting With the Problems We Already Had
I didn’t begin by proposing a rewrite.
After working with the application for a while, I started experimenting on my own time with smaller improvements that could address problems the team was already experiencing.
One of the first opportunities was our development and build process because surprising amount of routine work was manual. Compilation, optimization, and other repetitive tasks interrupted development and created opportunities for inconsistency.
So I introduced some concepts to automate those processes giving us a foundation for compiling and processing application assets consistently while moving repetitive work into the background. It also opened the door to tools such as Sass and CoffeeScript, which gave the team a more productive way to work with the existing application.
Then came a result that was impossible to ignore because optimizing the application assets produced roughly a 65% improvement in application performance and I still remember showing the result to my manager.
Until that point, modernization was mostly an engineering argument. Suddenly there was something tangible on the screen. The application was substantially faster, and the improvement came from changing the way we built software rather than changing what the product actually did.
The priorities changed almost immediately because the best argument I could make for modernization wasn’t that the technology was newer. It was that I could demonstrate a better result and that lesson shaped everything that came afterward.
Making Development Better Too
Performance was the most visible improvement, but it wasn’t the only one. The automated build process began changing the experience of working on the application itself.
Tasks that previously required manual intervention became repeatable. Sass made styling easier to organize and maintain. CoffeeScript gave us an opportunity to experiment with a different way of writing client-side code. The team could spend less time managing the mechanics of development and more time actually developing.
For the first time in a while, working in the codebase felt like it was moving forward and that mattered the most.
Technical debt doesn’t only affect application performance. It gradually affects the people working around it. When every change requires navigating the same old obstacles, developers naturally become more cautious. Eventually the goal can shift from improving the system to simply avoiding breaking it.
The early automation work showed us that those constraints weren’t permanent because we could change the way we worked without throwing everything away.
And once we had done that successfully, a larger question became reasonable to me:
What else could we improve?
Looking Beyond AngularJS
At the time, the JavaScript ecosystem was going through a significant transition.
Our frontend relied on AngularJS, while its successor—Angular—was emerging with a substantially different architecture. Angular’s adoption of TypeScript, component-oriented design, and a more structured application model meant that moving forward eventually wasn’t going to be a simple framework upgrade.
At some point, we were going to have to rethink substantial portions of the frontend anyway and I saw that disruption as an opportunity. If we were already approaching a point where the frontend architecture would need to change, perhaps we shouldn’t limit the discussion to replacing AngularJS. Perhaps we should reconsider the architecture of the application as a whole.
I had recently helped with a significant overhaul of our marketing site, and the success of that project gave me more confidence to explore what a broader modernization effort might look like across our product suite and that’s when I began seriously evaluating Node.js for the backend.
Why Node.js?
PHP had served the company well, and replacing it simply because Node.js was gaining popularity would have been a poor reason to undertake a major migration. But what interested me was how well Node’s programming model aligned with the kinds of applications we were increasingly building.
Our products depended heavily on APIs and communication between services. Node’s event-driven architecture and asynchronous, non-blocking I/O were a natural fit for I/O-heavy workloads and applications coordinating multiple external systems. To me it was obvious that there was also an organizational advantage.
Angular was moving toward TypeScript on the frontend. A JavaScript/TypeScript-oriented backend offered the possibility of reducing the conceptual distance between the two sides of the application. Developers could work within a more consistent ecosystem instead of continually moving between unrelated programming models.
Then there was NPM.
Its ecosystem was expanding rapidly, providing libraries and tooling around many of the problems we regularly encountered. The momentum behind Node.js made it increasingly attractive not only technically, but as a platform we could continue building on and that’s what convinced me it was worth exploring. It’s just that convincing myself was the easy part.
Don’t Pitch the Rewrite. Build the Evidence.
I knew walking into a meeting and saying “we should rebuild our applications with Angular and Node.js” wasn’t going to be enough because a modernization effort of that size carries real risk. There are development costs, migration costs, retraining, unknown technical problems, and the possibility that the new system ends up solving problems the business never particularly cared about.
So I went back to the approach that had worked before and I built things.
In my own time, I created small demonstrations showing what development could look like in the proposed environment. I experimented with Angular, Node.js, modular application structures, and the tooling surrounding them.
Rather than asking people to imagine the benefits, I could show them.
I shared the prototypes with the team. I talked about the approach whenever there was an appropriate opportunity. I connected the technical changes to problems we already understood: development speed, deployment complexity, application performance, scalability, and our ability to evolve the product suite over time.
Eventually, I had an opportunity to present the larger idea to the company. And it was well received.
What had begun as experimentation became an actual modernization initiative.
From Prototype to Product Direction
Moving toward modular applications over the following year allowed us to establish clearer boundaries between functionality. Angular gave us a more structured frontend architecture, while Node.js provided a backend environment well suited to the services and APIs supporting the product.
We integrated the new architecture into our AWS environment and continued improving the build and deployment processes around it.
The results validated the direction as application performance improved by roughly 3×. And I also developed Webpack-based automation around production workflows that helped reduce deployment time by approximately 25%.
Those numbers mattered, but so did what they represented because we weren’t modernizing for the sake of saying we used Angular or Node.js. We were making the software faster, making deployments quicker, reducing friction for developers, and giving the product architecture more room to adapt to whatever came next.
Modernization Without the Big Bang
One of the things I value most about this experience is that the modernization didn’t begin with a mandate to replace everything because it grew incrementally.
First, automate a painful process. Measure what changed. Then improve another part. Build a prototype. Show it to someone. Listen to the concerns. Demonstrate another advantage and eventually, enough individual improvements formed a credible argument for a larger architectural change and that approach reduced risk because each step had value independently of the larger vision.
If the company had decided not to pursue Node.js, the initial automation still made the existing application better. If Angular hadn’t become the direction we expected, the prototypes still taught us something about modular application design. And it’s that experience that fundamentally shaped how I think about legacy systems today.
A rewrite isn’t automatically modernization, and old technology isn’t automatically bad technology. The question is whether the existing architecture is preventing the product and the people working on it from moving forward. If it is the job is to build a convincing path from where the system is today to somewhere demonstrably better.
Technology Changes. The Reasoning Doesn’t.
I’ve worked with enough languages, frameworks, and platforms over the years to watch plenty of technologies arrive, dominate conversations, and eventually give way to something else.
Engineering decisions happen in context.
The important question isn’t whether a technology remains fashionable ten years later. It’s whether it solved the right problem, at the right time, and left the system in a better position for whatever came next.
That’s one reason I continue working heavily with Angular and Node.js today. Not because I expect them to be permanent, but because I understand the problems they solve well—and I also understand that eventually the answer may change.
What I Took Away From It
This project taught me as much about influencing technical direction as it did about application architecture.
I learned that developers can identify a better technical direction without demanding that everyone immediately agree with them.
Build evidence. Measure results. Create prototypes. Explain the tradeoffs. Make the benefits understandable to people who don’t spend their day thinking about frameworks. And recognize that the people hesitant to replace a working system aren’t necessarily resisting progress. They’re often correctly recognizing risks that engineers excited about a new technology can overlook and good modernization has to address both.
The progression at ReelWorld—from build automation, to prototypes, to architectural changes, to a broader Angular and Node.js product direction—showed me that meaningful technical change doesn’t always begin with permission to redesign the system.
Sometimes it begins with making one thing noticeably better then showing people what happened. And then you keep going.
More Case Studies
Different problems, different constraints, and different kinds of solutions. Here’s another project from the collection.
Have a Complicated Problem of Your Own?
If you’re working with a system where the details really matter—or you’ve run into a problem that doesn’t have an obvious answer—I’d be happy to hear about it. You don’t need to know the solution before reaching out. Figuring that part out is often the most interesting part of the work. Send me a message below or reach me directly at mitchell@betavc.com