What is a Domain Service in Domain-Driven Design?

  Рет қаралды 23,416

Milan Jovanović

Milan Jovanović

Күн бұрын

Пікірлер: 122
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@o.boyraz
@o.boyraz Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
You can return the entity from the Domain service, that's fine also
@kodindoyannick5328
@kodindoyannick5328 3 ай бұрын
Great video! Thanks Milan!
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
Glad you liked it!
@Kasiux
@Kasiux Жыл бұрын
Thanks for your service!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Any time!
@jtesh
@jtesh Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
@@bogdanb904 sure, one can make that argument. but is it overkill for a small or medium project? 🤔
@jandersongoncalves6688
@jandersongoncalves6688 Жыл бұрын
Thanks for the video, help me a lot.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You're welcome!
@orterves
@orterves Жыл бұрын
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 Жыл бұрын
Quite a few opposing opinions on this video
@Fikusiklol
@Fikusiklol Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
Performance problems should be a good reason to move to a domain service
@Fikusiklol
@Fikusiklol Жыл бұрын
@@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 Жыл бұрын
@@MilanJovanovicTech I would say moving something to a separate resource like AR for perfomance is one of the reasons Aggregate Pattern exist
@dikizekopires3228
@dikizekopires3228 10 ай бұрын
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 10 ай бұрын
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 10 ай бұрын
@@MilanJovanovicTech Tank you so much
@xavier.xiques
@xavier.xiques Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
​@@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 5 ай бұрын
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.
@charlesopuoro5295
@charlesopuoro5295 8 ай бұрын
Milan, you sure do know your onions. Thank you so much.
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
I hope I didn't make you cry 😂
@charlesopuoro5295
@charlesopuoro5295 8 ай бұрын
😁😁😁@@MilanJovanovicTech
@ryan-heath
@ryan-heath Жыл бұрын
The event is raised before the entity is persisted in the database, that's a problem, or is it?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
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 Жыл бұрын
Generally, you override SaveChanges to dispatch events after persisting entitied to db
@pilotboba
@pilotboba Жыл бұрын
Yes, "raise" is probably the wrong name here. More like queue event.
@bartoszpiasecki8187
@bartoszpiasecki8187 Ай бұрын
I have question: If FollowerService is Domain Service Should it implement/validate business rules between objects like aggregates? would be better call persistence method into handler?
@MilanJovanovicTech
@MilanJovanovicTech Ай бұрын
Am I not validating business rules here?
@mehdifarokhtabar4936
@mehdifarokhtabar4936 Жыл бұрын
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 Жыл бұрын
That's an alternative I consiidered
@LeotrimJusufi
@LeotrimJusufi Жыл бұрын
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 Жыл бұрын
Left my reply on another comment
@thedacian123
@thedacian123 Ай бұрын
StartFollowing logic seems to be a use case. Is it more suitable that this logic to stay in application layer not domain layer(i assuming that you are foloowing clean architecture).?
@MilanJovanovicTech
@MilanJovanovicTech Ай бұрын
You can have it either way
@renedekkers735
@renedekkers735 Жыл бұрын
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 Жыл бұрын
That checks requires a database call, so I put it in the repository.
@RMarjanovic
@RMarjanovic Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
Yes, you would create (or rather inject it) from a use case in the Application layer. Video on that incoming. :)
@neilhargis8120
@neilhargis8120 9 ай бұрын
@@MilanJovanovicTech Did you ever make this video? I can't seem to find it.
@rlyonsiii
@rlyonsiii Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
Testability
@richardhaughton9633
@richardhaughton9633 Жыл бұрын
I really don't like the parameterless constructor used by EF. Is there any way to bypasse this constructor? maybe with configurations?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
It doesn't bother me too much. Never tried bypassing it.
@DieDona
@DieDona Жыл бұрын
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 :)
@sameerpanicker7452
@sameerpanicker7452 Жыл бұрын
Milan, services are only meant to handle business logics or it can also be used to connect to other domains / repos ?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
If the repository serve to implement the business logic, then I consider it to be fine
@programedegraca
@programedegraca Жыл бұрын
Excelente conteúdo, parabéns !
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Glad you enjoyed it :)
@junior.santana
@junior.santana Жыл бұрын
Mandou um português mesmo rsrs
@programedegraca
@programedegraca Жыл бұрын
@@junior.santana E tive resposta.
@DiegoHammesHoffmann
@DiegoHammesHoffmann 5 ай бұрын
Perfect
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
Thanks
@danilousuga410
@danilousuga410 Жыл бұрын
What program do you use for modeling your components? I really like how it looks like. Thanks Milan, again, nice video!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Excalidraw?
@danilousuga410
@danilousuga410 Жыл бұрын
@@MilanJovanovicTech Thank you so much.
@nikogj9495
@nikogj9495 Жыл бұрын
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 Жыл бұрын
So just accept that small "tradeoff" and enjoy the benefits of good performance. Beats the other approaches IMO
@robertmarriott1008
@robertmarriott1008 5 ай бұрын
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 5 ай бұрын
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 5 ай бұрын
@@MilanJovanovicTech Thanks!
9 ай бұрын
Amazing, Milan. Very interesting. One question, what is the colour theme for look the functions/variables/methods like this?? Thanks!
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
ReSharper syntax highlighting
@andreyka26_se
@andreyka26_se Жыл бұрын
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 Жыл бұрын
User/Follower can be treated as separate aggregates
@davorzganjer5291
@davorzganjer5291 Жыл бұрын
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 Жыл бұрын
I have to use an external service (repository) to implement the logic. I wouldn't place this logic in the entity.
@davorzganjer5291
@davorzganjer5291 11 ай бұрын
@@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.
@WahidRezgui
@WahidRezgui Жыл бұрын
Hy thanks for the video. It looks like a use case inside application layer where a user is following another user
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
It could also be implemented as a use case, yes. However, I chose to keep the logic inside the domain layer.
@celiannelemaat9914
@celiannelemaat9914 Жыл бұрын
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 Жыл бұрын
Take a look at this: kzbin.info/www/bejne/m3SaeIB9frdnfdk
@sas-tube
@sas-tube Жыл бұрын
Can follower entity should be an sub entity of the user entity? So user will have the list of his followers
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
And what if that list contains 100,000 followers?
@roberteru25
@roberteru25 Жыл бұрын
​​@@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 Жыл бұрын
​@@MilanJovanovicTechcan I see the relationship configuration between the user and the follower entity ?
@syedkazimraza6769
@syedkazimraza6769 Жыл бұрын
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 Жыл бұрын
Register them from the Api/Application layers? It's just a call to service.AddTransiet/AddScoped
@syedkazimraza6769
@syedkazimraza6769 Жыл бұрын
@@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.
@TheAlien1900
@TheAlien1900 Жыл бұрын
Where is the unit of work called?
@lehoang2242
@lehoang2242 Жыл бұрын
I have a same question. Will we call the unitofwork inside the domain services?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
The domain service will be used in the use case, and that's where the unit of work will be called also
@ramytawfik9168
@ramytawfik9168 Жыл бұрын
What is the meaning of side effect please ?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Something that occurs after you trigger the main event
@ramytawfik9168
@ramytawfik9168 Жыл бұрын
@@MilanJovanovicTech thanks a lot my friend
@Metalyga
@Metalyga Жыл бұрын
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 Жыл бұрын
Wait for the next few videos 😉
@alexramossilva
@alexramossilva Жыл бұрын
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 Жыл бұрын
I dispatch the event after saving changes in DB
@MiguelAlves-pr7fu
@MiguelAlves-pr7fu Жыл бұрын
Vamosmanocu
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
🤔
@josemims
@josemims Жыл бұрын
Domain Services shouldn't have dependencies. The responsability of store data should be outside the service, so the repository should be out.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I disagree. And if you read Evans' DDD book, he states that domain services "are allowed to have side effects"
@RoelDieltjens
@RoelDieltjens Жыл бұрын
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 Жыл бұрын
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.
@josemims
@josemims Жыл бұрын
@@nikogj9495 Yes, you're right, my bad. My question is if Domain Service should know about the repository or not.
@techpc5453
@techpc5453 Жыл бұрын
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
👋
Get Rid of Exceptions in Your Code With the Result Pattern
13:06
Milan Jovanović
Рет қаралды 59 М.
Mapping Domain-Driven Design Concepts To The Database With EF Core
18:06
Milan Jovanović
Рет қаралды 57 М.
Quilt Challenge, No Skills, Just Luck#Funnyfamily #Partygames #Funny
00:32
Family Games Media
Рет қаралды 55 МЛН
1% vs 100% #beatbox #tiktok
01:10
BeatboxJCOP
Рет қаралды 67 МЛН
Quando A Diferença De Altura É Muito Grande 😲😂
00:12
Mari Maria
Рет қаралды 45 МЛН
Леон киллер и Оля Полякова 😹
00:42
Канал Смеха
Рет қаралды 4,7 МЛН
Domain Driven Design: What You Need To Know
8:42
Alex Hyett
Рет қаралды 158 М.
How to design great Aggregate Roots in Domain-Driven Design
11:30
Milan Jovanović
Рет қаралды 18 М.
I Spent 100 Hours Inside The Pyramids!
21:43
MrBeast
Рет қаралды 36 МЛН
Coding a Web Server in 25 Lines - Computerphile
17:49
Computerphile
Рет қаралды 363 М.
Modeling a Domain With Domain-Driven Design From Scratch | DDD
19:10
Milan Jovanović
Рет қаралды 97 М.
Real 10x Programmers Are SLOW To Write Code
14:51
Thriving Technologist
Рет қаралды 73 М.
How To Use Domain-Driven Design In Clean Architecture
30:27
Milan Jovanović
Рет қаралды 116 М.
Quilt Challenge, No Skills, Just Luck#Funnyfamily #Partygames #Funny
00:32
Family Games Media
Рет қаралды 55 МЛН