Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Controller logic vs Service/Business layer logic

I am working on an application and am using a Repository-Service-Controller approach for a REST API.

I find myself debating between controller logic vs service logic. The service logic deals with business logic, such as calculating a book price, and the controller logic should deal with presentation details.

  • What if part of the business logic of the application is to check the publisher is subscribed to a PremiumService to determine if the book is editable? Would this go in business logic or controller logic?
  • What if in the controller, I want to hide the books being presented if the publisher isn't subscribed in the PremiumService? Would PremiumService then be a dependency of PublisherController to check the publisher of the book is subscribed in the PremiumService?

I can see how creating too many dependencies on the BookService could turn into spaghetti code though.

Here is an interface with pseudo code to help answer my questions.

class Publisher
{
    public function getId(): int;
    public function getName(): string;
    public function getBooks(): Book[];
}


class Book
{
    public function getId(): int;
    public function getName(): string;
    public function getPublisher(): Publisher;
    public function getAuthors(): Author[];
}

class Author
{
    public function getId(): int;
    public function getName(): string;
    public function getBooks(): Book[];
}

// Simple CRUD repository.
class BookRepository
{
    public function find($id);
    public function findAll($criteria);
    public function create($book);
    public function edit($book);
    public function remove($book);
}

class BookService
{
    public function __construct(
        BookRepository $book_repository,
        AuthorService $author_service,
        PremiumService $subscription_service
    );

    public function get($id);

    public function getAll($criteria);

     // Book is editable if the publisher of the book is subscribed to the PremiumService
    public function edit(Book $book);

    // Book is removable if the publisher of the book is subscribed to the PremiumService
    public function remove(Book $book);

    // Can only add an author if the publisher of the book is subscribed to the PremiumService.
    public function addAuthor(Author $author, Book $book);
}

class PublisherController
{
    public function __construct(BookService $book_service);

    // Can only view a book if the publisher of the book is subscribed to the PremiumService
    public function getBook(Request $request);

    // Can only view books if the publisher of the book is subscribed to the PremiumService
    public function getBooks(Request $request);
}

What is the usual or recommended approach here if a service relies on too many dependencies of other services? Should the service be dumb, like the repository?

like image 580
Aimee Avatar asked Mar 16 '17 17:03

Aimee


People also ask

What is the difference between service layer and business layer?

The Service Layer is usually constructed in terms of discrete operations that have to be supported for a client. For example, a Service Layer may expose Creating an Account. Whereas the Business Layer may consist of validating the parameters needed in creating an account, constructing data objects to be persisted, etc.

Is business logic a controller?

Controller – The brain of your application. The controller is responsible for most of your business logic. If your application is a web application, the controller will handle the requests coming into your application.

What is the difference between business logic and application logic?

Business logic refers to the rules and procedures that govern a business, including things like pricing, discounts, inventory levels, customer eligibility, etc. Application logic, on the other hand, is the code that implements those business rules within a specific application.

Should service layer contain business logic?

Creating a Service Layer A service layer is an additional layer in an ASP.NET MVC application that mediates communication between a controller and repository layer. The service layer contains business logic. In particular, it contains validation logic.


1 Answers

To answer your questions:

1) You kind of answered your own question by saying "what if part of the business logic of the application is to..." Since it's business logic, put it in the business logic layer (i.e. service).

2) Hiding books if publisher the isn't subscribed to a subscription service sounds like it's part of your business logic (your business rules are that users can't read books if they don't pay for them), so that would go in a service. And then yes, that service would have to be a dependency of your controller.

I frequently find myself in a similar situation to yours, where a single business rule requires dependencies on a lot of business services in order to do its job. A good way of avoiding around having a ton of dependencies in your services, while keeping each service simple, is to use a facade service once you start getting to four or five dependencies for a service. The facade is a higher level service which handles coordinating the lower level services.

For example, you could have a ContentManager service which takes dependencies of BookService, AuthorService, and PremiumService. Then your controller just has a single dependency on ContentManager. When your controller wants to display a list of books, it would call ContentManager.getBooks and pass in some user details so you can determine whether that user is subscribed or not. Then ContentManager determines whether the user can view a book, gets the book's details, gets the book's author details, and so on.

Even though ContentManager ultimately has a lot of stuff going on underneath it in its sub-services, it's still a pretty simple class because its only job is to call the appropriate sub-service methods for a given action.

Admittedly that's not a great improvement in your case because you don't have a ton of dependencies, but if you found yourself in a situation where a controller needed, say eight dependencies, then you could break those into facades. If five of those services were used for one set of high-level business rules (such as your library/publisher management) and three of those services were used for another set of high-level business rules (such as billing) then you'd have one facade with five dependencies and another facade with three dependencies.

like image 91
Ben Rubin Avatar answered Oct 10 '22 13:10

Ben Rubin