Conf42 DevOps 2025 - Online

- premiere 5PM GMT

From Patchwork to Picasso: Refactoring 80+ Angular projects and what went wrong

Video size:

Abstract

Ever feel like your codebase is more Frankenstein’s Monster than a masterpiece? Juggling 180+ Angular projects can lead to inconsistencies, inefficiencies, and pure chaos. But what if there was a way to transform that patchwork into a beautiful, unified solution? Find out how in the talk.

Summary

Transcript

This transcript was autogenerated. To make changes, submit a PR.
Hello everyone. How's it going today? This is Con 42 and my name is Muhammad Ahsan Ayaz. I'm a Google developer expert in Angular and a software architect working at Scania. I'm also an author of two worldwide published books, namely The Angular Cookbook, and you can find me on my socials. Now today I'm going to actually talk about something special, something that's close to my heart. The topic is from Patchwork to Picasso, managing or refactoring 150 plus web projects and what we went wrong. You're gonna hear some stories. You're gonna also learn quite a lot of things. So if you want to follow on my socials, you can see them at the bottom. And I want you to take just a second to take this picture from your camera. This allows you to give feedback directly to me about the talk and anything that I can improve. So thank you in advance. Now, I want to ask you to UI question. A very existential question, if I may dare to say that. What if you had cats, about 150 of them, and you tried to walk them at the same time around your street? What would happen? Can you imagine what that would feel like? And this picture actually is a depiction of what it could feel like. And that is exactly how I felt when I was working on my second edition of the angular cookbook, because I had more than 150 projects. to work with. And that's what we are going to talk about in the next about half an hour. Who am I? I already introduced myself a bit. I'm an author of two worldwide published books. I'm also working as a software architect at Scania and I'm a GDE in Angular. I'm also maintainer of a lot of open source projects as well. But one of the most famous ones is NGX device detector, which is being used by more than 5, 000 projects on GitHub. I'm also someone who's recognized in the developers community as an educator. And this is one of the awards that I got recently at JS Pullin. And I've also been featured by Google when I was working with them on this AI campaign for Google Gemini. Let me take you back to 2019. That's when Pact, which is one of the publishers out there for books, reached out to me and they wanted me to work on a video course. And that was on Ionic. So I hope A few of you know what Ionic is. And at first I was really happy. I was like, okay, this is super cool because I was fascinated by all these, you know, thought leaders and course creators out there. And I wanted to do that myself as well. But there were some challenges. I used to live in Pakistan back then with my family and Even though it is a preferred way of living there, it comes with some challenges when you're living with your family, which means that each couple has one room to it. When I used to record, it was usually at night when everyone was sleeping and that actually came with some challenges. So the first challenge was I was newly married and I had very less furniture in my room, which means that whenever I was trying to record something and even if there was a slight echo, that would be recorded in the microphone and I would have to eventually re record it. So even the slightest sound of my wife sort of moving on the bed would just make me angry and I was like, ah, can you please not breathe? And then I would basically go out in the living room and I would try to record there, but that also came with some challenges. For example, or so I would hear all these sounds and that would make me. Yeah, as you can imagine. Fortunately, I moved to Sweden and you can see how happy I was. But once I published the video course, I thought I would earn a lot of money and I started dreaming about it. But that was exactly the same time when React Native came out and that basically kicked Ionic away. So the course actually did not perform really well. Then in 2020, PAC reached out to me again and they were like, can you write a book for us? And I was like, okay, I can do that. So long story short, I took over 10 months and wrote this Angular cookbook with over 80 plus projects and we sold over 2000 copies of this. So this was really a success. After that in late 2022, PAG reached out again and they were like, can you work on the second edition of the book? And I was like, okay. We can do that. And at first I thought it would be super easy because I just had to migrate or update what has happened in Angular. And this is just a second edition, right? But when I looked at the code base, I knew I was in trouble because there were more than 150 projects all staring at me and they were waiting to be updated from Angular version 12 to Angular version 16. Now you may ask why, and that is because Angular has a predictable release frequency. So every six months there is a major release and there are about one to three minor patches as well during the six months time. So for me, updating 150 projects basically seemed like this. I knew it was going to be super, super slow. So what did I do then? I basically found out this really cool tool called NX, which is the new cool way of managing monorepositories for your particular projects, especially if you have a lot of applications and or libraries. So looking at that, I decided to have one monorepository with two NX workspaces. So I had one GitHub repo that had two NX workspaces in that one for start and one for final because my book is basically in the form of a cookbook. So you have a Problem statement, you follow the recipe and then you have the solution for it. This is how the architecture looked like. So if you look at here, we have the GitHub repository that has two folders, start and final. And then in both of them, we have these chapter folders and inside we have a folder for each particular project or what we call a recipe. Let me ask you a question. Do you like ui ux or do you love ui ux? I think a few of you say yes. Then how many of you really advocate for ui ux? That means you go to designers, talk about that, or your product managers, et cetera. And then I want to ask you, how many of you actually advocate for a great developer experience? Because what I wanted for my audience or my readers. was a great developer experience, but not just for them, but for also myself as well, because I was about to migrate 150 plus projects. So with the current NX structure, this is what I would get. I would get a GitHub repository with these folders and I had to proceed with this. Now, by default, when I was designing this, any recipe would have to work this way. The reader would have to first go and do CD start. Then they would have to run NX. And then this whole name. Now, remember, whenever we are structuring our folders or our applications in Angular or in NX, whenever we try to give them a hierarchy of folder, that becomes the name of the project itself. So if I wanted something like CC on changes, inside the chapter one folder, then the name of that project becomes this, which is huge. And I think that's not really easy to remember. So for running a recipe in the start folder, they would have to run this. Similarly, they could also run other recipes like this as well. Now, as you know, as developers, we want to be dry, not exactly this, but I think you'll get my point. But also remember, we need a really good DX. I'm going to actually come back to this term again, which is developer experience. So my first goal was how do I make it so that the name of the project is not as long. So the first goal was actually to run this npm run serve and this command, which means that I don't want to cd. into the start or the final folder. I could just run either this or run the same command, but with additional parameter called final from the project's root. So nobody has to cd into it. And this was pretty simple. But the second goal was to avoid even having the chapter name when I'm running this command. And you may ask why that's because each recipe is unique. So in my entire code repository in the start folder, there is no duplicate recipe. Similarly in the final folder, All the recipes are unique. So I should be able to just use the recipe name instead of specifying the chapter. Now, the first goal was really simple. As I mentioned, I just moved to the CD step and the command into a script file. And I moved that script or use that script in my packages. And with this change, I could actually run this command pretty easily. So I could run this for the start folder and this one for the final folder, just by using npm run surf. Now I had to focus on the second task, which was how do I remove this change? chapter name from running the command and can just use the recipe name in general. Now I want to emphasize that at this point, I'm actually migrating these projects. So I'm actually creating those projects one by one, and I'm migrating them from separate 150 plus projects to two monorepositories start and final. Now, when I was doing that, I had three options. One, when I'm actually creating a project, I could exclude the chapter name from it. before the project is created. The second option was I create the project and then rename after it has been created. So just going into the files automatically somehow, and then renaming it, and the third option was just give up and start writing a PHP book, maybe that's easier, but I did not go for this. I choose the second approach, which means creating the project and then renaming it. Why? I actually don't know. At that particular time, I had no idea what I was doing and that's perfectly fine. You get into these issues as developers always when you don't know something and you know that. later on. Now, coming back to the problem at hand, I wanted to use this particular command npm run serve and just the recipe name. So keep that in mind. So for this particular situation, I created my own plugin using the narwhal NX plugin package. It's quite possible that the package name has changed now since everything moved to at NX now, but I used NX's plugin package to create my own plugin. Again, the question is why? Because I wanted to do. this in the steps. So let's have a look at how I was creating the application for my book. Back then I was actually trying to do this. I would actually go to a start folder and I would create a new project. Since I'm migrating them one by one, I would actually go and do NPM NX generate, create an Angular application for me, and then I would give that the path. So the chapter name or the chapter folder, and then the recipe folder, just like this, this basically generates with the app name. this one. And as we discussed, that is too much to remember. The chapter name and the recipe name, not super easy. Now, the plugin I created actually had two counterparts. One is the NX generators and the second is the NX executors. And that is what I'm trying to focus on this talk to actually tell you. So, the first part, that is the generator, actually creates the application. So instead of me going into the folder and running the command, it actually uses a generator to generate the application. And during the generation process, it adds the executor into the project JSON. So take it like two steps. So in the first step, we create the app. In the second step, we rename the project. That's the idea. So for that, the code looks something like this. When I generate my project, there's a function that I call and that essentially looks like this. It takes the package JSON of the project and then adds this rename executor inside that from my plugin. Then it basically becomes something like this. So let's say the recipe was This NG on changes, then I actually have these parameters like chapter number and then the app name. Since the actual name that we are targeting right now contains both the chapter number or the chapter folder and the recipe name, I can actually use this to use some regex to rename easily. Now, the second step. is to run the executor. So first step, we created the generator that creates the application. Second step, the executor actually goes into the project, JSON, and then it fetches out this information. What is the chapter number? And what is the recipe name? When it looks at that particular situation, it actually then renames this right here in this function. So we're not going to go too deep into this, but the idea is actually to rename using the executor's information. So if I Summarize this. This is my whole process. I had to just run this command to create a new project, which is super easy for me. I just run npm run create. I give the number of the chapter. I give the recipes name and the title I want to show in the header. So that means that runs a couple of things. First, it starts with a batch script. It runs the generator, which generates the application. Then it runs the executor that goes and renames the application. That's easy peasy. So. This is what happens when we run npm run create, this runs the packages in the script, which in turn runs the bash script. This is the chapter number. As I mentioned, this is the app name, and this is the title to show in the header. So this is pretty simplified version of what happens. So it takes out the app name, the app title, and all of these things as the argument or the positional arguments. And then it runs all of this. So here you can see that it runs the rename executor before that it runs the generation of the application for me. Awesome. Which means that if I was able. To run this correctly, all I had to do was run this NPM run serve CC engine on changes because the name already has been changed and the app has been renamed now. Great. Now, do you remember what our goal was? It was actually a great developer experience. And this was the time when I actually felt like I was over the moon because I actually conquered one of my biggest fears. And that was working with Angular schematics, which is what we use. to work with, NX generators and executors because it scripts everything and then does it automatically on the file system. As I felt enlightened, actually a new problem knocked my door and that was not great. Have you heard this term called consistency? Well, I actually wanted my entire project to be consistent in terms of UI UX and I wanted the same structure and user experience for all of my applications. So the idea was to have the same header across all the projects, which means. It could look something like this. So we would have the header at the top. So if we dissect it, it's the header having the title of the application, the Angular logo and information burden. And then this content is the dynamic content, which is different for every application. Now, I thought I could do the following using my generator. So my generator is already creating new applications, which means that if I went inside my generator and I look at the template, so one of them was index HTML. And the other one was app component HTML. So for all the things related to the consistent fonts across all applications and the icons, which is like material icons, which I can basically load from the CDN, I could actually work on index HTML. And for the applications architecture, I could actually use the app component HTML. To have the header and then the placeholder for dynamic content of the applications. So this is what I did. I actually modified the index HTML to include material icons, the font that I basically use, which is Nonito and everything that I needed on the index HTML level, then in the app component HTML, I actually had the toolbar and then this main element, which would have the dynamic content different for every application. And here you can see that we do have the info button. We also have the title here. And we also have the Angular logo as an SVG. Now we have discussed only the HTML part or the templates. But what about the biggest fear of web developers, which is CSS? How do I ensure that the styles across the applications are consistent and they're easy to update as well? That's actually when I created my own NX library within the NX workspace. So I created a library named NGCB UI. And this is actually within my plugins package repository or monorepository. So now I have this global SCSS, which contains all of my styles. I package it so I can use that. in my other workspaces like start and final. And I also ensure that this is included. So that means that now when I'm creating a new application, not only I'm creating an app with this consistent, structure with HTML for index HTML and app component HTML, but I'm also including this global SCSS sneakily into both those projects. And the beauty of this is that I'm not doing this for one 50 plus projects. I only have to do this for two projects. two workspaces. The start workspace and the final workspace. I don't have to do it for every project because I only have two NX workspaces. This is the beauty of automation so far. So when we looked at the result, It was beautiful. We had a header, we had the logo right here, we had the info button, and this was consistent for all of my applications. Having this dynamic container here, which can have different content, of course. And just as I thought everything was sunshine and butterflies, something big happened. Something crazy. Can you guess? I'm going to give you some seconds to think. All right, maybe you guessed it. Maybe you didn't. Angular actually changed their logo and they went from a red logo to this cool logo. And while this is so pleasing to the eye, this is so modern, I actually really liked it. But this caused And that was, I was left with 150 plus Angular projects still now, even with NX workspaces with hard coded SVGs that I had in my, App component html and that was not super cool So if you remember we had this app component html which had a toolbar the dynamic content But this hard coded image now, I have 150 projects having this in their code base And that was not good. First of all I compose myself like a good developer. I thought of analyzing what's happening right now and started thinking of a solution. So the first thing that came to my mind was to go from this, which is the current state of the app component HTML to something like this. Instead of having a hard coded logo, I could create a component in my NX library and I could use the same component throughout all of my application. And this file right now, which is app component HTML is part of the So if you think that sounds good and this could solve the issue, You're wrong. And that is because we are talking about the code of a generator. The generator only works when we are creating the applications. I already have my 150 plus projects already, which have that code. So having changed the generator's code or the template doesn't really work right now. I need something else. Because I have 150 projects, my 150 plus cats having the old logo, which nobody likes anymore. So I started thinking about the solution and I had some questions. My main questions were, how do geniuses at Angular and NX solve such issues of a workspace wide, Migration or change. How can I have a graceful fallback if I'm trying to do this automatically across my GitHub repository, how do I know if something breaks and, you know, revert my changes and not, you know, come in middle of a situation, which is half baked, so to say. And then how do I ensure that I don't have to think about the same problem again in the future? So first I created this header component inside my library is still, because still it's a good idea. Do not have the hard coded, header everywhere. And we could have this from a library. So if we needed to change anything in the header, we could just update the library and then all the projects start using that. So that's what I did first. Secondly, I use something called NX migrations. And trust me, this is really, really cool. Beauty of migration is that it allows us to run generators after the applications have been created. And this can run to the whole workspace. So to say, the beauty of this is that I can also specify which version of my plugin that I'm using right now in a start and final will trigger this migration. So I can also, versionize it. So to say, and that is. Really, really nice. So the goal for my migration was to have this replace app toolbar run in both the start and final folder. So that means two steps. And when I do these two steps, I should have migrated my whole code base, all the projects. And this is what the migration looks like. So if I show you the code base, it basically goes inside my application and looks at all the projects. Now, some of the Angular projects are module based, some are standalone. So essentially it goes, it finds the header or the title, it extracts it, and then it replaces it right here with the new toolbar. And if you look at the new toolbar, it is essentially this, the ngcbui header, just like we discussed before. And once that does it, it also makes sure that this particular component is also imported in the TypeScript file as well. Because you need that. For the standalone components. And if you're using a module based application, then you need to import this or declare this in the ng module of your application as well. So that was pretty nice. And if we actually look at what happened after I ran these migration, let me show you, this is the commit that actually was done after the migration. So this is replacing all the headers. in the start folder. And if I close the migration files, I also want to show you what happened in each project. So here you can see that this whole toolbar was replaced by API UI header. Then in the TypeScript file, we go and import this automatically and add that to the imports. And this is the same for all the recipes. So this toolbar had the same result, just like this, this one. And this one, and this one, you'll see the repeating sort of pattern for all of this. So this basically ran across all of my projects within the start folder. And then I did the same for the final folder as well. And once I ran the migration on both the folders, things were like muska as we say in Pakistan, which means like buttery smooth. And I want to show you the final result now. So if I. show you the demo. This is what it looks like. You can see that all the applications have a header right now, have this logo, and then this content is dynamic. So I can show you this really nice example in which I have, for example, folders moving right here. And this example actually shows how to lazily load different components, even on a single page. So here you can see that a lot of these projects or a lot of these components are lazily being loaded. So all of my recipes in my Angular cookbook, right now have the same consistent layout across all of the projects. And when I was actually able to achieve all of that, I felt like a self proclaimed NX expert. So if I summarize, what we have talked about is cats are possum, managing 150 plus projects is completely possible and no solution is perfect because I started with something, I failed, I found out the issue with that, and then I re evaluated and improved the solution and we as developers. should be easy or should be, you know, not hesitant to do so. And it's also never too late to learn something new. As soon as the opportunity presents itself, I think we should just grab it. Because when I started with migration, I did not know about Angular schematics or all of these things like NX plugins, generators, executors. But by the end of all of this, I actually know a lot that I can share now. So that's pretty much it. I would highly encourage if you can provide me the feedback with that. QR code that you can see here. And also, if you want to take your skills to the next level, and if you just want to explore all these projects, cool projects that I've built with the angular cookbook, check out the angular cookbook, second edition, or the latest edition, whatever is out there at the ng cookbook. com. And with that said, I want to thank con 42 for having me this time as always. Happy coding y'all. I'm going to see you next time.
...

Muhammad Ahsan Ayaz

Software Architect @ Scania Group

Muhammad Ahsan Ayaz's LinkedIn account Muhammad Ahsan Ayaz's twitter account



Join the community!

Learn for free, join the best tech learning community for a price of a pumpkin latte.

Annual
Monthly
Newsletter
$ 0 /mo

Event notifications, weekly newsletter

Delayed access to all content

Immediate access to Keynotes & Panels

Community
$ 8.34 /mo

Immediate access to all content

Courses, quizes & certificates

Community chats

Join the community (7 day free trial)