I wanted to model domain of simple game.
We have a player which can buy different buildings, he have also a stock, and player can have other things which I'm going to add in the future. But for now I'm focusing only on buildings and stock.
I decided to divide it into three aggregates roots Player, PlayerBuildingManagment, PlayerStock. Im not sure if it is proper division, because Stock, and PlayerBuildingManagment are very related to Player so mayby it shouldn't be aggregate roots. On the other hand I don't want to create one huge aggregate. In my case concurrency will not be a problem because everything stock, building managment will be modified only by one player.
Player
Stock
1. AddToStock()
2. TakeFromStock()
PlayerBuildingManagment
1. AddBuilding()
Now I need to implement process where player will buy a building so I need to
Check if he have enough resources and take it from a stock Stock.TakeFromStock()
I need to add building PlayerBuildingManagment.AddBuilding().
Persist data.
I can realize this process inside one service function but from what I know we shouldn't modify state of two aggregates inside one transaction. What do you think how this communication should be realized.
Maybe I should implement stock and buildingmanagment inside player aggregate. Or create some process manager to make this communication. Could you please give me some clue.
Obtaining transactional consistency between aggregates, which, by definition, are their own consistency boundaries, is problematic to say the least.
Let's go with your notion that there are Players, PlayerStock -- which acts like a bank, and PlayerBuildingManager -- which acts like a contractor.
Regarding the problem of checking for sufficient stock and the request to build building Y by player P for cost X, I'd probably send the PlayerStock aggregate a single command that takes these parameters:
the player id, P,
the amount of stock to take, X, and,
what to do if the stock take is successful:
Here the caller of this message to PlayerStock, will provide a "what to do" that effectively represents a message to send to someone else on success (you might also have a "what to do" on failure, but that is another matter).
In this case, "what to do" message parameter would encode a command to build a building, Y, for player X, and that is to be sent to PlayerBuildingManager.
The rest can be handled with eventual consistency that is typical of multiple aggregates.
Thus, some controller via the UI sends PlayerStock a message to deduct some amount X from player P and to send some message on success. On success, it will execute the success message, which is a message to PlayerBuildingManager to construct building Y for player P. There will be an eventual consistency period for which stock has been deducted but the building has not yet materialized. That is the eventual consistency you buy into when using multiple aggregates.
The reason to encode the on-success message as a parameter is so that you can more loosely couple PlayerStock from the catalog of things that can be constructed and by who can construct them. An arbitrary on-success message as a parameter will provide a high degree of flexibility without PlayerStock having to know too much.
(If you don't want to deal with that you can put them all in the same aggregate, of course.)
If you want to go further:
Let's say the PlayerBuildingManager fails at building the building in the command it received from the PlayerStock. Well, it should return the stock. But to keep things loosely coupled, the PlayerStock can provide a message to send in that case, which returns X to PlayerStock for P.
Also you might consider what happens if construction of the building takes not just latency but real-time (as would be the case in the real world). In that case, the player may want to cancel construction, and may or may not be allowed to do so, and maybe with full refund or partial refund...
Related
I'm new to Agile. I'm currently writing a software that basically does a simulation using real-life objects – for simplicity's sake here's an example:
I have a GUI where I can add two Human Object(s) onto a plane, a Ball Object, and one Human Object. Then I can press a PLAY button to simulate a situation where Human Object A can throw the Ball Object by specifying parameters I can use physics based on Force/Velocity/Direction, and then the Human Object B can catch the ball based on its own position and time while he is walking (where its movement is specified by reading in an input file).
It's a two step phase where I do parameter specification, then pressing play to simulate how those events unfold.
My difficulties reside only for the backend part where I know I need an a) Event Handler, b) Coordinate system infrastructure. But I'm having trouble determining where in my User Stories they should belong?
Right now they sit on its own User Story just written as tasks as "Event Handling." and "XYZ Coordinate System", which I feel is not very well placed.
What I'm trying to understand: If I have the User story:
As a user, I want to be able to be able to add a Human Object to my simulation so that I can have the object interact with the ball
Would my Task List (for specifically back-end stuff) include:
Implement xyz-coordinate system
Implement having an Event Handler and adding the Human Object to being an Event Handling object?
Or should I stick those tasks into a User Story like
As a user, I want to be able to see my objects interact with each other when I press a play button so that I can determine what the status of the objects are after it is done playing
to handle the task of implementing infrastructure of the coordinate system and event handling?
(And to note, in reality outside of the example, I have a lot more objects and back-end processing.)
The direct answer to your question is that the user story you put at the end is probably your best bet for a user story. Implementation tasks are just how your team is going to make that happen. Where it gets messy in complex work like what you are describing is if that user story takes a month to build and you have to break it down.
You want to deliver functionality, even if it isn't the whole package. This may be abusing your example, but where I'd probably start in the case you give is first limit the scope of the user story to simulating those exact objects and interactions: 2 humans and one ball. This takes out a lot of the variability. Now, from a programming standpoint, there is a huge trap here. When you implement it, make sure to do it in a way that those areas can be expanded later without throwing the implementation out and starting over if you can.
Next, if that is too big, I'd probably split the throw and the catch simulation. This is implementing the code in a way that is aligned with the purpose of Agile. If I make Human A throw a ball, I can show that to a user and potentially learn. Maybe we are simulating football and we throw a "prolate spheroid" (the term for the shape of an American football) in a perfect spiral. I show it to the user and he says "No no, we're from Spain, we are simulating an overhead 2-handed throw of a round ball." Now you've learned something critical about the work you've done and the work to be done (the receiver can't catch with their hands).
The specific tool of user stories may or may not be helpful. I could write this last one as "As a sports coach, I would like to simulate a throw-in so I can experiment with different techniques." That contains a lot of convenient information for me. In particular, user stories are most valuable in places where you are trying to understand your user's needs better. However, if you feel you understand them well enough, "Simulate throw" is a perfectly adequate backlog item.
I am a beginner in DDD and I came across a situation that involves a rule of not modifying more than 1 aggregate in the same transaction, using Domain Events to resolve changes in other aggregates. (see Effective Aggregate Project).
The situation is as follows: The user schedules to transfer a patient to another hospital. When the transfer time comes, the user selects it in a list and clicks 'Start'. However, this action changes three aggregates:
Transfer: marked as started. ex: transfer.Start();
Patient: is marked as being transferred. ex: patient.MarkAsInTransfer();
Hospital: you must reserve a place for the patient who is now coming. ex: hospita;.ReservePlace(patient);
Thus, when transfer starts, it raise an event TransferStarted.
But, for some reason, when the transfer is already occurring, an error occurs when handling the TransferStarted event (changing the patient's status or reserving a place in destination hospital).
How to deal with this situation, since the patient is already in transfer? I need to forget and use transactional consistency, modifying three aggregates in the same transaction? Using a Domain Service to do it?
Remembering that I am following an aggregate transaction rule.
How to deal with this situation, since the patient is already in transfer? I need to forget and use transactional consistency, modifying three aggregates in the same transaction? Using a Domain Service to do it?
There are a couple of aspects to what's going on here.
1) From your description, you are dealing with entities out in the real world; the book of record for the real world is the real world, not your domain model. So when you receive a "domain event" from the real world, you need to treat it appropriately.
2) collaborative domains, with contributions from multiple resources out in the real world, are inherently "eventually consistent". The people over here don't know what's going on over there, and vice versa -- they can only act on the information they have locally, and report faithfully what they are doing.
What this means, in practice, is that you need to be thinking about your "aggregates" as bookkeeping about what's going on in the real world, and documenting actions that conflict with policy as they occur (sometimes referred to as "exception reports").
3) Often in the case of collaborative processes, the "aggregate" is the instance of the process itself, rather than the entities participating in it.
How to deal with this situation, since the patient is already in transfer?
You invoke the contingency protocol provided to you by the domain experts.
A way to think of it is to imagine a bunch of SMS messages going around. You get a message from the attending announcing that the transfer is starting, and the moments later you get a message from the destination hospital that it is in lockdown.
Now what?
Well, I'm not sure - it isn't my domain. But it's probably something like sending a message to the attending to announce that the destination has been closed.
The important things to notice here are that (a) conflicting things happening in different places is a property of distributed collaborative systems, and you have to plan for it -- the race conditions are real and (b) the information you have about the state of affairs anywhere else is always stale, and subject to revision.
Take a careful read of Data on the Outside versus Data on the Inside. The real world is outside, all of the information you have about it is stale. Also, review Memories, Guesses, and Apologies.
When I face this sort of issue, the first thing I ask myself is: "are my aggregates correct, and do they have the right responsibilities"? After all, an aggregate is a transaction boundary which encapsulates the data and the business logic for a given process. If a process needs 3 aggregates, is it possible that they are, in fact, a single aggregate?
In your particular case, a Transfer sounds like an aggregate to me (as in, there must be some business rules to enforce and some data related to it), but Hospital and Patient look suspicious to me. What kind of data and business logic do they encapsulate and are in charge of? It obviously depends on the bounded context these aggregates are in, but it's something I would double-check. I assume though that they are all in the same BC.
For example, I would consider: why does a Patient need to be marked as in transfer? what kind of business rule does it enforce? If the reason is to avoid a Patient being transferred more than once, then it shouldn't be the listening an event from the Transfer (where does the transfer come from?), instead, it should be the one creating transfers (see Udi Dahan's Don't create aggregate roots). So, if you want to transfer a Patient, do Patient.TransferTo(otherHospital), which will check if the conditions are met to initiate a transfer and, if they are, send a Command to create a transfer. The Patient then can listen to TransferStarted, TransferCancelled, TransferCompleted events to update its own state safely (as a new transfer won't start until the previous one is completed either successfully or not).
From this point, the Hospital Room allocation would be something between the Transfer and the Hospital and the Patient doesn't need to know anything about it.
But regarding the Hospital, I don't know at this point, because it doesn't seem right to me that a single aggregate manages the room allocations of a whole Hospital. It seems a lot of data and responsibility and also, it's not clear to me that there's the need for transactionality: why the allocation of Patient A in Room 100 has to be transactional with the allocation of Patient B in Room 210? If you imagine the full Hospital, that's a lot of rooms and patients and a lot of contingency in a single aggregate, which won't allow concurrent changes. Obviously, I don't have enough knowledge of the domain and details to make a suggestion, these are only considerations.
So I'm trying to figure out the structure behind general use cases of a CQRS+ES architecture and one of the problems I'm having is how aggregates are represented in the event store. If we divide the events into streams, what exactly would a stream represent? In the context of a hypothetical inventory management system that tracks a collection of items, each with an ID, product code, and location, I'm having trouble visualizing the layout of the system.
From what I could gather on the internet, it could be described succinctly "one stream per aggregate." So I would have an Inventory aggregate, a single stream with ItemAdded, ItemPulled, ItemRestocked, etc. events each with serialized data containing the Item ID, quantity changed, location, etc. The aggregate root would contain a collection of InventoryItem objects (each with their respective quantity, product codes, location, etc.) That seems like it would allow for easily enforcing domain rules, but I see one major flaw to this; when applying those events to the aggregate root, you would have to first rebuild that collection of InventoryItem. Even with snapshotting, that seems be very inefficient with a large number of items.
Another method would be to have one stream per InventoryItem tracking all events pertaining to only item. Each stream is named with the ID of that item. That seems like the simpler route, but now how would you enforce domain rules like ensuring product codes are unique or you're not putting multiple items into the same location? It seems like you would now have to bring in a Read model, but isn't the whole point to keep commands and query's seperate? It just feels wrong.
So my question is 'which is correct?' Partially both? Neither? Like most things, the more I learn, the more I learn that I don't know...
In a typical event store, each event stream is an isolated transaction boundary. Any time you change the model you lock the stream, append new events, and release the lock. (In designs that use optimistic concurrency, the boundaries are the same, but the "locking" mechanism is slightly different).
You will almost certainly want to ensure that any aggregate is enclosed within a single stream -- sharing an aggregate between two streams is analogous to sharing an aggregate across two databases.
A single stream can be dedicated to a single aggregate, to a collection of aggregates, or even to the entire model. Aggregates that are part of the same stream can be changed in the same transaction -- huzzah! -- at the cost of some contention and a bit of extra work to do when loading an aggregate from the stream.
The most commonly discussed design assigns each logical stream to a single aggregate.
That seems like it would allow for easily enforcing domain rules, but I see one major flaw to this; when applying those events to the aggregate root, you would have to first rebuild that collection of InventoryItem. Even with snapshotting, that seems be very inefficient with a large number of items.
There are a couple of possibilities; in some models, especially those with a strong temporal component, it makes sense to model some "entities" as a time series of aggregates. For example, in a scheduling system, rather than Bobs Calendar you might instead have Bobs March Calendar, Bobs April Calendar and so on. Chopping the life cycle into smaller installments can keep the event count in check.
Another possibility is snapshots, with an additional trick to it: each snapshot is annotated with metadata that describes where in the stream the snapshot was made, and you simply read the stream forward from that point.
This, of course, depends on having an implementation of an event stream that supports random access, or an implementation of stream that allows you to read last in first out.
Keep in mind that both of these are really performance optimizations, and the first rule of optimization is... don't.
So I'm trying to figure out the structure behind general use cases of a CQRS+ES architecture and one of the problems I'm having is how aggregates are represented in the event store
The event store in a DDD project is designed around event-sourced Aggregates:
it provides the efficient loading of all events previously emitted by an Aggregate root instance (having a given, specified ID)
those events must be retrieved in the order they where emitted
it must not permit appending events at the same time for the same Aggregate root instance
all events emitted as result of a single command must be all appended atomically; this means that they should all succeed or all fail
The 4th point could be implemented using transactions but this is not a necessity. In fact, for scalability reasons, if you can then you should choose a persistence that provides you atomicity without the use of transactions. For example, you could store the events in a MongoDB document, as MongoDB guaranties document-level atomicity.
The 3rd point can be implemented using optimistic locking, using a version column with an unique index per (version x AggregateType x AggregateId).
At the same time, there is a DDD rule regarding the Aggregates: don't mutate more than one Aggregate per transaction. This rule helps you A LOT to design a scalable system. Break it if you don't need one.
So, the solution to all these requirements is something that is called an Event-stream, that contains all the previous emitted events by an Aggregate instance.
So I would have an Inventory aggregate
The DDD has higher precedence than the Event-store. So, if you have some business rules that force you to decide that you must have a (big) Inventory aggregate, then yes, it would load ALL the previous events generated by itself. Then the InventoryItem would be a nested entity that cannot emit events by itself.
That seems like it would allow for easily enforcing domain rules, but I see one major flaw to this; when applying those events to the aggregate root, you would have to first rebuild that collection of InventoryItem. Even with snapshotting, that seems be very inefficient with a large number of items.
Yes, indeed. The simplest thing would be for us to all have a single Aggregate, with a single instance. Then the consistency would be the strongest possible. But this is not efficient so you need to better think about the real business requirements.
Another method would be to have one stream per InventoryItem tracking all events pertaining to only item. Each stream is named with the ID of that item. That seems like the simpler route, but now how would you enforce domain rules like ensuring product codes are unique or you're not putting multiple items into the same location?
There is another possibility. You should model the assigning of product codes as a Business Process. For this you could use a Saga/Process manager that would orchestrate the entire process. This Saga could use a collection with an unique index added to the product code column in order to ensure that only one product uses a given product code.
You could design the Saga to permit the allocation of an already-taken code to a product and to compensate later or to reject the invalid allocation in the first place.
It seems like you would now have to bring in a Read model, but isn't the whole point to keep commands and query's seperate? It just feels wrong.
The Saga uses indeed a private state maintained from the domain events in an eventual consistent state, just like a Read-model but this does not feel wrong for me. It may use whatever it needs in order to bring (eventually) the system as a hole to a consistent state. It complements the Aggregates, whose purpose is to not allow the building-blocks of the system to get into an invalid state.
I am new to DDD. Now I was looking at the domain event. I am not sure if I understand this domain event correctly, but I am just thinking what will happen if domain event published failed?
I have a case here. When a buyer order something from my website, firstly we will create a object, Order with line of items. The domain event, OrderWasMade, will be published to deduct the stock in Inventory. So here is the case, what if when the event was handled, the item quantity will be deducted, but what if when the system try to deduct the stock, it found out that there is no stock remaining for the item (amount = 0). So, the item amount can't be deducted but the order had already being committed.
Will this kind of scenario happen?
Sorry to have squeeze in 2 other questions here.
It seems like each event will be in its own transaction scope, which means the system requires to open multiple connection to database at once. So if I am using IIS Server, I must enable DTC, am I correct?
Is there any relationship between domain-events and domain-services?
A domain event never fails because it's a notification of things that happened (note the past tense). But the operation which will generate that event might fail and the event won't be generated.
The scenario you told us shows that you're not really doing DDD, you're doing CRUD using DDD words. Yes, I know you're new to it, don't worry, everybody misunderstood DDD until they got it (but it might take some time and plenty of practice).
DDD is about identifying the domain model abstraction, which is not code. Code is when you're implementing that abstraction. It's very obvious you haven't done the proper modelling, because the domain expert should tell you what happens if products are out of stock.
Next, there's no db/acid transactions at this level. Those are an implementation detail. The way DDD works is identifying where the business needs things to be consistent together and that's called an aggregate.
The order was submitted and this where that use case stops. When you publish the OrderWasMadeevent, another use case (deducting the inventory or whatever) is triggered. This is a different business scenario related but not part of "submit order". If there isn't enough stock then another event is published NotEnoughInventory and another use case will be triggered. We follow the business here and we identify each step that the business does in order to fulfill the order.
The art of DDD consists in understanding and identifying granular business functionality, the involved aggregates, business behaviour which makes decisions etc and this has nothing to do the database or transactions.
In DDD the aggregate is the only place where a unit of work needs to be used.
To answer your questions:
It seems like each event will be in its own transaction scope, which means the system requires to open multiple connection to database at once. So if I am using IIS Server, I must enable DTC, am I correct?
No, transactions,events and distributed transactions are different things. IIS is a web server, I think you want to say SqlServer. You're always opening multiple connections to the db in a web app, DTC has nothing to do with it. Actually, the question tells me that you need to read a lot more about DDD and not just Evans' book. To be honest, from a DDD pov it doesn't make much sense what you're asking.. You know one of principles of DD: the db (as in persistence details) doesn't exist.
Is there any relationship between domain-events and domain-services
They're both part of the domain but they have different roles:
Domain events tell the world that something changed in the domain
Domain services encapsulate domain behaviour which doesn't have its own persisted state (like Calculate Tax)
Usually an application service (which acts as a host for a business use case) will use a domain service to verify constraints or to gather data required to change an aggregate which in turn will generate one or more events. Aggregates are the ones persisted and always, an aggregate is persisted in an atomic manner i.e db transaction / unit of work.
what will happen if domain event published failed?
MikeSW already described this - publishing the event (which is to say, making it part of the history) is a separate concern from consuming the event.
what if when the system try to deduct the stock, it found out that there is no stock remaining for the item (amount = 0). So, the item amount can't be deducted but the order had already being committed.
Will this kind of scenario happen?
So the DDD answer is: ask your domain experts!
If you sit down with your domain experts, and explore the ubiquitous language, you are likely to discover that this is a well understood exception to the happy path for ordering, with an understood mitigation ("we mark the status of the order as pending, and we check to see if we've already ordered more inventory from the supplier..."). This is basically a requirements discovery exercise.
And when you understand these requirements, you go do it.
Go do it typically means a "saga" (a somewhat misleading and overloaded use of the term); a business process/workflow/state machine implementation that keeps track of what is going on.
Using your example: OrderWasMade triggers an OrderFulfillment process, which tracks the "state" of the order. There might be an "AwaitingInventory" state where OrderFulfillment parks until the next delivery from the supplier, for example.
Recommended reading:
http://udidahan.com/2010/08/31/race-conditions-dont-exist/
http://udidahan.com/2009/04/20/saga-persistence-and-event-driven-architectures/
http://joshkodroff.com/blog/2015/08/21/an-elegant-abandoned-cart-email-using-nservicebus/
If you need the stock to be immediately consistent at all times, a common way of handling this in event sourced systems (can also in non-event based systems, this is orthogonal really) is to rely on optimistic locking at the event store level.
Events basically have a revision number that they expect the stream of events to be at to take effect. Once the event hits the persistent store, its revision number is checked against the real stream number and if they don't match, a conflict exception is raised and the transaction is aborted.
Now as #MikeSW pointed out, depending on your business requirements, stock checking can be an out-of-band process that handles the problem in an eventually consistent way. Eventually can range from milliseconds if another part of the process takes over immediately, to hours if an email is sent with human action needing to be taken.
In other words, if your domain requires it, you can choose to trade this sequence of events
(OrderAbortedOutOfStock)
for
(OrderMade, <-- Some amount of time --> OrderAbortedOutOfStock)
which amounts to the same aggregate state in the end
A group diary and time management system is intended to support the timetabling of
meetings and appointments across a group of coworkers. When an appointment is to be
made that involves a number of people, the system finds a common slot in each of their
diaries and arranges the appointment for that time. If no common slots are available, it
interacts with the user to rearrange his or her personal diary to make room for the
appointment.
First step is to think about what objects you have in the system. Make a list of candidates.
Now think about how does this scenario get initiated. Where does the message come from? Draw that incoming message.
The next step is to think about which object is going to receive that message. Now in order to do the work that object will probably need to talk to other objects. Sketch out the other object with an arrow and a message name.
Keep thinking about the sequence of messages and the objects to which the messages go - and try sketching them out one at a time.
Don't expect to get it right first time. Try sketching out several approaches.
A sequence diagram describes interactions between objects that achieve some goal.
So your first step needs to be to identify some objects (and actors). If you start with that step, show us your attempt, then we have something to discuss further.
"You should identify possible objects in the following systems and develop an object-oriented design for them. You may make any reasonable assumptions about the systems when deriving the design."
From Chapter 14 Exercise 14.7