How we upgraded a website with half a billion annual users to Angular 7 in less than a day
and how we will do it much faster in Angular 8
On the BlueWeb project, which is a project to completely rewrite the B2C web applications of Air France — KLM, we have been using Angular since the early days. We started our project on Angular 2.0.0-rc.2.
Since then Angular has gone through some major changes and also quite a few versions. In this blogpost we will share our experience in keeping up to date with the latest Angular and how we keep improving and cutting the time for each upgrade.
But first, why is it even important to keep up to date with the latest version?
We believe that the best measure of a healthy codebase and development team, is the time it takes from wanting a change to the time it is developed and deployed in production.
Sometimes people think that upgrading infrastructure frequently is hurting the pace of delivering features.
We believe that in the current state of web development, falling behind on version updates is making development harder. Even if the Angular team is having LTS versions, the truth is that they will always prefer to work on their own latest codebase instead of going back to an old branch to look at an issue.
Lacking behind is also a symptom of other problems. If it takes a long time to upgrade Angular versions, it will also mean it will take long to introduce other changes to the codebase, whether it’s infrastructure, new features or bug fixes.
So the ability to upgrade versions quickly has 3 major factors:
- Our own team structure, setup and ways of working
- The Angular library itself and the way the Angular team develops it
- Stick to the standards — don’t try and reinvent the wheel
We think that in the last few years these factors improved a lot and keep on improving, so we wanted to share the path we went through till now and our future plans in order to help others improve their development flows.
Getting better at updates
Our first ever update from Angular 2 to Angular 4 was a massive job but over time we got better and also the people at the Angular team certainly helped out by making the updates easier.
- Angular 2 to 4 — About a month of work
Our first big upgrade ever, which raised a lot of questions. What will happen? What will we exactly upgrade? How are we going to organize the upgrade? Which teams will or will not upgrade? Who’s going to ensure everything keeps working? When does it go live? Will it harm feature development?
All questions which were answered along the way. From our five development teams at the time we created a separate team to do the upgrade and move our code base to separate repositories.
- Angular 4 to 5 — A sprint of work (our sprints are 2 weeks)
With the upgrade to Angular 5 we also moved our component library to the just released stable version of Angular Material. Our component library is our own custom library built on top of Material.
One of the things we had to do was update the md-prefixes to mat-prefixes, anyone remembers doing this?
Also some of our unit test cases were breaking because of the move. We added some functionality to the Material dialog which was not in the actual dialog module at the time. During the upgrade we looked sharply if we could remove the code or if we had to repair the broken unit tests. In the end we ended up removing some code and made sure we were using the APIs provided by Material. In the ends this means less code for us to maintain which in our opinion is always the better option.
- Angular 5 to 6 — A sprint of work
During this upgrade the biggest thing for our team was to make sure we imported the right RxJS operators and so on. RxJS-compat really helped us out to gradually get this move done. Also with this upgrade we had a lot of breaking test cases which was some manual labor to get fixed but in the end it was all dandy. During this upgrade we really saw that the experience we gained as a team in doing big upgrades made it easier to do this one.
- Angular 6 to 7 — A day of work, and a very happy team.
The smallest update we did to date. When the Angular team announced the release and that it would take most teams less than 15 minutes to upgrade the codebase we could not believe it!
Well that actually was very true! We had a few small changes here and there and most of the time for this upgrade came down to running our automated test suite and make sure all functionality would work when we merged the upgraded modules.
So what made us upgrade faster?
State of mind
This is the most important thing. The understanding that upgrading frequently is actually important and the ability to dedicate time for it as part of the development cycle.
Being Agile doesn’t mean only talking to each other while standing up every morning….
Agile at its core means a very simple thing — the ability to change things fast.
All the rest is about that goal. if you can’t change things fast, including Angular versions, you are not Agile, no matter what techniques your team is pulling off.
We try to be separate modules, repositories and try to create an infrastructure to give each developer as little responsibility as possible. But in the end, we all have to understand that we are in this together.
Those type of architectures and structures, which usually rely on manual tools to do the separation (separate git repositories for example) makes it extremely difficult to introduce a change that does affect everyone, for example an Angular version that affects the whole app and all the teams building it. Again, remind yourself that separating git repositories is completely manual while having all the code in the same repo let’s you create automated rules over the code and its structure by import paths for example.
By creating an architecture that uses more automated tools to track the code itself instead of the folders and repositories its in, you make the developers be aware of the whole app, and a change with cross effects becomes more visible and easy.
Read more about our monorepo setup below.
From Custom Webpack to NG CLI setup
During our upgrade from Angular 2 to 4 we decided to adopt the Angular CLI setup to get all the benefits from the CLI. We did this by creating a brand new CLI project from scratch and moving our old Webpack setup code into this.
We still had a lot of custom scripts in order to separate the teams from each other.
When we moved the separate teams code into a single codebase and moved into the direction of treating all whole codebase as one single Angular app, the setup became even more simple, while giving us more time to optimize builds and get the performance benefits from new versions of the CLI instead of investing in custom code and lagging behind.
Our project is constantly going through changes. When we started we were in a single repository. As we were growing we split these repositories into multiple so teams could build Angular modules on their own. These modules were published as NPM packages and bundled together on build time.
We became separated, but it also created a lot of difficulties.
First, releasing a new version became a big pain. bundling all the modules together and only then finding out the integration issues ment we were finding the bugs only before we needed to release.
Same goes for updating dependencies. you update a dependency in one place, then testing it across the whole application became a huge task.
Separating code is the basic instinct of a developer. Before you separate, ask yourself why are you separating and if you can find an automated solution for it, before separating the code by a manual decision.
If your build is slow, try to fix the tools and not harm your development flows.
If you want to protect better certain places in the code from change, create a smart PR reviewers script instead of hurting your development flow.
So after a while we decided to move back to a monorepo setup. We are doing this gradually by using git-submodules. Over time all these git-submodules became folders in the actual monorepo. Git-submodules was a nice intermediate solution, but it comes with its own problems.
We are now in the process of simple removing those submodules and having to a single repository. That is another reason why we think that the Angular 8 upgrade will be even easier for us without the need to worry about keeping git-submodules up to date.
At the end of the day, we are shipping one webapp. the closer we make that webapp’s architecture to a standard Angular app, and minimizing the custom code and scripts, the less maintenance we would need to do, no matter how large the codebase.
The Angular library itself
Of course a huge factor of the ease of upgrades came from the Angular team themselves.
From release to release, the amount of breaking changes is minimizing and the tools that the Angular teams provide to help with those upgrades become better and better!
This is a very handy website, created by the Angular team, which shows all breaking changes for small/medium/big apps. https://update.angular.io
NG CLI Update
Once we moved to the standard Angular CLI, the Angular team introduced the ng-update command, which really helps and automates a lot of the changes needed when upgrading an Angular version.
Since introduced, we see the tool becomes better and more useful with time.
One last thing. The Angular team of course is encouraging the community to keep up to date with the latest versions.
That is because it makes their jobs easier by needing to do less support for older versions and getting earlier feedback from the community on the latest changes.
A great tool that helps keep dependencies up to date is RenovateBot.
We also had an idea that the Angular team can lead by example. The Angular libraries themselves are using many npm dependencies.
We think it might be a good idea for the Angular team to add a tool like RenovateBot to the libraries themselves, so that they could keep all their dependencies up to date and push all of our community forward. Maybe even include it as an option when generating an app with the Angular CLI so people will learn about that and could get that option out of the box.
A thank you note
A lot of those transitions of the state of mind, were pushed by Uri Goldshtein, the founder of The Guild, which dedicated the time and patience to talk in length with many engineers, architects, project managers and the biggest and smartest opponents of those transitions in order to push for this type of architecture.
But talking is not enough, Uri and his team are helping us a lot with the work itself by refactoring and cleaning a lot of the code and helping make those transition ideas into a reality.
Even though it seems like the transition from Angular 7 to Angular 8 would be a bigger change (thanks to Ivy), we are still confident that we will upgrade our apps faster than ever.
By that time we will move to the monorepo completely and with time, we’ve built trust in the Angular team on how they ship new versions and how they keep improving upgrade tools.
A community that moves faster together, is a better community.
If you have any questions, please reach out to me on Twitter (@martyganz) or in the comments right below!
Thanks to Uri Goldshtein, Ugur Korfali, Anthony Moendir and all of the awesome people from BlueWeb involved in this article.