Friday 19 October 2018

Best practices: Building Angular Services using Facade design pattern for complex systems


Angular Services

Angular services concept always confuses newbies with server side REST services. If you are still not sure what it is, I will recommend you to read Angular documentation
Angular Services have responsibility to provide application data/business logic to components. Components should take/provide data to service and function as glue between view and service. It is service who can decide whether to provide mock data or go to server and fetch data from database/file/another service(s) etc.
Ideally, services should be feature oriented. You have choice to build a giant service class or micro services collections. In first approach, there shall be only one service which shall contain all business logic and shall be provided via Angular Dependency Injection in all components within system. Issue with this approach is, giant service class shall get bloated eventually leading performance issue. Every component shall get injected with service and functionality which is not required to consumer component at all. Do you think it is good?
In second approach (followed widely), feature specific micro service gets built. For example, if your system have Login, SignUp, Dashboard components then you shall build LoginService, SignUpService, DashboardService and so on. Each service shall contain functionality required for specific targeted component. Now this design looks good, isn’t it?

Problem?

While building big and complex Single Page Application using Angular, you shall soon end up with hundreds and thousands of component classes. Having said so, you shall have similar number of Angular services injected. What is the problem here?
No matter how good naming convention you have followed for building components and services, there shall be time required to figure out specific name of service for specific class. Also you may end up writing duplicate service class with slightly different name for same component than other team built. If you are working in Extreme Programming model, your frontend developers are supposed to keep switching between modules/components/features. It should not take much time for them to figure out components and services associated.

Solution

We can solve this problem using Facade design pattern.
Facade Design Pattern
Facade discusses encapsulating a complex subsystem within a single interface object. This reduces the learning curve necessary to successfully leverage the subsystem. It also promotes decoupling the subsystem from its potentially many clients.
The Facade object should be a fairly simple advocate or facilitator. It should not become an all-knowing oracle or “god” object.
Here is the good read for Facade design pattern in details
Facade Design Pattern
Facade in action with Angular Services
I would recommend following steps to build Angular services using Facade pattern:
Define all your Angular services as per your business requirement and/or keep adding more as needed.
Create a service called “FacadeService” (feel free to use any other name here)
Create a shared NgModule and provide all Angular services
Providing all Angular services in Shared module
Facade Service implementation
Our main discussion shall be around “FacadeService” service only.
We have discussed about two approaches giant service versus micro service. We have seen their pros and cons. Best solution is to merge both of them to create service Facade. Now, FacadeService class shall be a God class but won’t have actual functionality but a wrapper over actual services.
FacadeService shall aggregate all Angular services within the said system. One easy approach is to inject all services inside FacadeService in constructor. But if we do so, we shall end up with similar problem as of giant service class.
Smarter way would be to aggregate all Angular services inside FacadeServiceand resolve their instances from Angular DI inside “property” access.
Let’s discuss AccountService usage.
We have a property defined called accountService inside FacadeService. getOrderList() and getAddress() functions of FacadeService works as wrappers for actual methods of accountService.
Whenever accountService member is accessed, its get property block shall be executed. Inside get block, we check if backing field _accountService is instantiated. If not, we asks Angular Dependency Injector to resolve an instance for us.
To access Angular DI engine, we need to inject Inejctor Angular’s built-in service inside FacadeService constructor. injector.get() shall query Angular’s DI engine to resolve requested service instance if it is provided. (Remember SharedModule where we have provided all services?)
If you have observed carefully, we have implemented Singleton design pattern as well inside get property section of accountService property.
Consuming FacadeService inside component(s)
We have AccountService aggregated inside FacadeService and it is ready to be consumed inside OrderComponent and AddressComponent.
Finishing up remaining system
On the similar note of accountService implementation, you can finish implementation of other Angular services inside FacadeService.
Implementing Facade design pattern in Angular Services

No comments:

Post a Comment

Angular Tutorial (Update to Angular 7)

As Angular 7 has just been released a few days ago. This tutorial is updated to show you how to create an Angular 7 project and the new fe...