If your organization developed an application using the framework formerly known as Angular, now retroactively rebranded as AngularJS, you probably know that all that hard work and capital you put in now is bolted firmly to a sinking ship. AngularJS will officially exit long term support in July 2021, and that’s if you’re using the latest version. After that, no one who runs software responsibly will want to touch your product with a barge pole. Yes, there are a ton of places like hospitals and city governments running all sorts of unsupported ancient software without bug fixes, but this is risky and you know it.
And yet you find yourself not wanting to pay your developers to rewrite all that perfectly good front end code again. Your users might even still be settling into the systems written in AngularJS. They still call it ‘new’ on their side of the screen because time does not seem to vanish quite as quickly in user space, especially when that user is just trying to do their job using your application. I’ve been asked, “how do I know this won’t happen again in another 5 years?” Truth be told, of course, no one can know that. Heck, I still remember when jquery was considered revolutionary, and that wasn’t so long ago. The trauma is real!
My current project involves an application that supports one of the key business activities of my client. People log into this application to record and process information that lies at the heart of what my client’s business does. It consists of a top-level menu with probably a dozen or so core workflows. It’s written using AngularJS on the front end. I have implemented a proof of concept and gone a few steps beyond that towards migrating to Angular in place by setting up a hybrid app. With some well-used components of the app now replaced, it is surprising how little people have noticed the presence of the new framework. With any luck, the whole thing will move over in a course of a year or so without any big fuss made, everything being silently refactored under the covers often released in conjunction with new functionality.
Project Assessment Required
It is important to assess a project first to see if it is ready for migration. If you need to migrate an app and it’s not doing well on one of these dimensions, do yourself a favor and shore that up first. Everyone who’s considered it has seen the official guidance (https://angular.io/guide/upgrade) and the things that document mentions are usually indicators of a project that has taken quality seriously to begin with. The four I would specifically mention are:
- use of component directives,
- use of modular design and build system (like Webpack), and
- rigorous implementation of automated testing
Obviously there are different levels of adherence to each of these factors: for example, permissiveness of the level of typescript was an issue in some places for us, which meant some small things had to be cleaned up and some even temporarily made to be ignored by the typescript compiler.
In addition to pretty much being ready with typescript, the app I am porting is also mostly implemented using AngularJS component directives for reusable parts, which are more analogous to Angular’s organization. I converted the build from a basic gulp copy to a webpack build with an eye to starting a hybrid app. In short, while there was and still is work to be done, this project is a good candidate slowly migrating over to the new Angular.
Finally, your automated testing is going to be your best friend when re-implementing a page or component in the new framework. Sure, you can look at a piece of code and generally understand what it does, but if you have good testing, all that will be spelled out in test cases. End to end tests (ETEs) can often just stay the way they are, merely updating page objects so that DOM references are up to date. Unit tests on business logic classes may be in a similar situation, and if abstracted from rendering often need no update whatsoever. Component controllers and rest layer classes for example though will require rewrites, and to the extent that your E2E’s and other tests outline expected behavior, a developer will not have to go hunting for information on those things or worse simply omit features because they were not aware of them. Keeping up a comprehensive set of automated test cases has always been an important part of refactoring in general.
Why a Hybrid App?
The main benefit of this migration path is that it is incremental and iterative, not that it is easy or fast. You will find yourself rewriting plenty of code, but you should be able to keep a running product at all times. This approach lowers risks by allowing smaller releases. Refactoring skills, i.e. pivoting a technical implementation behind functionality while keeping that functionality the same on the surface, is important here. A good software system should be like the Ship of Theseus: over time, you can replace any part and eventually all parts, but it should remain an operational entity at all times. This is the philosophy of migration from AngularJS to Angular.
The pilot project was a very simple page that I put on a route of its own just to show that I could run both Angular and AngularJS code in the same project. It was a simple feature flags information page in this case, and all it had to do was make one rest call and render the results to the user. This page would also serve as the basis for a discussion about the coding style we would adopt. Angular has set up some pretty intuitive and useful standards that we have yet to really take any exception to (https://angular.io/guide/styleguide).
One funny byproduct of the Angular framework upgrade is the search engine perplexity it causes. Often pages that have long answered perfectly to queries about “Angular” now speak to the older framework, especially when you’re looking into how to handle one of the libraries that you will need on both sides. Often you will want to find information about how to handle a situation involving a combination of support libraries during migration, which can really narrow the list of applicable search results. If your style tends to be looking for examples on the internet, be prepared to read more API documentation and to have to piece things together from there. I have found myself returning frequently to the official guidance (https://angular.io/guide/upgrade), discovering new insights from the same text, much like an archaeologist consulting the Rosetta Stone.
The Angular Ecosystem
The external libraries that frequently go with AngularJS also have important changes we need to address. Bootstrap components are a struggle: the Angular components will only work with version 4 but AngularJS components go up to 3. Therefore you need a way to migrate your CSS at the same time. There are ways to isolate your usage of Bootstrap 4 only to the Angular components on the page, and we have implemented some components this way but challenges still await us there. Protractor seems to be trying to decouple itself from Angular: no more AngularJS model queries in later versions and apparently also no more AngularJS test modules. That is a big deal if your project relies on those things heavily. UI Router seems to be the most amenable of the three major secondary frameworks involved in our migration. I have had little trouble so far replacing routes, but then our routes are wider in number than they are deep in layers.
The Strangler Fig
Just like building software in the first place, migrating software in an iterative way is favorable over the “big cutover” or all in one rewrite. Martin Fowler has identified a pattern he calls the “strangler fig” application (https://martinfowler.com/bliki/StranglerFigApplication.html). This biological analogy reveals a situation in which one organism is effectively replaced by another, but in the meantime, the second organism uses the structure of the first to get started. Implicit in this analogy though is the observation that it is a slow process; the strangler fig competes with the existing priorities of the trees, which continue for a long time in parallel. Our project is just beginning this process, and more lessons are sure to come.