Step 1: Initial Setup

We begin here, with our first PR: https://github.com/laas-sh/laas-sh-app/pull/1/files.

To follow along, run these commands one by one:

Then open http://localhost:4200/ in your browser, you should see this:

The app doesn’t do much at this point, but there are quite a few things we bootstrap here.

First of all, it’s an Nx monorepo already, with a single Angular 7 app called “frontend” inside. Nx is great, it allows us to develop both frontend and backend in a single repository, which allows for easy typing information and functionality sharing. It also helps us to set up Jest and Cypress, and has a few more “Angular CLI power-ups” to improve development experience.

We add Prettier right away in our initial setup, because prettier is just so good. No need to worry about individual code style preferences, no holywars around spaces and brackets. The bigger the team, the more benefit you get from using Prettier. We customize it just a bit in .prettierrc, otherwise it’s just the default configuration:

We add a few routes in app-routing.module.ts:

Note how we are using an enum for Page – it’s always helpful for readability to make enums where a fixed set of pre-defined values needs to be handled. We start with only 3 pages: Home (default), Privacy Policy and Terms Of Service – this is a fixed set of pre-defined values, so a perfect candidate for an enum. It’s a great imrovement over a free-form string, because it provides type safety and documentation – by simply looking at the enum, we know what pages we have in the app, this way we are building our DSL, domain-specific language.

Page enum values are relative page urls – by encapsulating this information in the enum we are also following the DRY principle – arguably, the most important principle of software development. If we want to change the url in the future, we won’t have to touch multiple files, the actual url is only found in a single place, right here in page.enum.ts:

We are building a Bitcoin app, Bitcoin is borderless, so we will need multi-lingual support. We add a dropdown for language selection in our footer.component.html:

It’s a fake right now, but we will implement this soon in an upcoming Pull Request. Note that we are using Material Design in this project, it’s a natural choice for an Angular app that works great on mobile as well as the web.

There’s a bit of interactivity already going on in the header:

This is again a fake, but not a complete fake: we introduce LoginService that exposes login and logout methods as well as Observable user$. Note how all of our components use ChangeDetectionStrategy.OnPush – there’s no reason to use default change detection strategy, using observables with async pipe is straightforward, and not using it is very expensive in terms of app performance, plus it’s harder to reason about. When everything is streamed asynchronously via observables, things are simple and fast. Here’s what LoginService looks like:

This is a nice little pattern we’re gonna use a lot – a service that exposes observables and methods to manipulate the observables. The view components consume the observables by using async pipe. The actual state is encapsulated in the service with a private BehaviorSubject, exposed publicly using _privateSubject.asObservable(). This pattern is called a Facade (when describing public API), and a Service with a Subject (when describing the internal implementation). Using NgRx is not an improvement over Service with a Subject in my experience, as it leads to more complex code that is harder to maintain and extend – but, by using Facade we can switch to using NgRx without having to modify any of the components, because from the point of view of the components, they will still consume the same API: call a method to affect the state and just subscribe to observables to get state changes streamed to you. The inside of the service can dispatch an action and expose an observable made from selectors if you choose to use NgRx, it wouldn’t matter on the outside, the public API of the Facade stays the same.

Here’s another place where we’re using this pattern – MiscService:

We are using Angular flex-layout here to expose isMobile$ observable – as user changes window size, we’re going to stream true or false through this observable to indicate whether or not we’re on mobile phone sized screen. This is going to be useful for responsive design. Note how header layout changes for different page width:

This is enabled by isMobile$ observable in header.component.html:

We also introduce shared library, with a couple enums and interfaces, for example User interface in user.interface.ts:

Conclusion

We have set up a monorepo created with Nx, with a single Angular 7 app, one shared library, basic routing, responsive design based on Angular flex-layout and a fake login service to simulate authentication state. We set some code quality standards by installing Prettier, setting up TSLint and insisting on ChangeDetectionStrategy.OnPush. We are getting ready for multi-lingual support, for unit testing with Jest and end to end testing with Cypress. It’s all broad strokes just now, but the outline of the project hopefully begins to emerge.

Reach out to me with any questions and suggestions: @ALeschinsky on Twitter is probably the best way to contact me.

Cheers,
Andrew

Published by Andrew Leschinsky

Founder and tech lead. https://twitter.com/ALeschinsky