Don't be fooled! That's NOT an Aggregate in Domain Driven Design

preview_player
Показать описание
Do you get frustrated that you have to open multiple files across multiple layers to make what seems to you like a simple change? One of the culprits for this is following structure and templates that apply patterns or concepts to solve problems you might not have. One typical case of this is using aggregate from domain drive design. In this video, I'll give some examples of where an aggregate can make sense and where it's not and adds useless indirection.

🔗 EventStoreDB

💥 Join this channel to get access to source code & demos!

🔥 Don't have the JOIN button? Support me on Patreon!

0:00 Intro
0:51 Indirection
3:20 Fake Aggregate
6:42 Consistency Boundary

#softwarearchitecture #softwaredesign #domaindrivendesign

Рекомендации по теме
Комментарии
Автор

Very good. We only truly master code patterns when we know where, when, and why not to use them. Great reminder of how important that is.

NelCapeTown
Автор

So I cannot over-engineer my solution any more to feel better about myself? 😭 /s

FlaviusAspra
Автор

Thankfully, I've watched older videos from you that prevented me from doing this! Honestly, I learn a lot from you.

codewkarim
Автор

Thank you for this video, kinda feel like i've been doing this all over my codebase. I guess it's time to re-evaluate what patterns i actually need to use rather then just using them blindly. I do however believe i should use Aggregate in my codebase since the Validation is quite complicated

einardivision
Автор

Do you have an example of when an Aggregate Root becomes to big and how to deal with it? I have an example where there is one single consistency boundary, but the objects inside the AR have two different "directions" - thus not related.
Example: A conference with speakers and participants. Both are bound by the rules of the conference, but the participants are not guarded by speakers and vice versa. But they are each guarded by themselves and the conference boundary.

Should this be split to different aggregates or kept and allow the AR to grow? If split, how to maintain the AR as a boundary for both?

Thanks

nicolaibaaring
Автор

I like that validated value object trick! Definitely food for thought.

Bigs
Автор

The first thing I see with setting the name directly with a public setter on the product is that I can set it to null or string.Empty. You are not enforcing your invariant now, unless the products name can be null or string.Empty, which I highly doubt. I’d rather still have a setter/edit method which at least checks for nulls or empty strings.

Sokooo
Автор

I agree, but to be able to use "simple code" you need to REALLY understand WHY you are adding useless complexity. And this is the hardest part. The only way to understand this, is to pratice A LOT of DDD, Clean Architecture etc etc. After I studied a lot of DDD I start to understand when and why don't use Aggregates, CQRS and write a simple Repository Pattern or a Transiction Script.

Anyway, my suggestion is: Pratice a LOT of DDD in your code. Write a lot of useless complex code so you can understand where and when use some pattern to resolve your specific problem. By the way, good video as always! :)

evilTano
Автор

How would you apply this 'flexible' approach to root + members situation? Let's make up an example - there's an aggregate root called Company with a list of members of type CompanyDepartment. Company could have a method ExtendServiceOffer(Service) which would iterate through Departments checking if any of them have the capability of providing such Service and if not - add new (it might make no sense in real world, it's just for the sake of an example). At the same time there might be a need to update some simple properties of Department like name. Changing name does not break any consistency of an aggregate so theoretically it could be done with public setter, but there's this rule saying that you should not access aggregate member directly, only via aggregate root. This is a fairly simple example, but I can imagine easily having more levels of aggregate members (DepratmentWorkers, WorkerSkills), which for sure will have some simple properties.

kubastepaniak
Автор

Thanks for all of your videos! I do think that bombarding the programmer’s mind with stuff do help them start thinking.

The problem that newbies have with DDD concepts is that they go directly to code and forgets the point of the patterns. Thinking: “I have to do this” The focus becomes pattern rather than use. You cannot write good comprehendible code just by following patterns, then AI would take your job.

If you have logic for a property setter, and you cannot abstract it away in a Value Object, perhaps it is better to manually write the setter, rather than to create this extra method which doesn’t provide any value other value than just the 1-5 lines for validation and setting the field.

marna_li
Автор

You're videos are great. It's a very simple case of whether you are validating input (which can simply be done with types) or actually validating the current state of the system.

MaxPicAxe
Автор

I usually prefer to use rich domain models where there's some more interactions/behaviour than the usual, simple, no business logic entities that just get stored in the DB.

The order vs product you gave is a great example since they're in the same field. A product is very simple. A catalog, a product page, an order/checkout, that uses some data from the product, is where you'll actually business rules applied. Those business rules probably use a product entity (or multiple) but they're their own thing within the different aggregates.

EldenFiend
Автор

This is a great example about DDD aggregates and their purpose

I also watched your time zones video and how to schedule an event in the future I found it a little bit vague could you make a more detailed video with an example
Thanks

mohamadyousef
Автор

The UML diagram used wrong syntax. The diamond indicated "aggregates" and need to be on the basket

danielpotzinger
Автор

Problem with using struct like this for validation is that we can pass invalid structure to the aggregate.
For example in case structure got it's default value.

ProductPrice productPrice = default;

Also there is an error in your code since domain exception will be thrown when product price equals 0 but the message says that price cannot be negative.

Anyway I'm still a regular on your channel, great work.

tomaszpajak
Автор

One of my coworkers follows DDDD (Dogmatic Domain Driven Design) where higher abstractions create an instance of a model (empty constructor, filled with null/default values) just to call a method on that model (passing in the repository object) to get back a collection of that model... because "it's domain driven design". There's no reasoning with this man. Believe me, I have tried.

Galakyllz
Автор

So if the properties become publically settable, then we don't use the value objects to set them. We can directly set item.price = request.price. Where do you perform the validation to ensure price isn't a negative value?

cdarrigo
Автор

Great video.

But one question. For validate the price you replaced the logic inside the "domain object" for a Value Object and great strategy. But what if you dont use a value object to make those validations of a specific property(s), what is the strategy? make the validation inside the transactions scripts using for example some kind of validation lib/framework knowing that you have the chance that your "domain model" (anemic model) can be in invalid state?

heikenem
Автор

Hello Derek! I am building an event driven application and i am currently developing a module that manages products in an ecommerce. The idea is that for some things i do not need an aggregate like u explained however in that case how would i publish the corresponding events if not inside an aggregate. For example ProductAddedEvent? Thanks in advance

acegame
Автор

I usually check string lengths in my Create / Set methods. Do you think in that case it's ok to have set methods or string lengths should not be checked at all and delegate those checks to database?

Ogix