DDD - bounded contexts sharing/communication - domain-driven-design

I am trying to utilize some DDD approaches in the app that allows guest purchase. While it looks easy, I got a bit confused and asking for your DDD advice.
The app has several bounded contexts and we are looking at 3 of them:
Customers (customers manage their user settings here, authentication, also admin can potentially create users)
Sales (orders)
Billing (charging customers for one-off payments and subscriptions)
The user story:
As a guest I want to order the product to do something.
This is one form and on checkout he/she will be asked for email and password. We need to create account on this step, but based on business logic this fits to Sales context - guest makes an order. We actually need to do simple steps:
Create user with ACTIVE status
Store billing details
Create order
Charge user later (event handled by Billing)
The confusion here is that it requires creating a user first. It looks more naturally to create it in customers, but probably it’s wrong? User can not sign up in any other way - only by placing an order, but admin can create a user manually. Based on different system events(from different contexts), the Customer context may change the user status based on special logic that is placed into Customer domain. Is there any safe way for sharing this User status logic between different contexts (while creating User in Sales we need that status enum class)? Does this logic for placing order look ok? Could you please recommend another approach if you think that this one is wrong?

Status is DDD at its worst. Including a status field is 1) lazy, and yet 2) very convenient. Yes, one of those design trade offs.
When you assign a status or read a status you are ignoring or sublimating significant business logic and structure for your domain. When “status” changes some very significant changes could occur in your domain... way beyond changing a status property.
Throw status out and instead consider some concepts: a CasualShopper or Guest (no purchases, browsing for products), a PotentialNewShopper (someone adding things in their basket who you’ve never seen before), and your usual Customer (which should probably be subdivided based on their current activity).
With this modeled, you can attach behaviors directly to each of these objects and “status” itself is sublimated into a richer DDD model. A common DDD mistake is not creating a transactionally-significant object (e.g. a Potential Shopper role) for some static/non-temporal object (e.g. a person).
From here you may decide you need a few bounded contexts; perhaps PotentialCustomers and EstablishedCustomers. In each the set of domain transitions are different and can be encapsulated rather than externalized.
So...
With that out of the way it looks like you have a Customer BC and a PossibleCustomer BC. You can safely do what you need to do in the latter now that it is self-contained.
Oh, but that may affect billing! and ordering!
True. That may mean new BCs or new objects in those BCs such as ProvisionalPayment and UnauthenticatedOrder. I’m spitballing a bit now...
My point is you have events that can transition between states rather than encoding those states, and as such you can attach the behaviors you need and persist them as needed in some physical store, that is likely partitioned in a way suitable to your DDD.
Doing all this work means not sharing unsafe status but sharing safe projections of relevant objects only.
Jumping into implementation briefly and anecdotally, developers are loath to store “temporary” state. “Temporary” state is OK to store and necessary when you’re modeling a domain without that cruddy status field.

You probably should ask yourself first whether you got the Bounded Contexts right.
In my opinion you have the following BCs
Identity and Users
Sales and Billing
consider this: the same person is a User in the first context but a Customer in the latter. so you have two views on the same real world entity which suggests that you have two bounded contexts where this entity means different things.
your bcs sound more like modules in the Sales and Billing context.
If you agree, then the control flow for your problem may be simplified where an entity in one context is created and the creation is propagated via event into the other. so the initial request could be handled by the Sales bc and the guest user handling would be propagated to Identity.

Related

How to handle hard aggregate-wide constraints in DDD/CQRS?

