Most of the applications today are based on a multi-tiered architecture to uphold the business needs of a flexible, agile and a scalable system. When you have applications which cater to more than one client and involve multifaceted transactional use cases, maintainability and scalability of such applications are major concerns. Implementing a service layer has proven to aid in easier management, data abstraction and scalability of such applications. For today, we will discuss about implementing service layer in rails application.
So what is a service layer?
A service layer is something which is in between of a model and a controller and is used to create actions that are outcome of domain logic. There might be some instances where the logic will not be a part of the core logic, in such scenarios you can think of services which may contain some generic logic that you can reuse in an application.
Services are regular classes which are used as a service layer and service class instances are used for invoking respective operations. Service instances are stateless, which means one should avoid associating it with any model having dependencies on service classes. It is considered as one of the good practices to pass any service method dependency at runtime.
Rails has made provisions by specifying dedicated directory structure to include services which enables writing cleaner and reusable code.
When to write service?
If you think that some of your code or your logic does not fit well into either model or controller i.e. you are writing a business logic which would be used by multiple models or is independent of model definition then you can think of services. Let me elaborate it further with an example.
Let’s walkthrough the scenario for issuance of stocks to shareholders which I think would be an apt example. Here, creation of stock issuance records in database will be directly associated with the StockIssuance model. But, if there is an additional step to apply vesting, then creating vesting schedule for stock allocation is essential but not a responsibility of StockIssuance model.
So, writing such logic in StockIssuance model leads to added complexity and lines of code.
In such situations, the user can write services which can be called from StockIssuanceController to take care of the conditional execution of steps arising from multiple models, like issuing stock and then creating a vesting schedule.
Another common example can be the handling of permissions. Process to identify and fetch applicable permissions and then enabling of user access to respective operations is needed in most of data critical models. As this process cannot be always associated with every model where it’s used, the best place to put it can be in a service layer.
Bank transactions is another case where a simple operation like transferring money between two accounts runs through multiple steps like checking balance, debiting money, crediting money and sending notifications to the accounts. All these independent operations will be associated with UserAccount model but a higher level function to transfer money cannot fit into the UserAccount model. To tackle this, write a simple service to place all such functions.
Here is a basic way of writing services in rails application.
Inside app/services folder simply create your service file and specify your class and action as below.
That’s it, now you can use this object to call any of the service action.
To summarize, use of services helps in writing thin controllers as it enlightens a systematic way for keeping reused logic in a single place. That’s why I have started to enjoy services for many different operations and would request you to share your thoughts and experience as well. Good luck!