Adventures in Angular2
The growing pains of learning a maturing framework.
At Versett, we are always looking for new and exciting opportunities to expand our internal tool belt. We’ve been working with American Express Global Business Travel to streamline the travel experience for their clients, while providing the best user experience possible. Our dev team was tasked with developing the front end of a web application that allows travellers to view a live itinerary of their current trip, as well as access information for past and upcoming trips. With the client we decided to use new hotness that is Angular2. When we began the project, Ng2 was at version 2.0.0-rc.2 and at the time of writing it sits at 2.3.1. We’ve been front and centre for breaking changes and our knowledge has certainly grown with the evolving framework.
It’s been a wild ride, to say the least. Here’s what we’ve learned so far.
Typescript is your friend
Componentize all the things
Angular.js, the predecessor to Ng2, was entirely based around controllers and $scope. These concepts were thrown out the window in Ng2 and replaced with components and directives. Directives allow you to extend HTML attributes, and components are essentially directives with a template. It was a bit of a learning curve to define a pattern in which to structure our application’s components, but we eventually landed on a composition of smart/dumb components.
By utilizing the concepts of containers (smart) and their inner components (dumb) we were able to divide complex features into small, de-coupled functional units.
Overall, we really enjoyed the component-based architecture of Ng2 and the fact that we were able to use HTML as our template language was a huge bonus for the traditionalists on the team.
State management is a bit of a nightmare
Ng2 lacks a robust state management mechanism out of the box. Because of this, we ended up with a large number of ‘services’ that acted as a Frankenstein mash-up of data store and traditional service logic. Our state management relies heavily on tightly coupled events to retrieve and modify data. Once we began implementing a custom content management system we quickly felt the pains associated with the complicated task of maintaining state in a single page application.
@ngrx/store to the rescue! …For our next application, anyway. @ngrx/store is a reactive state management library for Angular applications that provides a unidirectional data store powered by RxJS. Upon its discovery, we quickly understood how beneficial a tool like this could be for complex applications with lots of data input from users. Although introducing it into the current application was out of the question, we quickly implemented the state management solution as a major component of our internal Ng2 tool belt and will make use of it in all future applications. Once again, the learning curve to understand @ngrx/store events, reducers, and effects was daunting, but the team worked together to develop a collective understanding over numerous diagramming sessions.
Modules, Lazy Loading, and Dependency Injection — Oh My!
August’s 2.0.0 rc.5 release introduced the concept of NgModule. A module is at the top level of the component architecture of Ng2 and helps to define the components, services, and directives that are available in separate functional collections of code. By defining a module, you essentially tell the compiler which dependencies to make available and when. When we upgraded the application to rc.5, our entire application broke and we had to halt feature development until the entire app was modularized. Thankfully, the endeavour took significantly less time than initially anticipated and was far less of a chore than we expected. One of the obvious benefits to modularizing an application is the forced separation of functionality. At the time of this breaking change, we hadn’t yet begun to develop the custom CMS part of the application, but we quickly understood how the new NgModule concepts would benefit us when we did.
By allowing entire modules to be bundled together with their components and dependencies and defining them with lazy load capabilities, we were able to prevent large chunks of the application from being downloaded for users who would never make use of them.
Test Driven Development is tough
Shortly after beginning initial explorations for the application, we realized that generating tests in the Ng2 environment was very complicated. Generating mock services and working with TestBed tooling came with a significant learning curve and a bloated timeline. Given that the project was being developed in short 2 week agile sprints packed with requirements, we ended up abandoning unit testing altogether and relied solely on the end-to-end testing done at integration — much to the dismay of our newest dev team member!
Observables everywhere, but why?
One thing that we all agreed on early in the project is that observables in Ng2 make things a bit sloppy, specifically in relation to the HTTP module. Forcing HTTP responses to come in an observable stream lead us to write a custom wrapper around the HTTP module to aid in formatting the data, handling errors, and setting custom headers. Sometimes you just want a single chunk of data, and requiring a subscription to a data stream for these simple requests seemed like overkill. Perhaps there is a V// Alpha project in the works to make our HTTP wrapper more general so that it can be used by the entire community to solve some of the issues we faced. 🤔
In summary, our experience getting to know Angular2 was (mostly) positive. We really enjoyed the opinionated nature of the framework and the style-guide helped our team to align on best practices. Finding help in forums and in the ever-changing documentation was sometimes difficult, but the helpful enthusiasm of the community peppered with random rants from disgruntled devs made the hunt as helpful as it was entertaining. We built up a fairly robust build ecosystem using Webpack that we will utilize in future Ng2 projects. The project dev team tripled over the course of this project and learning a new framework together helped build up a solid foundation of trust and mutual respect as we made mistakes and learned from them together.