The Biggest Mistake of Spring Web Applications

Developers are very good at talking about the benefits of dependency injection when using Spring applications. Unfortunately, they don't really take advantage of its benefits like Single Responsibility Principle, Separation of Concerns principle. If we take a look at most of Spring's web applications, the common design mistakes are as follows:

1. Domain model objects are used to store application data (used as DTOs), and the domain model is an anti-pattern such as an anemic model.

2. The service layer has one service per entity.

The question is this is so common, where is the error?

Spring's web applications are this way because the way they do things has always been this way, old habits die hard, especially if they are senior developers or software architects, and one of these people's arguments for doing this is that : Our application follows the principle of separation of concerns, as it has been divided into several layers, each with its own specific responsibilities.

1. The web layer is responsible for processing user input and returning the correct response back to the user. The web layer communicates with the service layer.
2. The service layer acts as a transaction boundary. It is also responsible for authorization and contains the business logic of our application. Domain model objects managed by the service layer and communicate with other service and repository layers.
3. The repository/data access layer is responsible for communicating with the storage of the data used.

Separation of Concerns (Soc) is the separation of a computer program into different parts, each with a focus of attention. A typical Spring Web application follows this principle to some extent, but the reality is that the application has an overall service layer , it has too many responsibilities. More specifically, the service layer has two main problems:

1. Finding business logic in the service layer
Business logic is scattered across the various service layers. If we need to check how a business rule is implemented, we must first find it. It may not be easy. Also, if the same business rules are required in multiple service classes, the problem is that the rules need to be simply copied from one service to another. This will lead to a maintenance nightmare.

2. One service per domain model
This completely violates the Single Responsibility Principle, which is defined as follows: The Single Responsibility Principle states that every class should have a responsibility and that responsibility should be fully encapsulated by the class. All its services should be narrowly aligned with responsibilities. (The behavior methods that originally belonged to the domain model should not be implemented in the service, and the object not only has properties but also behaviors)

The service class has many dependencies, as well as a large number of circular dependencies. More like network tight coupling and monolithic services. This makes it hard to understand, maintain and reuse. This may sound harsh, but the service layer of a Spring web application is often the most problematic part. Fortunately, all hope is not lost.

1. We have to migrate the business logic of our application from the service layer into the domain model classes.

As an example: let's say I'm a service class and you're a domain model object. Would you like my decision if I made you jump off the roof? (If you jump down, you will fall, you have no brains or you are brainwashed, you will become a zombie, you only obey the execution and don’t think about your own safety. This is the problem of the anemia model.)

There are three ways to migrate business logic from the service layer to the domain model class. Advantages:

(1) Our code will be logically cut, the service layer only needs to focus on application logic, while our domain model focuses on business logic.
(2) There is only one place for business logic, and it is easy to find and modify.
(3) The source code of the service layer is clean and does not contain any copy-paste code

2. Each entity service is cut into smaller services with a single target.

For example, if there is a single service class that provides CRUD operations for people and user accounts, we should divide it into two separate service classes:
the first is to provide CRUD operations for people and the
second is to provide CRUD operations related to user accounts operation.

Benefit: One logical group responsibility per service class. Each service class has fewer dependencies, which means they are no longer a source of tight coupling. They are smaller and loosely coupled components. Service classes are easier to understand, maintain and reuse.

These two simple steps will help us make our application architecture cleaner, helping fellow developers to be more productive and happy.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325693393&siteId=291194637