Layered Architecture Clarification
Layered architecture is a common pattern of an architecture design, and it is very suitable for a small scale monolith. There are many advantages such as,
- very easy to design and implement
- very in line with human nature
- cooperate with each other more easily
When we are talking about the layered architecture, we often have a myth; in order to replace the dependency, we should make those dependencies as a layer.
In fact, that’s not the purpose of layered architecture. I believe we seldom need to change a database, a framework, even a programming language. Therefore, what is the benefit of using layers?
Before we discuss further, we should see an example first.
The above diagram is a classic layered architecture for a web server. We separate a request flow into 4 components, route, controller, service and repository. Each component has its responsibility to handle a part of a request flow. This kind of implementation is also known as Single-Responsibility Principle.
In many articles, we had been taught that route is made for the web framework changed, and the repo is to nail the database. However, as I mentioned earlier, we seldom need change those hard things. Route and repo here are just completing their own duties.
Single-Responsibility Principle
I will describe those 4 components’ responsibilities to let you realize them more confidently.
- Route is a the wrapper of a web framework. To interact with a framework and hide the implementation, we build a layer to enclose those details. In route layer, we usually define HTTP routes right here including HTTP methods and URI.
- Controller is the first line to handle a request. The main responsibility is validating the input request and assembling the response. This layer often implements some error handlers to reflect like “400 Bad Request”, “500 Internal Server Error”, etc.
- Service is where the business logic in. The core values of a web product are all here. If it is a E-commerce site, service will calculate the recommendation, orchestrate the render content, and all other logic.
- Repo is an abstraction onto a database. In order to isolate the business logic, we don’t want the database operation to pollute the code in services, thus, repo plays this role in accessing persisted data.
The text description is a bit abstract, so I provide a more concrete example: https://github.com/wirelessr/Clean-Architect-in-Golang
The GitHub repository is quite simple due to the screaming architecture, hence, we can know this is a classic web service.
- Route is a mux wrapper in http. It will do nothing and route HTTP request to the controller.
- Controller defines API interfaces. In AddPost, it also validates the request format and assembles the response.
- Service own all business logic including how to access durable data, what the post format is, and how to generate the post identifier.
- Repo hides all database details, so you can choose what data store you want. But, again, we don’t change our data store decision easily. Therefore, repo here is to encapsulate the data store access to make service be independent from
firestore
.
What’s Benefit
Do we just separate our web service into several layers for SRP? No. Actually, this comes some benefits. Let me show two most important advantages,
- Layers make testing become more easily.
- If those layers are modules, we can decouple the deployment of layer modules.
The second one is straightforward. Thus, I will dive into the test. According to my previous article, we can leverage the dependency injection to accomplish a high testing coverage. For instance, in my golang example, in order to verify the service, we can create a mocked repo to ignore the data store access.
Conclusion
There are many articles trying to compare layered architecture and microservice architecture. However, layered architecture is not only an architecture pattern but also the coding technique for a SOLID software. This article tells you still can use layered architecture in your microservice like my post example. They are not two mutually exclusive things; moreover, they are more close to each other.