Software systems to innovate and grow

Building Mission Critical Applications with Angular

By Engineering Team June 25, 2018 10 mins read

This article was written as a result of past experiences building mission critical applications with Angular 2 and 4. All of the topics described here are common problems and solutions that I came up with when developing different types of applications.

Let’s get into it.

Bundlers

A web project should have a bundler, regardless of the technology stack being used. A bundler is in charge of wrapping your application code together with its resources into a minimized, zipped bundle so it can be easily deployed on a server.

There are many bundlers out there, the most widely used are Grunt, Gulp and Webpack. They each have a different approach to accomplish their job, but in my opinion, Webpack really stands out from the others.

The main difference is that Grunt and Gulp bundles only the javascript files and assets. While Webpack maintains a dependency tree by evaluating the import statements that allows you to only bundle resources and javascript files that your code is actually using. It also identifies pieces of code using code splitting and bundles chunks together for a more efficient result.

Angular CLI

The Angular team has created a tool called CLI that is the command line interface for Angular, a very powerful tool that goes way beyond the simple bundler or generator. Angular CLI makes it easy to create a new working application that follows some of Angular best practices, right out of the box.

CLI has commands to generate components, services, routes, classes and pipes, and it will also create test files for all of these.  It also provides ways to easily serve, test, lint and format your application locally while developing.

Finally, it has Webpack included and already pre-configured, so you can enjoy the benefits of Webpack without the struggle of diving into the configuration. Moreover its part of the official documentation.

Directory Structure – Folders

Angular CLI already produces a new project with a good suggested default layout, running the ng new command, but the problem appears in the src/app folder, where all the actual logic is going to be placed.
It looks something like this:

  • – app.module.ts
  • – app.component.ts
  • component1/
    • component1.component.ts
  • component2/
    • component2.component.ts
  • component3/
    • component3.component.ts

As the app grows you’ll start adding more components, services to share the logic between components and to fetch data from the server, models to model the data, pipes to filter the data, etc.  Suddenly you can come across something like this:

  • – app.module.ts
  • – app.component.ts
  • component1/
    • component1.component.ts
  • component2/
    • component2.component.ts
  • component10/
    • component10.component.ts
  • directives/
    • directive1.directive.ts
  • guards/
    • guard1.guard.ts
  • mocks/
    • mock1.mock.ts
    • mock2.mock.ts
    • mock10.mock.ts
  • pipes/
    • pipe1.pipe.ts
  • services/
    • service1.service.ts
    • service2.service.ts
    • service10.service.ts

The problem is that the components are mixed in with all of the other groups and it becomes very difficult to find anything in the main folder. The solution is to move all of the components into a component folder.

  • – app.module.ts
  • – app.component.ts
  • components/
    • component1/
      • component1.component.ts
    • component2/
      • component2.component.ts
    • component10/
      • component10.component.ts
  • directives/
  • guards/
  • mocks/
  • pipes/
  • services/

This is a simple solution but also a very helpful one.

When your application continues to grow you can come to a point where your app module is becoming too big and has a lot of responsibilities. When this happens you can split different features into modules to organize them in a better way.

Your app directory will look like this:

  • – app.module.ts
  • – app.component.ts
  • components/
    • component1/
      • component1.component.ts
    • component2/
      • component2.component.ts
    • component10/
      • component10.component.ts
  • modules/
    • login/
      • login.module.ts
      • login.routes.ts
    • admin/
      • admin.module.ts
      • admin.routes.ts
    • dashboard/
      • dashboard.module.ts
      • dashboard.routes.ts
  • directives/
  • guards/
  • mocks/
  • pipes/
  • services/

Now everything is organized in their own little folders, with a good flat structure.

Angular Modules

Angular Modules allows you to enable lazy loading. This means that now you can load features only when they are needed and it makes the initial loading time of your application faster.

However, the solution is not yet complete. As you start adding more modules, your components folders will grow in size and will become almost impossible to find anything. There is also no relationship between components and modules. We will also have components that are being shared between modules. Because the whole point of using components is to make them reusable and easy to share.

So the solution is to create a shared folder to include components shared between modules.  We also want to create a component folder inside each module folder and then move each related component inside it’s containing module.

  • – shared/
    • – components/
    • – services/
    • – models/
    • – pipes/

To summarise our new folder structure:

  • – app.module.ts
  • – app.component.ts
  • modules/
    • module1/
      • components/
      • module1.service.ts
      • module1.module.ts
      • module1.routes.ts
    • module2/
      • components/
      • module2.service.ts
      • module2.module.ts
      • module2.routes.ts
  • shared/
    • components/
      • services/
      • models/
      • pipes/
      • – …

Separation of Concerns – Components

Angular components are based on web components.

The use of web components provides a way of building a webpage by supplying highly functional templates that are encapsulated within your own custom HTML selectors.

After noticing their power, the Angular framework switched from directives to components in Angular 2.

Create Small Components

This seems easy at the start of a project, but preventing components from growing takes time and discipline.

A common example is to start with a small component with a visible purpose and then continuously add functionality to it rather than splitting it into new components. This scenario will lead to coupling between unrelated pieces of code and the need to rewrite significant portions of your codebase due to our growing files.

My suggestion is to stick with the KISS principle. Think of web pages as a collection of components.

A component is meant to define a small piece of functionality, either it’s own functionality or group other components. It should receive only the data it needs to complete its job.

You’ll need to separate the display logic (components) from business logic (services). A component should focus on presenting data and data access should be delegated to a service.

Components should communicate with each other in a loosely coupled way using services with messages/events.

Remember that components are supposed to be reusable and easy to share between your app, and the bigger they get the harder it will be to achieve this.

Reactive Programming

The reactive programming approach is a declarative programming paradigm related with data streams and the propagation of change. Basically, it follows the Observer pattern, where data flows emitted by one component(called subject) and those changes will be propagated to other components(called observers) that are registered to be notified of any state change.

Angular uses RxJS (the ReactiveX library for JavaScript) to deal with reactive programming. RxJS is a library that makes it easier to compose asynchronous or callback-based code using Observables.

To make components completely isolated we can take advantage of using reactive programming where you are able to create data streams of anything. As a result, components will only communicate through a service acting as a data bus publishing/subscribing messages. This can be achieved with the usage of Observables as in the following example:

Testing

Testing is an essential task of the development process that provides long-term maintainability. You should always test all parts of your application.

Your application will evolve much more smoothly if you write modular pieces of testable code.

The Angular framework was built to be tested.

Following this premise, Angular comes together with a large suite of testing tools and has dependency injection included into the core of the framework.

Mocking out components, services, pipes and directives is achieved rather easily with the use of dependency injection.

Furthermore, mocking data and maintaining small components, helps to ensure that you accurately test small pieces of code for more useful test cases.

The Angular CLI prepares your application to be tested with only one command(ng test). The test framework used by the CLI is Jasmine.

If you haven’t written tests for your Angular application yet, you can review the Angular testing guide that offers advice and techniques for doing unit and integration tests in Angular applications.

Conclusion

Angular is a great framework that offers you a lot of very cool and handy features and together with the proper organization following some basic principles a scalable and testable web application is possible to achieve.

I do believe that it’s very important to have a properly organized file structure, encapsulation and loose coupling since front-end applications normally evolve very quickly, which means that you may need to be flexible for refactors.

I hope this article helps you improve your apps.

Enjoy your coding!