Unit Testing

Testing is essential for long term maintainability. We’re not perfect testers at Versett, but we believe that if we write modular chunks of testable code, it will age more gracefully than if we didn’t. In our initial Angular projects we made the mistake of not testing, which led to regressions making their way into production on more than one occasion. We now ensure all our code is thoroughly tested and you can find .spec.ts files throughout our codebase.

Angular was built to be tested. It includes a large suite of testing tools and has dependency injection baked into the core of the framework. Dependency injection makes mocking out services, pipes, directives, and components incredibly easy. Keeping your components tiny, dependency injection, and mocking helps to ensure that we precisely test small chunks of code for more useful test cases. The Angular testing guide is a great place to start for writing your first test.

Learn about RxJS operators by playing with marbles. Image: rxmarbles.com

RxJS

The Angular team jumped in head first with RxJS and reactive programming. Embracing RxJS can improve code maintainability dramatically by allowing manipulation of not only data, but how data is retrieved. If you’re one of the many struggling with RxJS, observables, or subscriptions, here are a few tips:

Use the async pipe and avoid using .subscribe().

The biggest mistake we made when dealing with observables was trying to subscribe to observables in order to extract the data. Subscribing led quickly to coupling, as well as a very confusing flow of variables throughout our components and templates. The async pipe allows data to be streamed directly into a component, which lets us get rid of those messy subscriptions. If we find an instance of subscribe() during a code review, we will try to find a way to restructure our code without the subscription because it often leads to cleaner and more understandable components.

There are lots of reasonable cases for using subscribe(), but we believe that overuse is considered a bad code smell.

Tiny components allows the async pipe to do the heavy lifting.

RxJS operators allow us to manipulate streams to contain only the data we need for our components. Rather than having to capture and manipulate our internal state every time it changes with ngOnChanges(), formatting data within a stream prevents us from having to deal with change detection and passes the data directly where we need it to be.

Only deal with observables in containers, never in presentational components.

Following the pattern of using presentational and container components, we find that we rarely need to subscribe to a stream in our containers and never need access to the observables in presentational components. The separation of streams and data is a very effective way to remove coupling between the presentational and container components.

Give ngrx a shot.

I’m skipping ahead to state management, but ngrx ties directly into RxJS and we were forced to learn the principles of RxJS in order to effectively use ngrx stores. Sometimes the best way to learn is by jumping into the deep end.

There’s only one response from the server, why would we treat it as a stream?

Our whole team disliked observables when we started with Angular, claiming that promises made more sense for ajax requests. It was only after we had added ngrx to our projects and embraced the pattern that we understood the original motivations of the Angular team, and how RxJS could help keep our code maintainable. If you don’t believe me, Christoph Burgdorf has an article about observables which explains their benefits, better than I ever could.

Unidirectional data flow, the key concept of Flux. Image: code-cartoons.com

State Management

Knowing when to add state management is a tricky problem to solve. Often using component state is enough, but knowing when to add it to a growing application can be hard to identify. While we didn’t realize it at the time, the root of many of our problems was a lack of state management early on in our development cycle.

If you’re new to Flux-style state management, you can check out a guide on getting started in Flux. There are several flavours of Flux-inspired tools such as Redux, MobX, and Relay, but for our projects, we opt for ngrx. Ngrx is a Redux inspired, Angular focused, and RxJS-embracing state management library. Backed by several of the Angular core team members, ngrx does more than just manage state: they also have libraries for managing side effects of actions, integrations with the router, and even handling web notifications. You can read an introductory video for ngrx for a more thorough understanding of what makes it different.

Further reading