Exploration of Repository, Service, Controller


Popular code architecture is a layered architecture. This architecture mainly consists of three layers:

Spring reflects layered architecture through the concepts of @Repository, @Service, @Controller:

so:

Clear responsibilities

@Controller should contain presentation-related logic, including data formatting, simple transformations, etc. @Service should contain business logic, and business rules. @Repository should contain data access. This may be obvious to you, but I have seen in many projects that this division of responsibilities is not maintained. I have seen projects where the @Service contains the data access or presentation logic and the @Controller contains the business logic. This is not good because we expect, for example, that the AddressService contains all the business logic associated with an address. We assume the business logic will be in one place, not scattered in multiple places. Scattered logic makes it difficult to understand, refactor, and, above all, testing.

Shallow system

Some systems or part of a system is a ‘shallow system’, meaning that the presentation layer needs data directly from the repository and there is almost no business logic. This is a typical CRUD. In this case, we do not need @Services, which only delegate to @Repositories.

Data encapsulation

We can treat the Service and the Repository as a coherent unit, like a class with methods (Service operations) and fields (data/Repository):

If we access the fields of a class directly, this is a violation of encapsulation. The same is true in this case:

PersonService should not invoke AddressRepository. Why? Because PersonService accesses Adresses directly through AddressRepository. This is data-level integration, which is almost bad practice – no data encapsulation. When the Address data structure, format, or semantics change, this directly impacts PersonService.

If there is an AddressService with business logic, the PersonService should call the AddressService. If the AddressService does not exist – the system is shallow, there is no need to create it.

Relationships

Let’s look at the following calls/relationships:

This is not good, because if we allow access to everything by everything, it will quickly lead to chaos:

To avoid chaos, we need to establish rules that enforce order, clarity, and the previously mentioned encapsulation:

  • @Controller should call its “own” service
  • @Service should call its Repository
  • @Service may call other services

Read-only data

Functions such as reports, dashboards, printing, etc. require read-only data/classes. If no corresponding methods exist in @Service, e.g., ReportController can directly access multiple @Repositories:

Summary

Protecting the data is always good practice. But, most importantly, you should follow the ‘Clear responsibilities’. The Controller, Service, and Repository express the intention and purpose.


Leave a Reply

Your email address will not be published. Required fields are marked *