In this blog, I have consolidated some of the important Best Practices for Angular development. This blog aims at providing a quick checklist of the best practices to keep in mind during the development and review of Angular Projects.
PREREQUISITE
Knowledge of Angular.
BEST PRACTICES – QUICK REFERENCE LIST
- Use Angular CLI: It is always recommended to use the Angular CLI tool while working with the Angular project as it not only increases productivity but also does the basic set of tasks when using the tool to create a new project or for a generation of modules, services, components, directives and pipes.
- Modularize: Develop Angular apps in a modular fashion by splitting the application into a core, shared and feature modules.
- Core module consists of components (i.e. header, main navigation, footer) that will be used across the entire app, which typically are part of the AppModule(RootModule). This also makes the AppModule leaner and lighter.
- A shared module can have components, directives and pipes that will be shared across multiple modules and components, but not the entire app necessarily.
- A feature module delivers a cohesive set of functionality focused on a specific application need such as a user workflow, routing, or forms or some specific domain specific functionality.
- Split UI into Components: Split your application modules into smart and dummy components. A dummy component is a component used for presentation purposes only, meaning that the component doesn’t know where the data came from but only has the logic to display the data. For that purpose, we can use one or more smart components that will inherit the dummy’s component presentation logic. Read more
- Follow standards and naming conventions: Use proper file naming conventions and folder structure throughout the application. Follow Style Guide. Angular essentials is a good consolidated pack of extensions that are extremely useful for Angular development.
- Light Template: Keep template light and clean with minimal logic like ‘*ngIf=”myVariable === 1” ’. Any complicated logic other than checking straightforward conditions should be written in the component’s class method, not in the template directly.
- Make use of Lazy Loading: Lazy loading a feature module is the best approach for accessing a module via Angular’s routing. That way we will be able to make our Angular app faster and lighter to load. With lazy loading, the feature module won’t be loaded initially, but when you want to load it.
It can be loaded when the corresponding route is navigated or if you know that the lazy loaded module will be required eventually, you can use the {preloadingStrategy: PreloadAllModules} to have it loaded in the background after the initial Application load. Therefore, making an initial load of the Angular app faster as well as the load of the feature module fast!
- Meaningful and up-to-date Comments:
This one is common to all Programming!
Use comments in your code to make it easily understandable by anyone. Use proper and self-explanatory variable and function names. (The 5 second rule – Anyone should be able to understand what your code does in 5 seconds just by looking at it, that is the way your code should be). Comments are useful to explain why some step of code exists, how some API is being used, or explaining the consequences of some code action. Also regularly update comments when the code is updated. Out-of-date comments are worse than no comments as they add to confusion instead of clarity.
- All business and data manipulation Logic in Services: Services are the place to contain all the code for business logic and data handling. It is important to have well-structured services which provide access to data, data manipulation and other reusable logic in a proper way.
- Have a base service class for API calls.
- Consider having one or more Utility Services to handle the logic on your components used to deal with some data, maybe preprocess it or mutate in some way.
- Class for declarables, Interface for Models: Always use a class instead of an interface for services and other declarables (components, directives, and pipes). Prefer to use an interface for data models. Interfaces are only used for type-checking and do not translate to any code in JS which makes them ideal for model definitions.
- Avoid repetition, Reuse instead: Whenever we have a situation where multiple HTML elements have the same behavior (for example: when we hover over the element it changes to green color), we should consider using attribute directives. We shouldn’t repeat the hover logic every time we need it on some HTML element. A much better way is to create a directive and then just reuse it on any element which requires the logic.
- Right hooks at right time: Lifecycle hooks play a very important part of Angular development. We should use them whenever we have an opportunity to. For example, if we need to fetch some data from a database as soon as our component is instantiated, we should use ngOnInit() lifecycle hook and not the constructor. If we have some logic inside child components and we want to execute that logic as soon as decorator parameters are modified, we can use ngOnChanges() lifecycle hook. If we need to clean up some resources as soon as our component is destroyed like unsubscribe, we should use ngOnDestroy() lifecycle hook.
- Proper dependency injection: Provide service at the proper location(Module or component) to avoid unnecessary instantiation. Since Angular v6, if we create a service with the Angular CLI command: ng g service service_name, it will create a service with the providedIn metadata with the “root” value.
1 2 3 4 5 6 7 8 9 10 |
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class HeroService { constructor() { } } |
By providing such a service means that we don’t have to import it in the app.module file or to provide it in providers array inside the same file.
- Safe Navigation Operator: Use Safe Navigation Operator (?) in HTML Template while accessing a property from an object in a component’s template. If the object is null and we try to access a property, we will get an exception. But if we use the safe navigation (?) operator, the template will ignore the null value and will access the property once the object is not null anymore.
- OnPush change detection strategy: Use OnPush change detection strategy for pure/dumb components that accepts data as input, which is immutable or does not change. Angular will optimize the performance of your application dramatically by not performing change detection over the entire sub tree with the root being the given pure component.
- Angular Observables: Make use of Angular Observables with the proper application of operators in routing, forms etc. to track and handle events appropriately.
SUMMARY
This is a quick reference list to start with and keep in mind when working with Angular. Following best practices makes our code look good as well as perform better. We should continuously work on improving our code and implementing the best practices. Also, consider the use of Ahead-of-time compilation and try the upcoming IVY renderer to reduce the bundle size and make your application faster.
Let me know in the comments if you think any other best practice should make it to this top list!