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.
PremiumService
to determine if the book is editable? Would
this go in business logic or controller logic?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?
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With