What is a Domain Service in Domain-Driven Design?

  Рет қаралды 20,860

Milan Jovanović

Milan Jovanović

Күн бұрын

Пікірлер: 115
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@o.boyraz
@o.boyraz 11 ай бұрын
One important point to consider; Domain services is just a pattern of ddd. In a real complex domain, you might end up with thousands of domain services, because most of the use cases includes complex rules which can not be implemented in the domain objects. As a result, developers create anemic domain objects with minimum behavior. My advice is that developers shouldn't concentrate on the patterns of DDD. They should analyse Business Problem in depth and create a model which solves the problem by considering oop and solid rules. Immediately deciding to use domain service might lead to procedural code and service booming.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Note that you could also implement this logic on an entity. But you would need to pollute the domain model with external concerns to make it work.
@greglarden712
@greglarden712 11 ай бұрын
Thank you for the great content! This might be a bit contrived, but what if we think about the user in a following and followed context. The "user" means something different in this context, so would this highlight the need for another aggregate?
@tmstechschool7239
@tmstechschool7239 10 ай бұрын
Thanks for making this video. One thing I am not comfortable with is injecting the repository to Domain service which I prefer to have it on the Application layer/service then pass necessary domain objects to Domain Service. In such a way Domain service will only worried about common business logics across multiple domain entities. I hope you guys get my point, thank you.
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
You can return the entity from the Domain service, that's fine also
@jtesh
@jtesh 11 ай бұрын
milan, in zooming out, your normal stack would have the following: command handlers, repositories and now services. Ordinarily, your "domain service" logic would belong in a command handler. One would argue, that would make handlers obsolete, useless or redundant, do you have an opinion? maybe we can see a video on all of these together.
@Larry-bv6ds
@Larry-bv6ds 11 ай бұрын
THIS idk either what service layer is for exactly, when MediatR handlers are taking its responsibility basically, possibly it's a suitable place for smaller, repeatable pieces of business logic
@bogdanb904
@bogdanb904 11 ай бұрын
You are a bit wrong here. A command handler is usually an orchestrator and belongs in the Application Layer. A domain service would contain domain business logic that belongs to the Domain Layer and involves multiple Aggregates so it cannot be contained by a single Aggregate. At least, that's my take on it.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
This will all start making sense (hopefully) in the next few videos, so bear with me here. This domain service will be used from a use case in the Application layer.
@rosenpetrov4251
@rosenpetrov4251 11 ай бұрын
@@MilanJovanovicTech It is also kind of confusing for me when the MediatR Request/Handlers come in play. For example, ATM, I am working on a bunch of tasks where the goal is to refactor services into Request/Handlers. Basically, each method from the service goes into Request/Handler. The architect of the project is considering this more granular and better. But when it should stay as Service and when split in smaller pieces with CQRS?
@jtesh
@jtesh 11 ай бұрын
@@bogdanb904 sure, one can make that argument. but is it overkill for a small or medium project? 🤔
@xavier.xiques
@xavier.xiques 11 ай бұрын
First of all, good video, thank you very much 👏 But I don't quite agree with this. For me, this is a "use case" to manage followers. A domain service, in my opinion, should not access a repository, but should have only domain rules, but without external dependencies.
@xavier.xiques
@xavier.xiques 11 ай бұрын
@@Marfig When I wrote the post I was thinking more about Hexagonal Architecture, which is what I'm using more lately. And in H.A. the repositories are only accessible from use cases, and not from domain services. I won't argue with your point of view, as it doesn't seem to me incorrect at all, but maybe I would go more for mine today.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
This is a very debatable topic - whether a domain service should have access to a repository. Since my repository contracts are all declared in the domain, and they only work with domain entities/aggregates - I don't consider this a major issue.
@nikogj9495
@nikogj9495 11 ай бұрын
I don't see at first sight why it would be bad for domain services (or entities) to access repositories (via their interfaces) ? It seems legitimate that some entities would need checking other unrelated entities to accomplish their behaviour from time to time.
@xavier.xiques
@xavier.xiques 11 ай бұрын
​@@nikogj9495 I did not say that it is bad to access repositories from domain services. Simply that in some scenarios it is not done. Surely many of us have seen on many occasions services with methods that only make a call to a repository, without any other business rule. I believe that the "domain" is to have rules, if there are no rules, there is no need for domain.
@RicardoFerraris-z5v
@RicardoFerraris-z5v Ай бұрын
I agree. For me this is a regular Use Case. A proper Domain Service should not store anything, otherwise it becomes an Application Service/Use Case (like the one in the video). Another thing that I considered wrong is that I wouldn't put IsAlreadyFollowingAsync directly on the repository, it should be on a separate interface (even if it's implemented in the repository), otherwise we make it a data-access-related concern, when it actually is more like a business concern.
@dikizekopires3228
@dikizekopires3228 6 ай бұрын
First of all, thank you so much for share your content with us. I'm very interested in your architecture test implementation, please could you show how you've implemented the tests in this project?
@MilanJovanovicTech
@MilanJovanovicTech 6 ай бұрын
Check this out: - www.milanjovanovic.tech/blog/enforcing-software-architecture-with-architecture-tests - kzbin.info/www/bejne/m4jNf3-Pg7hgpck - kzbin.info/www/bejne/lXWZfJSfabeXfbs
@dikizekopires3228
@dikizekopires3228 6 ай бұрын
@@MilanJovanovicTech Tank you so much
@ryan-heath
@ryan-heath 11 ай бұрын
The event is raised before the entity is persisted in the database, that's a problem, or is it?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
It's only "raised" in memory - added to a list on the Entity. But you control when it's published - which should be after saving changes to DB.
@baranacikgoz
@baranacikgoz 11 ай бұрын
Generally, you override SaveChanges to dispatch events after persisting entitied to db
@pilotboba
@pilotboba 11 ай бұрын
Yes, "raise" is probably the wrong name here. More like queue event.
@Fikusiklol
@Fikusiklol 11 ай бұрын
Hey there, guys! :) From my perpective, a follower feels more like a ValueObject concept inside a User Entity in this context, rather than having a continuing life cycle of an Entity. And I would say that: 1) It's perfectly fine for a user to check if he's already following someone or not, as some business rule. 2) It's a user initiative to actually follow someone, thus creating a follower inside (as VO or even AR). However: 1) It's okay for creating a domain service to check for a public profile availabitity. 2) With my approach, I would probably run into perfomance problems for write operations quite fast. 3) I would not use repositories inside domain services, but rather just accept domain objects as an arguments for less mental overhead/testing Just my thoughts out loud. Good job nonetheless, waiting for your domain to mature and evolve :)
@pilotboba
@pilotboba 11 ай бұрын
But there are two sides to the relationship. A user has a list of people they follow. A user also has a list of people following them. A user might also have a block list. It almost seems to me that this should be a new type of entity... Relationship or something with a method to create a relationship between two users. Rather than a create followers domain service. But, so many ways to skin this cat.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Performance problems should be a good reason to move to a domain service
@Fikusiklol
@Fikusiklol 11 ай бұрын
@@pilotboba Now that I think about it - Entity (or most likely an AR) like FollowerList | BlockList are good candidates for that. Invariants, if there are any, could be forced by a domain service.
@Fikusiklol
@Fikusiklol 11 ай бұрын
@@MilanJovanovicTech I would say moving something to a separate resource like AR for perfomance is one of the reasons Aggregate Pattern exist
@orterves
@orterves 10 ай бұрын
5:31 I really really really don't like throwing exceptions for simple domain consistency checks. C# makes it clunky to do so, I know - but ideally this method should not be callable with data that isn't already in the correct state. But if the data does need validation, better than exceptions is using the Result pattern.
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
Quite a few opposing opinions on this video
@charlesopuoro5295
@charlesopuoro5295 4 ай бұрын
Milan, you sure do know your onions. Thank you so much.
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
I hope I didn't make you cry 😂
@charlesopuoro5295
@charlesopuoro5295 4 ай бұрын
😁😁😁@@MilanJovanovicTech
@Kasiux
@Kasiux 11 ай бұрын
Thanks for your service!
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Any time!
@mehdifarokhtabar4936
@mehdifarokhtabar4936 10 ай бұрын
Great video! However, there's something that bothers me in your implementation, specifically the insertion of data in the domain service. I prefer having my domain service method output the follower entity, allowing the application layer to handle the insertion task instead. what do you think about it?
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
That's an alternative I consiidered
@renedekkers735
@renedekkers735 11 ай бұрын
Thank you for making these videos. I think a lot of people benefit from them, me included. One question though. Why would you put the IsAlreadyFollowing check in a repository? That would mean you have to write them for every implementation unless you’ll put it in an extension method. The check itself also belongs to the domain right so why not put it in the domain service
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
That checks requires a database call, so I put it in the repository.
@jandersongoncalves6688
@jandersongoncalves6688 10 ай бұрын
Thanks for the video, help me a lot.
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
You're welcome!
@LeotrimJusufi
@LeotrimJusufi 10 ай бұрын
Hi Milan! Great video as always. I'm new to DDD and was wondering where/how to implement/inject the domain service. Do i create an interface for the service and inject it into the entity directly? Or do i inject the interface in the handler? And where do the interface and the implementation of the domain service reside?
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
Left my reply on another comment
@nikogj9495
@nikogj9495 11 ай бұрын
There is that something about repositories which I find sometimes unsettling but at the time I don't know how to solve for my own code: It's about ending having little domain logic inside repository implementations. Take the IsAlreadyFollowing method for example. The knowledge about "what makes a user being already followed" sounds more belonging to the domain. Unfortunately, that piece of logic (the "What") finds itself down in the implementation along with the "How" (the usage of the dbcontext). But at the same time: Changing the method by adding a parameter of Expression looks like leaking implementation detail. Changing the method by a specification pattern looks overkill. Changing the method with by returning (fetching) all entities and execute the where clause inside the domain service would hurt performance badly. So... ?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
So just accept that small "tradeoff" and enjoy the benefits of good performance. Beats the other approaches IMO
@danilousuga410
@danilousuga410 10 ай бұрын
What program do you use for modeling your components? I really like how it looks like. Thanks Milan, again, nice video!
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
Excalidraw?
@danilousuga410
@danilousuga410 10 ай бұрын
@@MilanJovanovicTech Thank you so much.
@rlyonsiii
@rlyonsiii 11 ай бұрын
Hi Milan, Quick Question, what is the reason to pass the createdOnUtc to the Create method instead of just instantiating it directly in the Create method? Just curious. Thx.
@secretaccount3842
@secretaccount3842 11 ай бұрын
When you're trying to test the creation of two entities, if you insert the creation date inside of the constructor, when comparing there will be a microsecond different and the test will fail. That's my guess.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Testability
@richardhaughton9633
@richardhaughton9633 11 ай бұрын
I really don't like the parameterless constructor used by EF. Is there any way to bypasse this constructor? maybe with configurations?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
It doesn't bother me too much. Never tried bypassing it.
@DieDona
@DieDona 11 ай бұрын
as it is private, it is merely a concern of implementation. i also dont like it, but it is the payoff for having an ORM :)
5 ай бұрын
Amazing, Milan. Very interesting. One question, what is the colour theme for look the functions/variables/methods like this?? Thanks!
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
ReSharper syntax highlighting
@sameerpanicker7452
@sameerpanicker7452 11 ай бұрын
Milan, services are only meant to handle business logics or it can also be used to connect to other domains / repos ?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
If the repository serve to implement the business logic, then I consider it to be fine
@robertmarriott1008
@robertmarriott1008 Ай бұрын
Great video! Sorry if you've already covered this in another video, but how would one handle checking if a Sku property is unique on a Product entity, say we don't want the client to create two different products with the same SKU. Would I create an IProductService interface with an IsSkuUnique() method? If so, wouldn't I have to pass that into the constructor or factory Create() method of Product so I can call IsSkuUnique() as a guard clause before assigning/updating the Sku property? Similarly, if my domain model has two aggregates, Category and Product, should I check if the CategoryId exists before setting Product.CategoryId? If so, wouldn't that require a domain service as well? Or, do we only worry about this in the application layer?
@MilanJovanovicTech
@MilanJovanovicTech Ай бұрын
Uniqueness is something I like to handle with database constraints, it's the safest approach. For the latter one, I'd most likely start with doing that in the application layer and refactor if needed.
@robertmarriott1008
@robertmarriott1008 Ай бұрын
@@MilanJovanovicTech Thanks!
@andreyka26_se
@andreyka26_se 10 ай бұрын
I guess it is a bit misused. According to Blue and Red books, Domain service is needed when you need to take actions on 2 aggregated roots. All other cases should be handled by the application service or inside the Aggregated root.
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
User/Follower can be treated as separate aggregates
@RMarjanovic
@RMarjanovic 11 ай бұрын
I dont follow how to use the service itself? Do you create it in your use case (ie application layer)? Create a singleton instance of it in startup and inject it with dependency injection or what would you propose?
@RMarjanovic
@RMarjanovic 11 ай бұрын
@@MarfigMeaning that you would create a new instance of the service within a domain entity to actually call the method on the service?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Yes, you would create (or rather inject it) from a use case in the Application layer. Video on that incoming. :)
@neilhargis8120
@neilhargis8120 5 ай бұрын
@@MilanJovanovicTech Did you ever make this video? I can't seem to find it.
@davorzganjer5291
@davorzganjer5291 10 ай бұрын
Can you please give some argument as to why the User or/and Follower business logic doesn't belong to any of the entities? Why in this example user/follower stands out from the other entities?
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
I have to use an external service (repository) to implement the logic. I wouldn't place this logic in the entity.
@davorzganjer5291
@davorzganjer5291 7 ай бұрын
@@MilanJovanovicTech going again through the video and having a deeper knowledge of DDD itself, I'd assume that a repository to store the data should be injected in the application service along with a domain service from where the applications service will orchestrate storing the data.
@Metalyga
@Metalyga 11 ай бұрын
Looks like modern style of DDD leans toward Domain Service becoming usecases with validation engines/buisness rules and entitles are becoming POCO again. 😅
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Wait for the next few videos 😉
@WahidRezgui
@WahidRezgui 11 ай бұрын
Hy thanks for the video. It looks like a use case inside application layer where a user is following another user
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
It could also be implemented as a use case, yes. However, I chose to keep the logic inside the domain layer.
@programedegraca
@programedegraca 11 ай бұрын
Excelente conteúdo, parabéns !
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Glad you enjoyed it :)
@junior.santana
@junior.santana 10 ай бұрын
Mandou um português mesmo rsrs
@programedegraca
@programedegraca 10 ай бұрын
@@junior.santana E tive resposta.
@TheAlien1900
@TheAlien1900 11 ай бұрын
Where is the unit of work called?
@lehoang2242
@lehoang2242 11 ай бұрын
I have a same question. Will we call the unitofwork inside the domain services?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
The domain service will be used in the use case, and that's where the unit of work will be called also
@sas-tube
@sas-tube 11 ай бұрын
Can follower entity should be an sub entity of the user entity? So user will have the list of his followers
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
And what if that list contains 100,000 followers?
@roberteru25
@roberteru25 10 ай бұрын
​​@@MilanJovanovicTechI believe you can load the user without including the followers entity via EF core, and you can also load users follower differently.
@roberteru25
@roberteru25 10 ай бұрын
​@@MilanJovanovicTechcan I see the relationship configuration between the user and the follower entity ?
@DiegoHammesHoffmann
@DiegoHammesHoffmann Ай бұрын
Perfect
@MilanJovanovicTech
@MilanJovanovicTech Ай бұрын
Thanks
@celiannelemaat9914
@celiannelemaat9914 10 ай бұрын
Is it allowed within DDD to inject a domain service inside a AggregateRoot? For example i have dynamic roles and i want to check inside a RoleService if the name is unique. Could i reference that service within the Role aggregate? So i have a method inside the role thats called ChangeName which checks by calling the role service if the name is unique, if so it updates the new name. This way you contain all the business logic inside the Role aggregate.
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
Take a look at this: kzbin.info/www/bejne/m3SaeIB9frdnfdk
@syedkazimraza6769
@syedkazimraza6769 10 ай бұрын
I wanted to ask one question. Could be dumb lol. So If I have domain services in my domain layer and now I want to pass it to my event handlers using DI but my dependency injection configuration is in API layer which communicates with the Application layer and there is no communication between my Api layer and Domain layer. Now how do I configure DI in Api layer while my interfaces and implementation for the domain services exist in the domain layer?
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
Register them from the Api/Application layers? It's just a call to service.AddTransiet/AddScoped
@syedkazimraza6769
@syedkazimraza6769 10 ай бұрын
@@MilanJovanovicTech Cool. Thanks for that. I need a suggestion please. I have web app where user can upload images and images are part of an aggregate and images are local entity to that aggregate. Now I am adding image through aggregate root and when I add image through aggregate root then it has no url because its not been uploaded yet to S3 and and is added to the list of images for the aggregate where url is empty and then aggregate root raises event and then in the event handler I use upload service to upload image to amazon S3 and if S3 upload is successful then update image url and if amazon S3 fails then I remove image from aggregate. It just doesn't feel the right to me to add images this way. I was initially doing uploading and then adding image to aggregate part all without event handler and but in that case also I have to create imageId explicitly to give to S3 service and then use that to create image record becauae i want to match image id with image name on S3 and that didn't feel right to me as well.
@alexramossilva
@alexramossilva 10 ай бұрын
Really good videos. One question, what happen if you set a domain event, that happens when you create a new instance but you have an exception later, like a database error or similar, your event will already be dispatched. For example you try to follow someone, it passes the validations , you instantiate the follower, which triggers a domain event, then it sends the notification, but it then fails when persisting on the DB the following. Is that ok?
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
I dispatch the event after saving changes in DB
@ramytawfik9168
@ramytawfik9168 9 ай бұрын
What is the meaning of side effect please ?
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
Something that occurs after you trigger the main event
@ramytawfik9168
@ramytawfik9168 9 ай бұрын
@@MilanJovanovicTech thanks a lot my friend
@MiguelAlves-pr7fu
@MiguelAlves-pr7fu 10 ай бұрын
Vamosmanocu
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
🤔
@josemi_MS
@josemi_MS 11 ай бұрын
Domain Services shouldn't have dependencies. The responsability of store data should be outside the service, so the repository should be out.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
I disagree. And if you read Evans' DDD book, he states that domain services "are allowed to have side effects"
@RoelDieltjens
@RoelDieltjens 11 ай бұрын
Agree, for me this is more an example of an application service. Domain services live in the domain which means that they do not have external dependencies.
@nikogj9495
@nikogj9495 11 ай бұрын
The storing of data is not done inside the Insert call of the repository; The actual storing is done when calling the Savechanges on the unit of work...in the application layer.
@josemi_MS
@josemi_MS 11 ай бұрын
@@nikogj9495 Yes, you're right, my bad. My question is if Domain Service should know about the repository or not.
@xxXAsuraXxx
@xxXAsuraXxx 9 ай бұрын
Instead of throwing exception for the if check. You should use Results pattern
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
You don't say? kzbin.info/www/bejne/jXSmnHiblK2saLs
@techpc5453
@techpc5453 10 ай бұрын
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
👋
Mapping Domain-Driven Design Concepts To The Database With EF Core
18:06
Milan Jovanović
Рет қаралды 51 М.
Why use Type and not Interface in TypeScript
14:12
ByteGrad
Рет қаралды 208 М.
Крутой фокус + секрет! #shorts
00:10
Роман Magic
Рет қаралды 28 МЛН
Get Rid of Exceptions in Your Code With the Result Pattern
13:06
Milan Jovanović
Рет қаралды 51 М.
How To Use Domain-Driven Design In Clean Architecture
30:27
Milan Jovanović
Рет қаралды 109 М.
The Problem With Microservices
17:47
Continuous Delivery
Рет қаралды 434 М.
Design First APIs and Domain-Driven Design - Ljubica Lazarevic - DDD Europe 2022
24:00
Domain-Driven Design Europe
Рет қаралды 10 М.
Domain Driven Design: What You Need To Know
8:42
Alex Hyett
Рет қаралды 127 М.
Is an Anemic Domain Model an Anti-Pattern?
9:54
Milan Jovanović
Рет қаралды 22 М.
"I NEED data from another service!"...  Do you really?
10:41
CodeOpinion
Рет қаралды 32 М.
Крутой фокус + секрет! #shorts
00:10
Роман Magic
Рет қаралды 28 МЛН