Best practices: Building Angular Services using Facade design pattern for complex systems
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?
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.
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
Design Patterns and Refactoring articles and guides. Design Patterns video tutorials for newbies. Simple descriptions…sourcemaking.com
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
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
FacadeService and resolve their instances from Angular DI inside “property” access.
We have a property defined called
accountService inside FacadeService.
getAddress() functions of
FacadeService works as wrappers for actual methods of
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
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
Consuming FacadeService inside component(s)
AccountService aggregated inside
FacadeService and it is ready to be consumed inside
Finishing up remaining system
On the similar note of
accountService implementation, you can finish implementation of other Angular services inside
Contribute to service-facade-demo development by creating an account on GitHub.github.com
Facade design pattern help us building complex Angular application by providing a simplified access to many complex Angular micro services.