This series of blog posts which I have converted from Youtube videos. I personally have really enjoyed these videos so in order to textually document them, these are essentially some screenshots and rough notes organised.
This particular post is based on the awesome James Henry NGVikings 2018 talk. It can be found on the link below:https://www.youtube.com/watch?v=bMkKz8AedHc
NX stands for NRWL Extensions, it is an enterprise tool, completely open source.
Why does NX exist?
In order to understand why NX exists, we will be talking about Collaboration and how it is impacted by Code Storage and Code Structure. What we do, is write code, which is interpreted by machines but read by human beings. So, to write code that is easily understood even over a long period of times, we have to collaborate with people in our teams. For collaboration to be effective, there are certain things that we need to keep in mind related to code storage and code structure. While these aspects do not necessarily make your collaborations mind-blowing, they do make it easier to have a good collaboration.
Some of the requirements of enterprise (or basically any) teams are:
- UX Consistency across applications
- De-duplication of effort
- Agile and adaptable applications
We want to be able to achieve all the above-stated objectives, while also maintaining the autonomous power of the teams, allowing them to be independent units and letting the developers feel that the impact in these teams. This allows the individuals to grow personally and professionally, and not make them feel like an insignificant part of something a whole lot bigger.
In Monorepo, there is a single repository which contains every single piece of code written, storing the data. So, this does not require us to independently release or coordinate anything.
In Polyrepo, our code gets split up into many parts and saved in different repositories. And when a complete unit is required to be released to the clients/users, the repositories – that are separately stored – are then wired together for deployment purposes.
In Monolith, everything will be blended together, however, this can cause problems with abstractions leaking because even something from within the hierarchy can be imported quite easily as everything is mixed together.
In Modular, the data is split out by de coupled reusable units, which allows boundaries to be placed around things so that they do not mix. Boundaries allow the testing of different parts in isolation.
Monolith and Modular are extreme ends of structural organization, Code Structure.
One thing to keep in mind would be, that Monolith and Monorepo do not necessarily always go hand in hand because Monolith can exist within a Monorepo and a Polyrepo as well.
Monolithic Polyrepos are the enemy of Collaboration
- Polyrepos are good at autonomy
- Poly repos can work well with proper tooling and ideal conditions
Even though Polyrepos are easily manageable in isolation, but it can get quite difficult to wire them together in an effective way.
Why inconsistent implementations?
- Each application lives in its own repository
- Design spec was ambiguous
- To create a common repository would take significant work
o Setting up build, test, CI
o Managing distribution of the library
o Awkward dev lifecycle of developing in two repositories when modifying components.
Polyrepos makes it a lot easier to mess up the application than to do the right things. So, in its stead, Monorepo could be used.
Monorepos allows the UX consistency because of everything being in the same space.
Why duplicate implementation?
- To create a repository for the Ticket Service would take insignificant work
o Setting up build, test, CI
o Managing distribution of the library
o Awkward dev lifecycle of developing in two repositories when changing the service
In this implementation, if you, for example, built a test for a service which has been isolated and separately deployed. Unit testing for that library might pass, however, when you try to integrate it, another version of the library has been created and then when you import it to your application, it breaks all of the tests inside the app.
However, in Monorepos, the duplication is not there in the first place because it is only implemented once for all the consumers.
There is no need to separately build it, release it, deploy it because it has already been built as part of the rest of the repository. So, when we run the tests for the repository, we are actually testing the integration of the smaller part along with the whole picture. If any changes are made to the ticket service of the clients, tests are not only for the isolation testing but also to check that the application has not broken.
What does NX provide?
This is the part where NX enters, it brings the Monorepo and Modularity to the storage and structure of the code, built with Angular CLI. NX is actually a very thin layer on top of the Angular CLI, schematics are leveraged to provide more power on top of the existing Angular CLI application. NX can be used without ever touching any of its custom components. All of the original CLI commands of Angular still work, NX is just adding to the top of the CLI with extra stuff.
The main concern of NX is how you set up your repository and how you compile it. Since NX is just a thin layer over original Angular CLI means that it is aligned with the official solution for the management of angular repository.
The key difference that can be seen between a regular Angular CLI and with NX workspace is that NX workspace contains multiple applications and multiple libraries in a place where standard Angular CLI would just have a source. You may or may not want or have multiple applications, but NX workspace provide you an option of having multiple applications should you choose to have them.
NX contains an understanding of multiple application contained in Monorepo and libraries are also here to give the users an experience that is best of both worlds. This allows us to bring in the encapsulated unit inside of an application but there is no need to store it separately. Through this way, we can access the benefits of modular approach while implementing Monorepo.
- Applications are independently deployable build targets.
- Libraries are encapsulated collections of code with explicit APIs
If you are already a user of NX, the best method of approach would be to consider your application as a platform where all you have to do is to wire the code together. Nothing is actually living in the applications, but a space for wiring things together and then build and deploy the libraries, where essentially all of your code is contained. A common pattern of its working is to have a library that has name matching to that of the application, and then it would be containing the majority of the things normally found in a standard angular application.
The code is specific to one application, not necessarily reusable because that is not the goal here. However, the stuff that is reusable is stored in a separate library in UI library.
Another important factor is explicit APIs, and how to design it so that the code can be split without being at the risk of adding a new application and then importing something from within another library because it is convenient as the code is just right there.
Features like consistency and reusability can be accessed easily by having the code together.
What about leaking implementation details of libraries?
Each library exports its public API via index.ts
Internally the library can export whatever it needs to for testing and internal sharing.
So, another thing that NX provides are some custom TS lint rules to make sure that you do not do anything like doing a deep import to get to an NG module out of the library. It should be specified on the public API of your library. Rather than having to go through the process of deploying something, building it and then putting it on a separate repository to bring it into our project application, we end up in similar kind of situation but this time all in the context of our repository. So, at this point, it is just easy to split things up into libraries.
What else does NX give me?
- Idiomatic code with NRWL best practices
- Extra code generation applications, libraries and NGRX state management and tests
- Advanced linting and code formatting
- Scripts to run only affected by builds and tests in CI environments
- Runtime and testing helpers for NGRX data persistence
- And more!
As with many software applications, continuous updates are bringing you new features, with new upgrades of Angular you will also have the benefit of getting updated NX versions.