1

If some model can only exist if set of values are passed to it and validation on them are performed, then how to load such a model if only one of those values is needed for some action?

It seems a little overhead to do hydration of model all over again if only one value for action on that model is needed. That can be expensive.

I have an auction model. It has title, description, owner, current value, dates and bids. For particular operation like bid I only need current value and bids in this model to be populated. However, model, theoretically, cannot exist if other values are not received and validated (in constructor).

What to do? How to do separation? Is that normal/common for DDD and there is just some trade offs you cannot avoid?

  • 1
    Is this a real problem or are you prematurely optimising? Otherwise you are allowed to utilize lazy loading in ddd. Have you looked into lazy loading? – Esben Skov Pedersen Oct 18 '15 at 11:41
  • Right now I am just theorethising. I know that lazy loading exists. However I cannot wrap my head around that principle because there is business rules involved when creating instance. I do not know how to split attribute hydration per usecase. – chba Oct 18 '15 at 12:42
  • 4
    Maybe just start and see if you encounter any real problems, they would be easier to solve. – Esben Skov Pedersen Oct 18 '15 at 12:56
2

I believe I understand your dilemma.

Though it may be a waste to rehydrate the entire aggregate for this, the aggregate serves the specific purpose of being the consistency boundary. If you had a subset of the domain just to handle the bids, and the full aggregate for other operations, how are you going to maintain consistency when you have potentially two objects servicing operations on the same AR? You no longer have a single consistency boundary. Are you positive that performance is going to be a problem if rehydrate the entire thing for this minor operation? Have you measured it?

If it becomes a problem, one thing you can do is to move your use cases up a level so that they are intercepted before the aggregate root is loaded. This is common in messaging-based systems where you issue commands to the domain (not call a method directly on a loaded aggregate). Commands are received by handlers, which hydrate the aggregate as appropriate for the use case (e.g. a deleted version of the aggregate which refuses to do perform any operation since it is deleted, or in your case a limited version which only accepts bids). Sometimes the handlers even load other aggregates (for information only, otherwise the consistency boundary is violated again) or prepare services to hand off to the aggregate to perform the given use case.

In a non-messaging system you could accomplish the same with the Facade pattern. Essentially, you make an object that is your interface into the domain. The object has a method per use case. Inside that method, you run handler code; hydrate your appropriate aggregate, wrangle the resources/services necessary for the user case, and call the aggregate's method. Maybe save the changes as well. Eventually, you may get too many parameters on the Facade methods and you will need to refactor them to an object. At that point, you have a command message as your parameter. :)

However, if you do something like this you need some infrastructure guarantees. For example, a specific aggregate can only run one use case at a time. My first infrastructure like this, each type of aggregate (not each instance) could only run one use case at a time -- in other words if I submitted 100 operations, each to a different auction, they would still be performed one at a time. In practice, this was not a performance problem at all as you will usually be bottle-necked by I/O more than running domain operations.

  • Yea, you got the idea behind my question. Performance will not be degraded dramatically, but it will stand out. For me it's just that, it does not make sense to do more calculations than it is needed for some concrete operation, thus I would like to find out right structure. You gave me an idea. Aggregate hydration based on use case makes total sense. But I am not sure that it answers my question entirely just yet. I am new to this and I would like to know more to related subject and real world practices. – chba Oct 20 '15 at 7:12
  • A non-messaging analog would be having a Facade pattern. I'll update the answer. – Kasey Speakman Oct 20 '15 at 14:07
  • How did you achieved one use case per aggregate? – chba Jan 25 '16 at 9:40
  • @chba Assuming you mean single threaded execution per aggregate, I achieved it with F# MailboxProcessors. It's a bit OO-like, but here is an example. Prior to that I used a worker for each type of aggregate. F.ex all Customer aggregate operations are serviced by one worker/agent. I'd recommend that as a start since it's more straight-forward and perf is not likely to be a problem. I wrote the Agency code mainly to satisfy my curiosity. – Kasey Speakman Jan 25 '16 at 15:38
0

When you realize that most of the data an AR carries is not needed at all to fulfill some of it's commands then you are on the urge of discovering a new domain concept. Another analysis that may help the discovery process is doing a concurrency conflict analysis to see if your design introduces unnecessary concurrency conflicts.

e.g. Should changing the title of the auction conflict with someone who's trying to bid?

The fact that you are asking this question is a strong indicator that your aggregate boundaries are wrong and that your Auction concept is currently not very cohesive.

Most people will solve the data-loading part of this problem by introducing lazy-loading, but that's a code smell and doesn't address the heart of the problem.

I can't tell if that really fits with your domain, but what about having a Listing aggregate as well as an Auction aggregate. A Listing is sold through an Auction.

The Listing would handle the descriptive part of what's being sold while the Auction will handle the bidding process.

Both ARs can be created in the same transaction: the creation of the Auction is an immediate side-effect of the creation of a Listing.

"But there's a rule stating that one should not modify more than a single AR in a transaction".

Yes and it's very important to respect that rule, but here we aren't modifying ARs we are creating them and that's very different because no contention can exist during the creation process. Those ARs aren't shared resources yet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.