Aggregate Root Design 101 | DDD, Clean Architecture, .NET 6

แชร์
ฝัง
  • เผยแพร่เมื่อ 9 พ.ย. 2024

ความคิดเห็น • 136

  • @MilanJovanovicTech
    @MilanJovanovicTech  2 ปีที่แล้ว +4

    Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
    Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt

  • @zikkrype
    @zikkrype 2 ปีที่แล้ว +4

    Nice one man. It's really cool that someone explains such stuff to the people who are not familiar with this yet. I with there were such videos when I was investigating this topic

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว

      At least we have this for the future generations. Right? :)

    • @zikkrype
      @zikkrype 2 ปีที่แล้ว +1

      @@MilanJovanovicTech definitely)

  • @marna_li
    @marna_li 2 ปีที่แล้ว +6

    Great video! I have a couple of questions:
    1. What if Gathering is having 1000+ Invitations? Is it wise to fetch the entire Aggregate?
    2. When dispatching domain events before committing changes to the DB. How do we handle Email/NotificationService correctly if case committing afterwards fails?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +3

      1. I already mentioned in a few other comments 😅
      One solution can be filtered include.
      2. Coming up in next video 🕜
      What is "afterwards" in your case?

    • @marna_li
      @marna_li 2 ปีที่แล้ว +1

      @@MilanJovanovicTech
      1. You mean that in retrieving the aggregate, I add a condition on what related data to include? .Include(gathering => gathering.Invitations.Where(x => x.DateSent < date)) ?
      That would work!
      2. My domain events are dispatched before persisting the changes to the DB. If you trigger sending an email. How would you handle that if the save fails? Sent a new e-mail? Perhaps acceptable in this case if requierments call for it.
      I’m looking forward to your upcoming video!

    • @marna_li
      @marna_li 2 ปีที่แล้ว +1

      @@MilanJovanovicTech I gave it a through. When pre-dispatching events (before saving changes), instead of calling the e-mailservice directly you put the action in an outbox that can be committed after successfully saving the changes, as with integration events. My worries is about how to make that clean.

    • @sudhirpatil8217
      @sudhirpatil8217 2 ปีที่แล้ว +1

      I got my question answered so will delete my comment. Thank you both!!!,😊

  • @ransandu
    @ransandu 2 ปีที่แล้ว +3

    Thanks Milan for this great series of DDD. Much appreciated your effort!

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +2

      Thanks a lot. I'm quite enjoying making it! There is still a few more videos in the DDD series left 😁

  • @emiraksoy1520
    @emiraksoy1520 2 ปีที่แล้ว +4

    was waiting for Aggregate Root Design thx so much

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +1

      I hope I managed to convey the topic properly!

  • @zutafe
    @zutafe 2 ปีที่แล้ว +1

    Wait for the next ep., very interesting topic

  • @andrewseaton5727
    @andrewseaton5727 2 ปีที่แล้ว +1

    On first looking at the project, I would think that a Member sends an invitation. Understanding that the Gathering is sending the invitation (and managing the attendees) makes perfect sense but isn’t obvious to a newbie like me so thank you.

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว

      The question to ask in that case would be: "Who owns the invitation"?
      Is the the Member?
      Or the Gathering?
      I decided on Gathering. You may come to a different conclusion. And we could both be right 😁

    • @vitalyvolovodenko3473
      @vitalyvolovodenko3473 ปีที่แล้ว

      @@MilanJovanovicTech We model objects of real life so it is impossible for "gathering" to send invitations.....maybe this is responsibility of creator

  • @tanvirarjel
    @tanvirarjel 2 ปีที่แล้ว +4

    Let's say, Post is the AggregateRoot and Comments are the children of Post. A post can have thousands of comments. How would you update a comment through the AggregateRoot? Obviously not pulling all the comments into memory just for updating a single comment. I think we should use filtered include for the children.

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +2

      Filtered incldue definitely solve this problem, that's a great suggestion. But what I didn't cover in this video is that you have consider performance when designing Aggregates.
      In your example, performance would be severely degraded if we used Post as the AggregateRoot.
      The proper approach would be to have the Comment reference the Post by FK.
      That way we can only fetch that Comment, and modify it.
      We wouldn't have a "real" Aggregate,

    • @fbsouza
      @fbsouza 2 ปีที่แล้ว +1

      This scenario maybe implemented by domain events. In post you may fire commentUpdated event and intercept this event to do the update.

    • @darksinge
      @darksinge ปีที่แล้ว

      The way I understand it is the aggregate root is meant to enforce invariants within the aggregate cluster and ensure they're accessed and modified in a consistent and controlled manner. The root protects the boundary around the aggregate cluster, which doesn't necessarily mean loading a ton of data just to modify bits of data.

  • @Yosso117
    @Yosso117 ปีที่แล้ว +3

    Братан, хорош, давай, давай, вперёд! Контент в кайф, можно ещё? Вообще красавчик! Можно вот этого вот почаще?

  • @javiermayorga9857
    @javiermayorga9857 ปีที่แล้ว +1

    Hi Milan which book do you recommend to learn more about this topic?

  • @100kshooter5
    @100kshooter5 2 ปีที่แล้ว +2

    So choosing an aggregate is mainly based on responsibility of the class. What you can identify as a single process and you treat those objects as one unit?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว

      There's a bit more nuance to it. But that's the general idea. It's hard to define a set of rules. It kind of evolves on it's own as you build out the project.

  • @luisfalcon1822
    @luisfalcon1822 2 ปีที่แล้ว +3

    I got the idea to maintain consistency in DDD, but performance is still an issue if I pull all that information from database. Some others folks also pointed that out here.

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +8

      Absolutely, DDD should never be followed to the letter. You must be *pragmatic*. If you have a collection with a tendency to grow extremely large: post-comments (Reddit). Then we can throw out this design out the window.
      I'm really glad so many people are commenting about performance - it means I have good engineers watching these videos 😁

    • @LucasSantos-yw4nh
      @LucasSantos-yw4nh 2 ปีที่แล้ว +1

      ​@@MilanJovanovicTech I think another way to reduce the complexity is what Eric Evans says about associations in the blue book. He says that there are at least three ways of making associations more tractable:
      1) Imposing a traversal direction
      2) Adding a qualifier, effectively reducing multiplicity
      3) Eliminating nonessential associations
      In that case I believe number 2 may help to reduce the number of "valid" invitations. But I would appreciate a Milan´s video about it haha

  • @roeiohayon4501
    @roeiohayon4501 ปีที่แล้ว +1

    I wonder, lets say i am trying to model the problem of doing some business operations on historical stock data, so a stock is basically a symbol (for example AMZN), and a time series that represents the data of that stock. Often we want to query and do operations on the stock data based on symbols, so ultimately my question is, should symbol also be an aggregate root, alongside with stock? If not, should i still have two separate repositories? If so, should I create a repository that encapsulates both of them? How would you go about handling this situation

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      I'd choose the approach that's easier to work with in terms of:
      - Storing data
      - Querying data
      Symbols are just like an enum value, right? They don't change much. You're more interested in the time series data of the stocks price changing over time.

    • @roeiohayon4501
      @roeiohayon4501 ปีที่แล้ว

      @@MilanJovanovicTech I see, in my case, I want to allow the functionality of assigning tag to symbols, for example: S&P 500, bad stock, etc.
      So I think it is more fitting that the symbols would also be aggregates, as they are more complicated than a simple string, and also, while it is true that they don't really change overtime, I don't want to assume they are always existing in my DB, as I'd assume all enum values are in an enum

  • @goorn4489
    @goorn4489 ปีที่แล้ว +1

    Don't we need to specify parameterless private constructor to let Entity Framework create an object of specific Entity ? But we should pass an Id to the constructor of the base class using your approach. How do you handle that ? Do you use specific Entity within DbContext?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      In most cases EF can get by with a constructor that has some params, like the one with the ID and use the properties to fill in the rest

  • @solarmatica
    @solarmatica 2 ปีที่แล้ว +1

    Thanks Milan! Which tool do you use for model diagram?

  • @lostinsarajevo
    @lostinsarajevo ปีที่แล้ว +1

    Hi, watching this a bit later :D
    Any reason for not using SingleOrDefault on the gathering.Invitations?

  • @justgame5508
    @justgame5508 ปีที่แล้ว +2

    If your only reading data, why is consistency and issue? Surely an aggregate is for only write actions, read actions should be allowed outside the aggregate if that functionality is necessary (I.e. you only care about a small subset of the aggregate data in some scenario)? If I want to list to the user all invitations for whatever reason, surely I shouldn’t have to pull that through the aggregate?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      That's a query - and it's a separate concern from the Domain

    • @justgame5508
      @justgame5508 ปีที่แล้ว

      @@MilanJovanovicTech ahhh I must have misunderstood the video I thought you was talking about both commands and queries

  • @nicolasundiano8406
    @nicolasundiano8406 ปีที่แล้ว +1

    Hi Milan
    in the case that we have to return a dto to the client with data of multiples aggregates, how we can do that without doing multiple queries to the db? because we cant retrieve that data in one single query because the aggregates are not related in the properties so we cant include that data

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      You just do multiple queries to the DB 🤷‍♂️

  • @luan_maik
    @luan_maik 2 ปีที่แล้ว +2

    Great video. Could you explain us an alternative aproach to the case where has hundreds/thousands of Invitations, would you separate again?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +2

      Excellent question! Yes, definitely this does not hold in such a case. You couldn't have a collection so large in that case.
      You would have to make Invitations reference Gathering, to make the solution peformant.
      It's a lengthy discussion. I will try to find you some good reading resources, if there are any. Or just create a separate video on the topic.

  • @user-rp9iis1en6h
    @user-rp9iis1en6h ปีที่แล้ว +1

    I am trying to learn the aggregate root patterns but it seems hard for now. Can you please list down the tutorial links from beginning to intermediate so that we can follow them? For example in this video I can see u are adding Aggregate but what are value objects, Entity, how did u add them and which tutorial will show these things?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      There's a playlist which you can follow on my channel and it goes over everything in order

  • @René-k5i
    @René-k5i 17 วันที่ผ่านมา

    Hi Milan, since Gathering is the aggregate root, I'm confused that Member knows about the Id of the Invitation. Components outside of the aggregate should not be allowed to reference Ids of non-root entities.

    • @MilanJovanovicTech
      @MilanJovanovicTech  16 วันที่ผ่านมา

      | Components outside of the aggregate should not be allowed to reference Ids of non-root entities.
      Why not?

    • @René-k5i
      @René-k5i 16 วันที่ผ่านมา

      @@MilanJovanovicTech According to Evans: Now, to translate that conceptual AGGREGATE into the implementation, we need a set of rules to apply to all
      transactions:
      • The root ENTITY has global identity, and is ultimately responsible for checking invariants.
      • Root ENTITIES have global identity. ENTITIES inside the boundary have local identity, unique only
      within the AGGREGATE.
      • Nothing outside the AGGREGATE boundary can hold a reference to anything inside, except to the root
      ENTITY. The root ENTITY can hand references to the internal ENTITIES to other objects, but those objects
      can only use them transiently, and may not hold onto the reference. The root may hand a copy of a
      value to another object, and it doesn’t matter what happens to it, since it’s just a value and no longer
      will have any association with the AGGREGATE

  • @Ahmed-ui5wn
    @Ahmed-ui5wn ปีที่แล้ว +1

    Thanks for the series. Informative content. I have a small question: Can I just use the aggregate pattern in Clean Architecture without using DDD (no events etc..).

  • @prabhpahul
    @prabhpahul 2 ปีที่แล้ว +1

    Hello Milan, thank you for informative video. Quick question, how would you handle ForiegnKey relations with other aggregates inside? Should we use Keys or actual entities?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว

      Aggregates should only reference other aggregates. So for sure use FK

  • @justind6983
    @justind6983 2 ปีที่แล้ว +1

    What if you want to display the available gathering types in the Ui before you create a gathering? I see a need to get all types without going through the aggregate root, right?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว

      Gathering types being an enum, you can easily return them via some endpoint. Or even replicate the enum on the frontend (assuming it's a separate application)

    • @tafs7
      @tafs7 2 ปีที่แล้ว +3

      I think this is where the concept of separation of commands and queries (CQRS) comes in handy. Querying the DB to read data for presenting in UI should not be handled by your aggregate repositories. You should instead use either raw SQL (executed via EF or Dapper), or create new query specification types for just that use case, and if you must use EF dbsets, I suggest you use a separate "read-only" dbcontext for your queries that power the views (MVC) or http GET API calls (web API). Then in this read-only ("AsNoTracking()") dbcontext, you can expose DbSets for all tables that you need to query directly, knowing you will never need a change tracker for this dbcontext as it is meant for presentation queries only.
      Only use your aggregates and repositories for use cases that modify data in the DB (aka, "commands"), because that's when you need the transactional consistency. Then you can limit your exposed DbSet properties on this DbContext, to only where T: AggregateRoot .

  • @fernandocalmet
    @fernandocalmet 2 ปีที่แล้ว +1

    Great content! thank you Milan

  • @vertikalniserklaz8694
    @vertikalniserklaz8694 7 หลายเดือนก่อน

    Milan, if the requirement is to delete an order item that belongs to the Order aggregate normally we would access the corresponding method from the aggregate, but in DDD are we considering this as an Update (whole aggregate) or DeleteOrderItem? What would be the implementation detail of it within aggregate root assuming that we know to persist this scenario against DB? In my head this is Update aggregate and would use Update method from the aggregate but also could be RemoveChildItem.

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 หลายเดือนก่อน

      What does it change?

    • @vertikalniserklaz8694
      @vertikalniserklaz8694 6 หลายเดือนก่อน

      @@MilanJovanovicTech While doing remove an order item the action represents the aggregate change.

  • @thecodeman_
    @thecodeman_ 2 ปีที่แล้ว +1

    Hey Milan, great video! So this practically means you can manipulate the whole hierarchy only through the main object?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +1

      Yes, that is the idea behind the pattern. Designing a proper Aggregate is a science, to be honest. You can never get it quite right.

  • @ugochukwuumerie6378
    @ugochukwuumerie6378 2 ปีที่แล้ว +1

    Great video

  • @mohammedessaddek8175
    @mohammedessaddek8175 ปีที่แล้ว +1

    Hello Milan, thank you for those videos,
    I have this business need and I am a little bit confused about using aggregates:
    I have a step (that belongs to the destination aggregate) each step has a reference to a city.
    I have an address which reference also a city.
    the address exists in more than one table,
    should the address be in a separate aggregate? how to manage aggregate boundaries in this case?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      Typically an address is a value object, but in your system it seems like it's an entity since you're working with destinations.
      From what you said - the address existing in multiple tables - implies you are using it as a value object.
      I'd be cautious with giving you advice from just your short description. Maybe you can show me some class diagram?

    • @mohammedessaddek8175
      @mohammedessaddek8175 ปีที่แล้ว

      @@MilanJovanovicTech I can't upload an image, where can i share the class diagram

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      @@mohammedessaddek8175 LinkedIn/Twitter

  • @rudinandrey
    @rudinandrey ปีที่แล้ว +1

    intersting video, thanks. What is the font in your IDE editor ?

  • @vasthestampede
    @vasthestampede ปีที่แล้ว +1

    Is it really prohibited to fetch entities that fall under aggregate separately?
    I though that this rule applies only to write operations, whereas for read operations you can do whatever you want

  • @camilotorresc.2046
    @camilotorresc.2046 ปีที่แล้ว +1

    Thanks for this great video! Great work!
    In case you need to load a gathering with the member information (Email, First Name, Last Name) of the attendees, will you hold a reference to the Member entity on the Attendee collection? Or do you think it is better to have another abstraction that represents the Member information on the Attendee entity? Or just having in the query handler a reference to the dbContext and constructing the query without loading aggregate?

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      Plain and simple, if it gets the job done. So go with Member reference on Attendee

  • @sfjadi
    @sfjadi 10 หลายเดือนก่อน +1

    Are you offering any coupon for the course?

  • @huynhtriet444
    @huynhtriet444 ปีที่แล้ว +1

    Hi Milan, great video again. I just want to ask about refactoring legacy code with anemic domain model. I want to apply your teachings towards creating rich domain model but some of these concepts about aggregates are quite complicated so I think I need to spend more time practicing. Would it be a good first step to just move domain logic out of the handler method and into the domain model first without aggregate design and such? Thanks!

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว +1

      That would be a wonderful first step, yeah. Domain modeling doesn't have to be one-and-done. It's an evolution.

  • @cmartinez4727
    @cmartinez4727 2 ปีที่แล้ว +1

    But what happens when you want to delete, say, an invitation? Does the client have to include both the gatheringid and the invitationid in the request? If so, does this mean you can’t create a restful api (where you send a delete method with just a single id)?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +1

      That depends what is RESTful to you? I think this is a good route:
      DELETE api/gatherings/{gatheringId}/invitations/{invitationId}

    • @cmartinez4727
      @cmartinez4727 2 ปีที่แล้ว +1

      @@MilanJovanovicTech that’s a good point

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +1

      @@cmartinez4727 Not to say the other approach would be wrong.
      There's more than one way to design this 😁

  • @tantruongthe-z7o
    @tantruongthe-z7o หลายเดือนก่อน

    So, if an entity (that is mapping to a table) can be an aggregate by adding bussiness logic inside its class (rich model), then perform CRUD with that class to persist into DB ?
    The AggregateRoot, because of it empty, is only use for marking that some classes is an aggregate root ?
    When you say fetch aggregate with related entities, you changed the repository codes, why ? We still can use Include() method for the same purpose.
    I have a small design, see below:
    A class named User (Id, Name, List SkillList, List ProdList ), Skill class (Id, SkillName), Product (Id, ProdName).
    When i create an user, it will also add all products belong to current user, i am tending to create an aggregate named UserCreateAggregate that only has 2 required props (User user // root, List ProdList) with a void CreateMethod()
    {
    user = new();
    user.prodList = Prodlist;
    }.
    I am stucking right here, i don't know how to persist to DB, i have 2 ways, feel free to express your opinion:
    1. Pass UserRepo to Aggregate then saveChanges(), this way worked but it looks stupid :)
    2. Return current user (use prop that is declared earlier) to service class then userRepo saves it to DB. (this seems more appropriate).
    Additional info, i am using EF Core with UOW and repository (For each entity).

    • @MilanJovanovicTech
      @MilanJovanovicTech  หลายเดือนก่อน +1

      Entities can contain business logic (rich models) and be used for CRUD. Return the user from your aggregate to the service, then save via repository. Consider simplifying your architecture - full UoW and repository patterns may be unnecessary with EF Core.

  • @medzik1993
    @medzik1993 ปีที่แล้ว +1

    Milan first of all love your work

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      You would do it differently if the collection is large. Just load a single invitation, and have it reference a Gathering.

  • @alang39564
    @alang39564 11 หลายเดือนก่อน

    I'm a bit confused about how to define aggregates when there's a N:N relationship, imagine we have TaxRegimes and TaxPayerType, you may have a use case to where you create a TaxPayerType with some TaxRegimes, and other use case where you create a TaxRegime with some TaxPayerTypes associated with it. Which one is the aggregate root? TaxRegime or TaxPayer?

    • @MilanJovanovicTech
      @MilanJovanovicTech  11 หลายเดือนก่อน

      What if we create a larger concept to hold both of them together?

  • @ivandrofly
    @ivandrofly ปีที่แล้ว +1

    Thanks

  • @Synergy_World
    @Synergy_World 2 ปีที่แล้ว +1

    can you create a tutorial where you create a project using ddd and cqrs

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว

      I have an entire series about that on this channel: th-cam.com/video/tLk4pZZtiDY/w-d-xo.html

  • @ElvijsTeikmanis
    @ElvijsTeikmanis ปีที่แล้ว +2

    Hello over-fetching, my old friend

  • @botyironcastle
    @botyironcastle 6 หลายเดือนก่อน +1

    what if you have huge data like 100000000comments in Post object. I don't think you can init a domain object with that much... looks useless to me when dealing with large chuncks of data. Thoughts?

    • @MilanJovanovicTech
      @MilanJovanovicTech  6 หลายเดือนก่อน +1

      The amount of data also dictates domain modeling, obviously. We wouldn't create a collection navigation in that case.

  • @TheophilusQuaicoe-king26
    @TheophilusQuaicoe-king26 5 หลายเดือนก่อน

    please i went to your app and i did not find the source codes

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 หลายเดือนก่อน

      It's all shared on Patreon: www.patreon.com/milanjovanovic

  • @kresimir.sutalo
    @kresimir.sutalo 2 ปีที่แล้ว +1

    Hi Milan, can you upload the code to GitHub so it is easier to read?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +2

      Hi Krešimir, I have a similar example on my GitHub already that you can take a look at.
      github.com/m-jovanovic

    • @flywheel56
      @flywheel56 2 ปีที่แล้ว

      @@MilanJovanovicTech Thanks for all you do. This one was especially valuable.

  • @DanKac182
    @DanKac182 3 หลายเดือนก่อน

    Is this a rule, not to use multiple repositories in the handler? there is still attendeeRepository there

  • @user-jc6kq1ex7w
    @user-jc6kq1ex7w ปีที่แล้ว +1

    Hi Milan Thank you for your effort I was just confused about how the relationship between these tables will look according to this diagram there is a cyclical relationship between the tables the entity framework gives me this error
    Introducing FOREIGN KEY constraint 'FK_Invitations_Members_MemberId' on table 'Invitations' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
    Could not create constraint or index. See previous errors.

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      You can define a cascade behavior you think is appropriate in EF config

  • @johnnuy
    @johnnuy 11 หลายเดือนก่อน +1

    Say you have a very large gathering, like 2 million people... everyone one of these people accepts the invitation you're going be retrieving the entire aggregate with all invitations each time, just so that you can then access the single invitation you want to accept?

    • @MilanJovanovicTech
      @MilanJovanovicTech  11 หลายเดือนก่อน

      I hope it's obvious that we change the domain model based on the application load and requirements. Right?

    • @johnnuy
      @johnnuy 11 หลายเดือนก่อน +1

      ​@@MilanJovanovicTech- So when you put this together (yes it's a year ago), what was your thought process behind grouping the attendee and invitation as part of an aggregate root of Gathering, rather than Member, because it seems pretty clear that a Gathering has the potential to have significantly more members, than a Member would attend gatherings... This thought process of domain design is what I'm interested in, and is rarely discussed.

    • @shanerobertson1097
      @shanerobertson1097 6 หลายเดือนก่อน

      @@MilanJovanovicTechyou do so wrong. Sounds very impressive. Your analysis is so wrong though

  • @microtech2448
    @microtech2448 ปีที่แล้ว

    You have been using same domain entity to persist changes in DB. Can you create video where both DB and domain entities are separate and mapped in Application layer? Because domain entities are not supposed to be dealt with DB even if DB and domain entities share the same properties .

    • @MilanJovanovicTech
      @MilanJovanovicTech  ปีที่แล้ว

      Is there a value in having a separate persistence model?

    • @microtech2448
      @microtech2448 ปีที่แล้ว

      @@MilanJovanovicTech why not, when we are having such a pain of declaring domain entities, separate out every layer then why not entities?

  • @TrungTran-le2ht
    @TrungTran-le2ht 7 หลายเดือนก่อน +1

    I just failed at coding round about this concept. but thanks anyway

    • @MilanJovanovicTech
      @MilanJovanovicTech  7 หลายเดือนก่อน

      That sucks. Who asks DDD questions in an interview, though?

  • @danielmoreira4981
    @danielmoreira4981 2 ปีที่แล้ว

    how to "search everywhere"?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว

      What?

    • @danielmoreira4981
      @danielmoreira4981 2 ปีที่แล้ว

      @@MilanJovanovicTech at 2:48 of the video, you open a search box, how - with what command - did you do that?

    • @MilanJovanovicTech
      @MilanJovanovicTech  2 ปีที่แล้ว +1

      @@danielmoreira4981 Ctrl + T

  • @PersianCamel
    @PersianCamel หลายเดือนก่อน

    Let's forget about ubiquitous language for the time being then.

  • @maniumek9907
    @maniumek9907 7 หลายเดือนก่อน

    Aggregate should not contain Invitations, but InvitationIDs

  • @shanerobertson1097
    @shanerobertson1097 6 หลายเดือนก่อน

    Wrong

  • @skelaw
    @skelaw 5 หลายเดือนก่อน

    Hey! Two questions:
    1. What real problem does this solve beyond following the established artificial rule that logic should be in aggregate root?
    Apart from the change in the location of the function, nothing has changed.
    2. Why not fetch the invitation along with the gathering in one query?
    Commands, after all, are not reusable.

    • @MilanJovanovicTech
      @MilanJovanovicTech  5 หลายเดือนก่อน +1

      You have to look at this from a conceptual perspective instead of focusing on a made-up example.
      The ideas I'm implementing here are that the Aggregate should act as a consistency boundary for the root and respective entities - and - that the aggregate root should expose methods to manipulate it. I talked about this more from a theoretical perspective here: th-cam.com/video/Pkvt87yL6Gs/w-d-xo.html