Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using multiple services or multiple repositories within service?

Imagine we have two entities, EntityA and EntityB. Both entities have a repository to query the database, EntityARepository and EntityBRepository. There are also services for both of them, EntityAService and EntityBService.

Now there is a method in the EntityBService, which also needs to use EntityA. What would be the right way of doing this?

  • Should the EntityBService use the EntityARepository directly?
  • Should the EntityBService use the EntityAService?

I could see how using the repository directly might be very convenient, but also it seems to get kind of messy when having not only two entities.

Is there common design pattern around this topic or recommendations?

like image 673
tschaka1904 Avatar asked Oct 11 '19 11:10

tschaka1904


2 Answers

TLDR; it depends!

If you're trying to follow Domain Driven Design, I think it's a good idea to differentiate service and repository. There are different definitions which may differ in details but I'll stick to Martin Fowler's one for Repository:

(...) A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. (...)

and for service:

A Service Layer defines an application's boundary [Cockburn PloP] and its set of available operations from the perspective of interfacing client layers. It encapsulates the application's business logic, controlling transactions and coor-dinating responses in the implementation of its operations.

It is worth pointing out that service isn't just repository + business logic. For most simple scenarios repository just wraps up accessing single database, but for advanced scenarios creating single entity may require accesing multiple databases, so repository role is to remove this woffle from service layer.

And here is what you could come up with:

  1. Use EntityARepository directly in EntityBService if what you're trying to do is just fetching EntityA without any business logic related to EntityA. Here is a simple example:

EntityBService performs operation on EntityB, but it depends on purely EntityA state.

  1. Use EntityAService in EntityBService if requesting EntityA involves some business logic related to EntityA. Here is a simple example:

EntityBService performs operation on EntityB and EntityA and later needs to be created if it doesn't exist - creation involves a business logic like checking is it allowed (e.g. based on user role).

like image 173
Krzysztof Skrzynecki Avatar answered Nov 17 '22 11:11

Krzysztof Skrzynecki


Is there common design pattern around this topic or recommendations?

One common practice is to avoid changing entities that are stored in different places in the same transaction. One way to ensure that you never do that is to have only one entity active in any transaction.

So we might reasonably have entityA, and a copy of the information we need from B. Or we might have entityB, and a copy of the information we need from A.

For use cases where we aren't changing either entity, we can just use copies of the data.

In the case where we are using entityA and recent-copy-of-B, we know that entityA comes from a repository. Where does recent-copy-of-B come from? Well, it comes from an abstraction that looks something like a repository, except (a) it fetches values, rather than entities and (b) it is read only.

recent-copy-of-B looks something like a DTO. And while you might use the same one everywhere, it is actually safe (because values are immutable) to create specialized versions for different use cases.

like image 40
VoiceOfUnreason Avatar answered Nov 17 '22 10:11

VoiceOfUnreason