Architectural Considerations for Angular Applications

Software

When it comes to application architecture, my approach is holistic: it's not just about the application design, but the things around the application -- for example, unit tests and linting -- that can help produce a solid application. 

Here are some of my thoughts for creating successful Angular applications, though many of these apply to other sorts of applications as well. The goal is to design something in such a way that it's easy to maintain, easy to enhance, avoids pitfalls, and most importantly, works as intended.

Here we go!

1. Use those spec files

Angular was designed from the start with unit testing in mind. But a lot of Angular developers I've spoken to don't use the spec files the CLI creates for us. Having good code coverage is important, and it's worth taking the time to write those unit tests. For more information on how unit testing has helped me write better software, check out this post.

2. Organize code into judicious feature modules with lazy-loading

Feature modules allow you to organize your code into cohesive chunks, and to utilize lazy-loading so that only the parts of your application that the user needs are downloaded. You can read about feature modules in the official docs here, and learn about lazy-loading them here.

3. Use the Container/Presentation Pattern...when it makes sense to

The Container/Presentation pattern is one wherein you have some components which act as containers of child components, and those child components simply present information without acting on it -- they take input from the container (parent) component and emit events to it. It's the container (parent) component that handles all of the data manipulation and logical operations.

This pattern allows for simple presentation components, but there is a downside: sometimes, the container component can become very complex.  The key is to use it judiciously. It can be very helpful under the right circumstances, but if the container component contains a lot of child components, it can get hairy!

4. Don't call methods within template expressions

Making method calls within HTML templates for things other than responding to user events can adversely affect performance, because they'll get invoked any time change detection runs, and that's almost certainly more often than you'd expect. Try calling a method from within an *ngIf and putting a console.log() call in the method you're calling, and you might be shocked by how often it gets called. Instead, use things like variables and pipes.

5. Follow the Angular coding style guide

The Angular team has put together a coding style guide with some good advice. It's worth reading! You can find it here.

6. Lint!

Running the linter before committing your code, and at the start of your build process, helps prevent potentially harmful code from making its way into your codebase. The official docs are here, but here's a few tips they don't mention:

  • To run the linter and only see the errors (not the warnings), run ng lint --quiet.
  • To save the linter output to a file, run ng lint > (output filename).

7. Seriously, avoid Promises

If you're making HTTP requests, use Observables (the native return type) instead of Promises. Observables, and RxJS in general, provide a lot of usability. Learn more about RxJS here.

8. Determine the best approach for passing JWT tokens

When Angular was first released, if you needed to pass a JWT token along in a web request, you needed to write code, usually in a service, to include the token in the request header. In version 4, they introduced HttpInterceptors which made this much easier. I've used both approaches, as I've been using Angular since v2. These days, the HttpInterceptor is almost always the better option, but sometimes you might need a service that provides other authentication-related functionality, and the functionality might belong there.

9. You don't need (and shouldn't use) jQuery

In Angular, DOM manipulation is done via directives. You shouldn't use jQuery for this. In fact, it's better to avoid jQuery altogether. There are other ways to get things done. jQuery isn't even part of Angular.

10. Don't be rigid

Regardless of how much time you've put into the application's design, sometimes you might receive feedback from a developer recommending an alternative approach. Listen to them. Be flexible. There have been times I've put a design and architectural notes together, only to have a developer begin work, get in the weeds, and realize there was a better way. At the end of the day, we want the application to be the best it can be, and if a developer has a better idea than you did, go with it.

11. Use an external configuration

Using an external configuration makes you application easier to configure for different environments. There was a time when we could use environment.ts and environment.prod.ts for configuration, but these files have been deprecated in v15 and are no created with new CLI-generated apps. Additionally, they were only useful within an organization or other closed environment, and not something easily modified by end-users of externally distributed apps (the code being bundled during the build process). You can read about how to use an external config file in this post.

In Conclusion

These are just some of the considerations I take into account when architecting an Angular application. I hope this information is helpful!

Comments

Popular Posts

Resolving the "n timer(s) still in the queue" Error In Angular Unit Tests

How to Get Norton Security Suite Firewall to Allow Remote Desktop Connections in Windows

Silent Renew and the "login_required" Error When Using oidc-client

Fixing the "Please add a @Pipe/@Directive/@Component annotation" Error In An Angular App After Upgrading to webpack 4

How to Determine if a Column Exists in a DataReader