Service Layer and Controller: Who Takes Care of What

Service layer and controller: who takes care of what?

If you wish to have controllers be able to persist changes to a Child object, then traditionally you would have a method in the service named something like ChildService.update(Child newchild), which will handle calling the correct DAOs to persist the new version of this Child.

Controllers are free to ask the service for a Child, change the fields around (conceivably based on some user input) - a sane design would have the Controller doing some work with the Child POJO and then asking the Service to persist the change. The model POJO should know nothing about a controller, service, or DAO but just simply hold data as you suggest - certainly you would not want every call to setName() or setGender() to automatically result in a database update.

Instead, the controller and/or service should acquire a Child object, do whatever work it needs to the object in it's unit of work, and then ask a Service (and then the DAO) to persist the changes.

Validation can take place in several layers - the Controller might want to validate any input from the web user, and the Service may want to validate that it has a valid Child object before it persists it. It especially makes sense to have some level of validation in both layers in case you want to re-use this Service in other capacities - such as exposing a REST interface, a different front-end, etc.

Difference between service layer and controller in practice

In both examples, why do you need to cast Client? That's a code smell.

Since the call to the service tier is also the call that establishes the database transaction boundary, making multiple calls means that they are executed in different transactions, and are therefore not necessarily consistent with each other.

That is one of the reasons why multiple calls are discouraged. @ArthurNoseda mentions other good reason in his answer.

In your first case, there should be a single call to the service tier, e.g. something like this:

if (changeEmailResult.hasErrors()) {
return new ModelAndView("/client/editEmail");
}
try {
clientService.updateUserEmail(user.getName(),
changeEmailBean.getCurrentPassword(),
changeEmailBean.getNewEmail());
} catch (InvalidPasswordException unused) {
ModelAndView model = new ModelAndView("/client/editEmail");
model.addObject("wrongPassword", "Password doesn't match to real");
return model;
} catch (DuplicateEmailException unused) {
ModelAndView model = new ModelAndView("/client/editEmail");
model.addObject("email", oldEmail);
model.addObject("emailExists", "Such email is registered in system already");
return model;
}
refreshUsername(newEmail);
return new ModelAndView("redirect:/client/profile");

You could also use return value instead of exceptions.

As you can see, this will delegate the business logic of changing the email to the service tier, while keeping all UI related actions in the controller where they belong.

Responsibility of Controller or Service?

Possible duplicate.

The responsibility of the controller, is to accept a request, invoke the processing, and respond according to the result of the processing.
Try to look at the SOLID principles and always try to apply them.

So first of all, DTO, it depends on your architectural design, but I would say that the DTO is the abstraction that allows you to decouple you Domain Model from the client model.
The DTO should be seen as the data representation between two layers, if the DTO crosses more than one layer, it probably isn't a DTO but a business or data entity.

) Fetch images from body

this looks like something you designed to be able to receive the desired data, but is not something your domain model cares about.
For example if your form allow you to save "Sale advert", which is made of few images and some text, probably this aggregation of data in your business layer (service), is represented by one or more domain objects, so the fact that you receive a body in whichever format, depends more on technology or transport, and should be transparent to your business layer.
A good example to help you find boundaries, is thinking about re-usability. How would you reuse your service layer if you were to use it from a WCF service for example?
Your service should always receive and expose Domain Objects.
Leave to the consumer component the responsibility to decode/encode.

3) Check Summary and body text rules (and all other checks)

seems to be a validation, but I cannot tell if this validation is only related to the domain.
Some validation is also done in the controller itself to check if the request is valid or not.
So if this check is done on the DTO structure, before you try to convert it, probably that is a controller validation, if instead, this validation is necessary to decide weather or not the input can be saved, well probably in this case it would be considered other's responsibility.
You mentioned:

for example summary text length

if this is a business rule, then I would place it in a validation object, responsible to validate the "summary text" or let's call it again "Sale advert".

The responsibility to save a domain object to a data store, is normally delegated to a Data Access Layer, which is coupled to the database structure and provides the abstraction to the business layer.
This can be done implementing a repository pattern or maybe using an ORM, I normally don't add logic to persist data in the business layer.

Another note, here you are asking about controller responsibility, but pay attention to your service "layer", I have seen often code where a huge service class, was encapsulating all the business logic and validation, that is very bad because again goes against most of the solid principles.
Look at the command query and decorator pattern, I love them because the really help you breaking down your code in smaller pieces with single responsibility.
If interest look at this example project on github (.net core).
I am still working on the documentation but should be clear enough.

Who is responsible for parsing? The controller or service layer?

Generally speaking data submitted from the view should be parsed by a ModelBinder, falling back to the Controller if using a ModelBinder doesn't seem to make sense.

Parsing in an application service makes sense if multiple sources can submit the data in the same format (like web service or file system persistance).

What methods should be written in the Service Layer?

  1. I read that all CRUD operations should go in the dao layer.

You are right. userDao.save(user) - this is CRUD. But set password and adding the roles - it's a part of the business logic. DAO layer should know nothing about business logic. In this case dao layer should just take prepared user and save it into db. Thats all.


  1. What the purpose of findByUsername(String username) in UserServiceImpl

For the same reason, findByUsername (String username) is in the Service. This is now nothing happens and just a method is called from the DAO. But suddenly it will be necessary to add some logic before calling the method from the DAO.

Why we need to write business logic in separate service layer instead of writing in controller itself?

It depends on your architecture. If you're using some of the Domain Driven Design principles, there would be little if any logic in the controllers/api. The controllers would be used to coordinate/ manage the communication between the domain services (i.e. AccountService), repositories (i.e. AccountRepo), and or infrastructure services (i.e. EmailService). All logic would be in the models and services. Some advantages are...
1. Unit testable code
2. The code better models the business problem (controllers mean nothing to the business problem)
3. Controllers don't become a place to jam a lot of business logic into and result into a tangled mess
4. And more...

Of course this all depends on whether maintainability is a priority

is it a good practice to inject Controller into service layer in spring applicaiton?

This is not a good idea. The controller is meant to deal with the receiving of new requests. Hence controllers are tightly coupled to the medium/technology that they operate on. For example HTTP controllers, or controllers that get their requests via a message queue.

The service classes, on the other hand, are designed to not be coupled at all with how the request arrived into the application. This allows you to re-use service classes, which contain the main business logic, across various controllers. Let say that tomorrow your boss no longer wants to use HTTP, and instead wants all new requests to come in via a message queue. Because your service classes are not dependent to any controller classes, it will be a lot easier to alter your application so that it can properly process requests coming from the message queue.

As such, your controllers would require the services classes, and not the other way around.



Related Topics



Leave a reply



Submit