I'm new to DDD and I'm trying to model and implement a simple CRM system based on DDD, CQRS and event sourcing to get a feel for the paradigm. I have, however, run in to some difficulties that I'm not sure how to handle. I'm not sure if my difficulties stem from me not having modeled the domain properly or that I'm missing something else.
For a basic illustration of my problems, consider that my CRM system has the aggregate CustomerAggregate (which seems reasonble to me). The purpose of this aggregate is to make sure each customer is consistent and that its invarints hold up (name is required, social security number must be on the correkct format, etc.). So far, all is well.
When the system receives a command to create a new customer, however, it needs to make sure that the social security number of the new customer doesn't already exist (i.e. it must be unique across the system). This is, of cource, not an invariant that can be enforced by the CustomerAggregate aggregate since customers don't have any information regarding other customers.
One suggestion I've seen is to handle this kind of constraint in its own aggregate, e.g. SocialSecurityNumberUniqueAggregate. If the social security number is not already registered in the system, the SocialSecurityNumberUniqueAggregate publishes an event (e.g. SocialSecurityNumberOfNewCustomerWasUniqueEvent) which the CustomerAggregate subscribes to and publishes its own event in response to this (e.g. CustomerCreatedEvent). Does this make sense? How would the CustomerAggregate respond to, for example, a missing name or another hard constraint when responding to the SocialSecurityNumberOfNewCustomerWasUniqueEvent?
The search term you are looking for is set-validation.
Relational databases are really good at domain agnostic set validation, if you can fit the entire set into a single database.
But, that comes with a cost; designing your model that way restricts your options on what sorts of data storage you can use as your book of record, and it splits your "domain logic" into two different pieces.
Another common choice is to ignore the conflicts when you are running your domain logic (after all, what is the business value of this constraint?) but to instead monitor the persisted data looking for potential conflicts and escalate to a human being if there seems to be a problem.
You can combine the two (ex: check for possible duplicates via query when running the domain logic, and monitor the results later to mitigate against data races).
But if you need to maintain an invariant over a set, and you need that to be part of your write model (rather than separated out into your persistence layer), then you need to lock the entire set when making changes.
That could mean having a "registry of SSN assignments" that is an aggregate unto itself, and you have to start thinking about how much other customer data needs to be part of this aggregate, vs how much lives in a different aggregate accessible via a common identifier, with all of the possible complications that arise when your data set is controlled via different locks.
There's no rule that says all of the customer data needs to belong to a single "aggregate"; see Mauro Servienti's talk All Our Aggregates are Wrong. Trade offs abound.
One thing you want to be very cautious about in your modeling, is the risk of confusing data entry validation with domain logic. Unless you are writing domain models for the Social Security Administration, SSN assignments are not under your control. What your model has is a cached copy, and in this case potentially a corrupted copy.
Consider, for example, a data set that claims:
000-00-0000 is assigned to Alice
000-00-0000 is assigned to Bob
Clearly there's a conflict: both of those claims can't be true if the social security administration is maintaining unique assignments. But all else being equal, you can't tell which of these claims is correct. In particular, the suggestion that "the claim you happened to write down first must be the correct one" doesn't have a lot of logical support.
In cases like these, it often makes sense to hold off on an automated judgment, and instead kick the problem to a human being to deal with.
Although they are mechanically similar in a lot of ways, there are important differences between "the set of our identifier assignments should have no conflicts" and "the set of known third party identifier assignments should have no conflicts".
Do you also need to verify that the social security number (SSN) is really valid? Or are you just interested in verifying that no other customer aggregate with the same SSN can be created in your CRM system?
If the latter is the case I would suggest to have some CustomerService domain service which performs the whole SSN check by looking up the database (e.g. via a repository) and then creates the new customer aggregate (which again checks it's own invariants as you already mentioned). This whole process - the lookup of existing SSN and customer creation - needs to happen within one transaction to to ensure consistency. As I consider this domain logic a domain service is the perfect place for it. It does not hold data by itself but orchestrates the workflow which relates to business requirements - that no to customers with the same SSN must be created in our CRM.
If you also need to verify that the social security number is real you would also need to perform some call the another service I guess or keep some cached data of SSNs in your CRM. In this case you could additonally have some SocialSecurityNumberService domain service which is injected into the CustomerService. This would just be an interface in the domain layer but the implementation of this SocialSecurityNumberService interface would then reside in the infrastructure layer where the access to whatever resource required is implemented (be it a local cache you build in the background or some API call to another service).
Either way all your logic of creating the new customer would be in one place, the CustomerService domain service. Additional checks that go beyond the Customer aggregate boundaries would also be placed in this CustomerService.
Update
To also adhere to the nature of eventual consistency:
I guess as you go with event sourcing you and your business already accepted the eventual consistency nature. This also means entries with the same SSN could happen. I think you could have some background job which continually checks for duplicate entries and depending on the complexity of your business logic you might either be able to automatically correct the duplicates or you need human intervention to do it. It really depends how often this could really happen.
If a hard constraint is that this must NEVER happen maybe event sourcing is not the right way, at least for this part of your system...
Note: I also assume that command de-duplication is not the issue here but that you really have to deal with potentially different commands using the same SSN.

DDD Modify one aggregate per transaction with invariants in both aggregates

Suppose I have an aggregate root Tenant and an aggregate root Organization. Multiples Organizations can be linked to a single Tenant. Tenant only has the Id of the Organizations in it's aggregate.
Suppose I have the following invariant in the Organization aggregate: Organization can only have one subscription for a specific product type.
Suppose I have the following invariant in the Tenant aggregate: only one subscription for a product type must exists across all Organizations related to a Tenant.
How can we enforce those invariants using the one aggregate per transaction rule?
When adding a subscription to an Organization, we can easily validate the first invariant, and fire a domain event to update (eventual consistency) the Tenant, but what happens if the invariant is violated in the Tenant aggregate?
Does it imply to fire another domain event to rollback what happens in the Organization aggregate? Seems tricky in the case a response had been sent to a UI after the first aggregate had been modified successfully.
Or is the real approach here is to use a domain service to validate the invariants of both aggregates before initiating the update? If so, do we place the invariants/rules inside the domain service directly or do we place kind of boolean validation methods on aggregates to keep the logic there?
UPDATE
What if the UI must prevent the user from saving in the UI if one invariants is violated? In this case we are not even trying to update an aggregate.
One thing you might want to consider is the possibility of a missing concept in your domain. You might want to explore the possibility of your scenario having something as a Subscription Plan concept, which by itself is an aggregate and enforces all of these rules you're currently trying to put inside the Tenant/Organization aggregates.
When facing such scenarios I tend to think to myself "what would an organization do if there was no system at all facilitating this operation". In your case, if there were multiple people from the same tenant, each responsible for an organization... how would they synchronize their subscriptions to comply with the invariants?
In such an exercise, you will probably reach some of the scenarios already explored:
Have a gathering event (such as a conference call) to make sure no redundant subscriptions are being made: that's the Domain Service path.
Each make their own subscriptions and they notify each other, eventually charging back redundant ones: that's the Event + Rollback path.
They might compromise and keep a shared ledger where they can check how subscriptions are going corporation wide and the ledger is the authority in such decisions: that's the missing aggregate path.
You will probably reach other options if you stress the issue enough.
How can we enforce those invariants using the one aggregate per transaction rule?
There are a few different answers.
One is to abandon the "rule" - limiting yourself to one aggregate per transaction isn't important. What really matters is that all of the objects in the unit of work are stored together, so that the transaction is an all or nothing event.
BEGIN TRANSACTION
UPDATE ORGANIZATION
UPDATE TENANT
COMMIT
A challenge in this design is that the aggregates no longer describe atomic units of storage - the fact that this organization and this tenant need to be stored in the same shard is implicit, rather than explicit.
Another is to redesign your aggregates - boundaries are hard, and its often the case that our first choice of boundaries are wrong. Udi Dahan, in his talk Finding Service Boundaries, observed that (as an example) the domain behaviors associated with a book title usually have little or nothing to do with the book price; they are two separate things that have a relation to a common thing, but they have no rules in common. So they could be treated as part of separate aggregates.
So you can redesign your Organization/Tenant boundaries to more correctly capture the relations between them. Thus, all of the relations that we need to correctly evaluate this rule are in a single aggregate, and therefore necessarily stored together.
The third possibility is to accept that these two aggregates are independent of each other, and the "invariant" is more like a guideline than an actual rule. The two aggregates act like participants in a protocol, and we design into the protocol not only the happy path, but also the failure modes.
The simple forms of these protocols, where we have reversible actions to unwind from a problem, are called sagas. Caitie McCaffrey gave a well received talk on this in 2015, or you could read Clemens Vasters or Bernd Rücker; Garcia-Molina and Salem introduced the term in their study of long lived transactions.
Process Managers are another common term for this idea of a coordinated protocol, where you might have a more complicated graph of states than commit/rollback.
The first idea that came to my mind is to have a property of the organization called "tenantHasSubscription" that property can be updated with domain events. Once you have this property you can enforce the invariant in the organization aggregate.
If you want to be 100% sure that the invariant is never violated, all the commands SubscribeToProduct(TenantId, OrganizationId) have to be managed by the same aggregate (maybe the Tenant), that has internally all the values to check the invariant.
Otherwise to do your operation you will always have to query for an "external" value (from the aggregate point of view), this will introduce "latency" in the operation that open a window for inconsistency.
If you query a db to have values, can it happen that when the result is on the wire, somebody else is updating it, because the db doesn't wait you consumed your read to allow others to modify it, so your aggregate will use stale data to check invariants.
Obviously this is an extremism, this doesn't mean that it is for sure dangerous, but you have to calculate the probability of a failure to happen, how can you be warned when it happen, and how to solve it (automatically by the program, or maybe a manual intervention, depending on the situation).

DDD Customer, Contacts, and Addresses (aggregate root)

I'm building an application that manages most of the LOB stuff at my company. I'm trying to wrap my head around DDD... starting with customer management. Many examples are very, very simple in regards to the domain model which doesn't help me much.
My aggregate root is a Customer class, which contains a collection of Addresses (address book), a collection of Contacts, and a collection of communication history.
Seems like this aggregate root is going to be huge, with functions to modify addresses, contacts (which can have x number of phone numbers), and communication.
E.G.
UpdateCustomerName(...)
SetCustomerType(...) // Business or individual
SetProspect(...) // if the customer is a prospect
SetDefaultPaymentTerms(...) // line of credit, etc. for future orders
SetPreferredShippingMethod(...) // for future orders
SetTaxInfo(...) // tax exempt, etc.
SetCreditLimit(...)
AddAddress(...)
RemoveAddress(...)
UpdateAddress(...)
VerifyAddress(...)
SetDefaultBillingAddress(...)
SetDefaultShippingAddress(...)
AddContact(...)
UpdateContact(...)
RemoveContact(...)
SetPrimaryContact(...)
AddContactPhoneNumber(...)
RemoveContactPhoneNumber(...)
UpdateContactPhoneNumber(...)
AddCommunication(...)
RemoveCommunication(...)
UpdateCommunication(...)
etc.
I've read that value objects don't have identity. In this system, each address (in the database) has an ID, and has a customerId as the foreign key. If Address is it's own aggregate root, then I wouldn't be able to have my business logic for setting default billing / shipping. Many examples have value objects without an ID... I Have no idea how to persist the changes to my Customer table without it.
Anywho, feels like I'm going down the wrong path with my structure if its going to get this ginormous. Anyone do something similar? Not sure how I can break down the structure and maintain basic business rules (like making sure the address is assigned to the customer prior to setting it as the default billing or shipping).
The reason that you're butting up against the issue of where business logic should lie is because you're mixing bounded contexts. LoB applications are one of the typical examples in DDD, most of which show the application broken up into multiple bounded contexts:
Customer Service
Billing
Shipping
Etc.
Each bounded context may require some information from your Customer class, but most likely not all of it. DDD goes against the standard DRY concept when approaching the definition of entities. It is OK to have multiple Customer classes defined, one for each bounded context that requires it. In each bounded context, you would define the classes with properties and business logic to fulfill the requirements within that bounded context:
Customer Service: Contact information, contact history
Billing: Billing address, payment information, orders
Shipping: Line items, shipping address
These bounded contexts can all point to the same database, or multiple databases, depending on the complexity of your system. If it is the same database, you would set up your data access layer to populate the properties required for your bounded context.
Steve Smith and Julie Lerman have a fantastic course on Pluralsight called Domain-Driven Design Fundamentals that covers these concepts in depth.

What if domain event failed?

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

How granular should a domain event be?

I am wondering how granular should a domain event be?
For example I have something simple, like changing the firstName, the secondName and the email address on a profile page. Should I have 3 different domain events or just a single one?
By coarse grained domain events when I add a new feature, I have to create a new version of the event, so I have to add a new event type, or store event versions in the event storage. By fine grained domain events I don't have these problems, but I have too many small classes. What do you think, what is the best practice in this case?
What's the problem with many classes? Really, why so many devs are afraid of having too many classes? You define as many classes as needed.
A domain event signals that the domain changed in a certain way. It should contain all the relevant information and it should be taken into consideration the fact that an event is also a DTO. You want clear events but it's up to the developer to decide how granular or generic an event is.
Size is not a concern, however if your event 'weights' 1 MB maybe you have a problem. And the number of classes is not a domain event design criteria.
I can agree with MikeSW's answer, but applying SRP during the modeling, you can end up with small classes, which is not a problem at all.
According to Greg Young the domain events should always express something that the user does from a business perspective. For example if the user has 2 reasons to change her phone number PhoneNumberChanged, and this information can be important from a business perspective, then we should create 2 event types PhoneNumberMigrated, PhoneNumberCorrected to store technically the same data. This clearly violates DRY, but that is not a problem, because SRP can override DRY in these cases as it does by sharing aggregates and their properties (most frequently the aggregate id) between multiple bounded contexts.
In my example:
I have something simple, like changing the firstName, the
secondName and the email address on a profile page.
We should ask the following: why would the user want that, has it any importance from the perspective of our business?
her account was stolen (security, not business issue)
she moved to another email address
she got married
she hated her previous name
she gave the account to somebody else on purpose
etc...
Well, if we have dating agency services then logging divorces can have probably a business importance. So if this information is really important, then we should put that it into the domain model, and create an UserProbablyDivorced event. If none of them are important, then we can simple say, that she just wanted to change her profile page, we don't care why, so I think in that case both UserProfileChanged or UserSecondNameChanged events can be acceptable.
The domain events can be in 1:1 and in 1:n relation with the commands. By 1:1 relation they name is usually the same as of the commands, but in a past tense. For example ChangeUserProfile -> UserProfileChanged. By 1:n relation we usually split up the behavior which the command represents into a series of smaller domain events.
So to summarize, it is the domain developer's decision how granular the domain events should be, but it should by clearly influenced from a business perspective and not just from a modeling a data schema perspective. But I think this is evident, because we are modeling business and not just data structure.

Resources