Quality
12 min
Clean code is vital to a stable software that meets the usability and performance expectations customers demand. Not only that, clean code is easy to maintain and can be easily adapted to accommodate new features without negatively impacting other areas of the system.
As the size and complexity of the application grow, it is even more important to keep the codebase clean.
Here are our top suggestions for writing clean code in Angular projects to keep your software in the best shape possible.
Objects and arrays are reference types. If you need to modify them, it is best to do so in an immutable way. That way you avoid modifying the original objects.
The best practice is to use the es6 spread operator (...).
The Original Object
this.user = {
name: 'David',
age: 25,
address: 'Sunny street 34'
}
Deep copy the user object and override the name property.
let updatedUser = {
...this.user,
name: 'Paul'
}
As companies rely more on popular frameworks such as Angular and NextJS, these projects can quickly become unwieldy as they grow in size and complexity.
It is important to ensure the project remains well-organized to make it easy to locate things as efficiently as possible.
Following standards such as bundling code into modules, following single responsibility patterns, and organizing SCSS files go a long way to keeping the code clean.
Flexibility becomes increasingly important as the system grows.
Using interfaces allows you to define the public properties and methods that should be exposed without defying how they should be implemented.
You can save implementation details for later in the project by later creating a class that implements the interface.
The constructor should only be used to start class members, while ngOnInit() should be used to do actual work that needs to be executed as soon as the class is instantiated.
The reason for this is because when Angular calls ngOnInit, creating the component DOM, dependency injections and input bindings are complete. Thus, it is the ideal place to begin performing actual “work.”
Duplicate API calls can impact performance. When possible, use caching mechanisms to avoid unnecessary calls.
With caching, you store the returned value in temporary storage. That way, when you need to make another request to the same API, you can check the cache for the value and avoid an additional call.
If you are dealing with values that change infrequently, consider including a timing mechanism to expire the values stored in the cache to force a new API call to get updates periodically.
Each new subscription requires memory. If these resources are not released, they will continue to consume memory unnecessarily and eventually cause memory leaks.
Be sure the code closes subscriptions when they are no longer needed.
Operators such as take() or takeUntil() can help with this.
The take() operator can be used when you only need the first value returned.
signature: take(count: number): Observable
The takeUntil() operator listens to an observable until it emits another value.
signature: takeUntil(notifier: Observable): Observable
There may be times it is necessary to aggregate values from multiple or nested observables to perform an action.
However, nesting these subscriptions in the observable block of another subscription makes the code difficult to read.
With so many nested subscriptions it can be difficult to detect and close these resources properly.
As a result, you could end up with memory leaks.
A better solution for writing clean code in Angular is to use switchMap, forkJoin, and combineLatest to make things easier to read.
this.returnsObservable1(...)
.subscribe(
success => {
this.returnsObservable2(...)
.subscribe(
success => {
this.returnsObservable3(...)
.subscribe(
success => {
...
},
this.returnsObservable1(...)
.pipe(
flatMap(success => this.returnObservable2(...),
flatMap(success => this.returnObservable3(...)
)
.subscribe(success => {...});
There should be no business logic in templates. Even a trivial (==) check should be avoided.
Placing any logic in the template makes it difficult to unit test. Perhaps the biggest problem, however, is that performance suffers when placing logic in templates.
Angular can’t detect changes in values from function calls inside templates.
Thus, each function must be re-executed for changes to be detected.
One way to fix this problem is to use the setter function. Another option is to use ngOnchanges.
Angular creates a SPA (Single Page Application. As such, all of its components are loaded at once.
Loading modules this way can make the application sluggish on startup.
It is best practice to lazy load, which is essentially loading resources on demand.
The recommended approach for lazy loading is to use NgModules. Each NGModule consists of code necessary for a specific function only.
As The size and complexity and applications grow, so too does the number of modules.
Shared modules are a way to organize and streamline Angular code. Anything that needs to be shared throughout the project should be registered in a shared module file.
To reuse it, import it to any module that needs it.
It is sometimes common practice for developers to manipulate HTTP requests directly in components. However, setting up HTTP requests isn’t always simple. They may require additional directives and configuration that could clutter the component.
It is best practice to move HTTP request manipulation to a service. A service is a class with a specific purpose. Services can be anything such as a value, function, or feature the app needs.
A service is shared and can be used by modules to perform complex tasks.
A clean codebase is the foundation of an application that can grow to meet user demands.
Writing clean code in Angular ensures the application is maintainable and can support changes without negative consequences.
If your business needs assistance with creating Angular coding standards, contact one of our professionals at Adservio.
We would love to help you apply Angular code review and clean code best practices in your organization.