I recently decided to learn Domain Driven Design. I came up with a hypothetical application and tried designing the architecture for it. It is a simple Poing-Of-Sale application with bounded contexts Sales and Inventory. This is where I have two conflicting designs when implementing the code for these bounded contexts.
Design #1:
Anything and everything that has to do with inventory belongs in inventory bounded context.
If a sales order comes in, the request initially enters the sales bounded context, then one of the steps to make the sale, you must check the inventory to see if the item is available. In which case, you request the inventory context (however this is done within the system). Inventory context will check the database and respond back with availability confirmation. This way any other bounded contexts that need any kind of inventory involved logic would use this bounded context to achieve it. Code is encapsulated and good to go.
Design #2:
The division of bounded contexts are strictly at the business level divisions in their operational contexts.
If a sales order comes in and hits the sales bounded context, it should contain all the logic in code that has to do with sales. It would check the database whether an inventory is available via the service, it would then remove that item from the inventory, record the sales in database via the service again, send out an sales made notification email to admin if this is a requirement. Just everything and anything that has to do with sales will all happen in this bounded context. Once the sale is made, it could fire an event sale made, and inventory context would listen to this to check the inventory in the database, see if new purchases need to be made to bring in new inventory or not as it is an operation related to inventories at the business level.
I am just trying to understand what Domain Driven Design approach is in such system. Thanks.
=================================
After some thought this is the added question to the original.
Let's say your business needs to do shipping. Whether it would be due to making a sale (Sales Bounded Context) or due to a warranty replacement (Support Bounded Context). What if shipping itself is complicated depending on situations. Where certain products or shipping addresses you need to make the decision to ship it yourself or via some 3rd party shipping company using a web service. Does the "shipping" deserve its own Shipping Bounded Context? Or it simply is just another domain logic embedded in the Sales Bounded Context and the Support Bounded Context? This is all within the case of simple retail store domain.
My 2 cents... Design #2 seems better as Design #1 should lead you to a distributed system. You do not want a distributed system. You should not take storage or tables into account before getting the business. Just consider business, and when you get it, consider how you could be able to get your BC run in complete isolation (offline mode vs distributed mode). If data is missing, then consider using Domain Events to propagate this knowledge to your BC.
Design #1 is the correct one. Inventory context should be the only one which decides and knows how to check for inventory. It could be the inventory context is checking from multiple places and those could be changing based on meta data updates as new data warehouses come online. At some point retailer might decide to have all physical shops as data warehouses as well.
Similarly shipping should be a context as well. Notes above said we should not aim for distributed system but I don't see why not if that provides agility.
Related
I have a scenario for which I have to design a use case diagram, activity diagram and a class diagram:
“I run a small computer consultancy firm with a number of employees.
Along with the basic information about the employees (name, DoB,
contact details, etc.) I need to be able to keep track of what type of
role they perform, such as Hardware Technician, Programmer, and
Software Installer. A single employee can perform multiple roles, and
each role has an associated hourly pay. I need to keep name and
contact details of all customers that have a contract with us. A
customer can have multiple contracts at the same time, but each
contract is only associated with one customer. Each contract has a
name, a description, a creation date, and a job type – e.g. System
Development, Software Upgrade. No details of job types need to be
captured other than their name. Each contract also has a single
employee designated as the project leader. One employee may be the
project leader of multiple contracts.”
I have tried to draw a use case diagram and I want to know if I have drawn it correct and if there are any mistakes or any improvements that should be made:
Let's analyse your requirements, to identify use cases:
Manage employee
I run a small computer consultancy firm with a number of employees.
Along with the basic information about the employees (name, DoB,
contact details, etc.) I need to be able to keep track of what type of
role they perform, such as Hardware Technician, Programmer, and
Software Installer. A single employee can perform multiple roles, and
each role has an associated hourly pay.
Manage customer data (may be included in contract management)
I need to keep name and contact details of all customers that have a contract with us.
Manage contracts
A customer can have multiple contracts at the same time, but each contract is only associated with one customer. Each contract has a name, a description, a creation date, and a job type – e.g. System Development, Software Upgrade. No details of job types need to be captured other than their name.
Assign project leaders (may be included in contract management)
Each contract also has a single employee designated as the project leader. One employee may be the project leader of multiple contracts.”
Now, more use case may be hidden behind these sentence and could be deduced. However, let's see critically if the additional ones you've identified fit.
The following seem ok at first sight:
Make contract (more precise than manage contract. On the other hand, what with contract modification and termination?)
Give contact details (par of manage contract)
Keep customer details (similar to manage customer data) but who 'd be the owner ?
Assign a project leader (see above)
Assign other members (excellent: not explicitly mentioned , but if employees are assigned to roles and hourly pay, it's certainly because it's relevant to assign them to projects)
Assign employees to project (see previous bullets)
The following use case are questionable:
Accept contract: will the owner of the contract (who is it: the customer ? the leader ? s.O. else ?) really accept it IN THE SYSTEM ?
Perform role: is it implied here, that the employees will use the system to perform their role ? Or will they just register some time for the projects ? Or will they not interact with the system at all ?
get paid hourly (same question)
Leading the project: will the project leader interact with the system to lead the project ? or is he/she just registered as leader for administrative responsibility purpose ?
Finally, some of these requirements go beyond the (goal oriented) use case, and describe the class model. Don't get trapped by this: the use case should focus on the actor interaction with the system.
I have an ERP project with multiple sub-domains. It is not using CQRS or domain events.
I have two sub-domains; CRM and Accounting. The customer concept needs to be modeled differently in the two sub-domains. CRM needs to know the size (number of employees) of the company but not the tax number. Accounting needs to know the tax number but not the size. The company name is needed by both sub-domains.
I am thinking of modeling both CRM Customer and Accounting Customer as entities. But then whenever a new customer is created by a CRM user, an Accounting Customer instance also needs to be created. And if a report needs information from both sub-domains, then the queries become more complicated then when you have single entity containing all the information.
Is this the way to go? Is there a better way? Does it make sense to have multiple sub-domains without utilizing domain events?
Are you sure you need DDD? The use case seems quite simple, maybe you just left out all the other complexities, but from just the info you're asking, a simple CRUD app would do. Data Centric apps, like reporting, don't need DDD. You need DDD when you must modify the data in strict ways, to maintain consistency.
If you are sure you do need DDD, then you need to understand the point of the model is to protect against the invariants of the domain. You say a CRM Customer must always have an equivalent Accounting Customer. How is this handled by the business today? How does accounting know about CRM customers? How does accounting know they're talking about the same customer as CRM? However they are doing it currently, is what you should try to model.
As an example, if they do it in real life by just letting the other one know. You could have your CRM context publish a new Customer event, and your Accounting context could react to it by creating an Accounting Customer for it.
If on the other hand, they both learn about it from something else, then maybe they both react to that other something's event.
If you don't want to use events, it could be a direct call, from the CRM context to the Accounting context. Though know that this would grow more restricted as the app grows, but if again you've got a simple domain, its no problem.
Also, querying data is not the same as modifying it. Queries should not use the domain model entities and value objects. It could, but it should not be constrained by it. That's because query is a read only operation. You need to put your data inside your domain model only when you are going to change it.
What I'm trying to achieve is to develop an application implementing the DDD approach.
The story might sound silly but it's an actual, real life problem. Believe me.
The business looks as follows:
Let's say a company specializes in manufacturing sweets which are distributed to its own shops for sale.
The craftsman makes different types of candy depending on what is - and what is not - currently at the display at one of the company's shop.
When a basket of one flavour 'disappears' the seller replaces this type of sweet with a different kind from the shops storage cabinet.
Duplicates of flavours at the display shouldn't exist and the display should be populated with as much as the capacity allows or how much the manafacturer can handle to produce.
The sweets are distributed from the manufacturer's lab's storage to the shop's one depending on the demand.
Let's assume each worker has public view access to the display and the storage cabinet. Each worker (user) decides on it's own what to provide. The shops display view will be publicly accessible through the application to a potential client as an information what is currently on sale.
So far I have split the business logic into three separate (sub?)domains which are:
Production
Distribution
Sale
And of course each entity like Sweets, Storage, Craftsman, it's Repository etc. are placed respectively in their domain.
The concerns I approach are:
Is it appropriate that an entity (Sweet) is being passed from one domain to another?
Should a Provider be able to reach the StorageCabinet of one domain and pass it's content to another?
Is my reasoning proper? Correct me if I'm wrong or violating any DDD rules.
Thanks in advance.
The story might sound silly but it's an actual, real life problem.
This is great, actually. In his recent retrospective, one of the things that Greg Young called out is that "shopping cart" models are a really lousy as a teaching tool. He points out briefly that the interesting questions are in the supply chain.
Is it appropriate that an entity (Sweet) is being passed from one domain to another?
No, but a message (DTO) describing an entity's state might be passed from one domain to another.
You want to keep the flexibility to define the entities differently in each domain; that's part of the point of identifying bounded contexts.
Should a Provider be able to reach the StorageCabinet of one domain and pass it's content to another?
Probably not: your domain model isn't the book of record for the storage cabinet. Listen very carefully to Greg's comments on one way commands.
So we may apply the domain driven design for multiple projects but there could be intersection of the same piece of domain model.
In this case, how to apply the domain driven design (use ORM, model first, generating database schema)? Create multiple databases with a lot of same tables? Or how to share data? Use synonyms? What is the possible strategy to resolve the sharing model (including data)?
Any suggestion is welcome. Thanks in advance!
In my previous project we had a lot of discussions regarding having redundant info in several models that have some shared parts.
What we found interesting is that we thought that several projects (not C# proj, but real large development projects) or call it systems very rarely share the exact same perspective on how using the model. We thought that in a larger domain that spans over several application/systems/projects you could spot several core's where you don't want the cores to be duplicated in each application.
It all ended up with a domain that where distributed on several machines. And we had GUID keys to bind them together in database. But since we did this "model first", sub domains looked at each other like infrastructure related services that where reached through Domain events.
Complicated? Not really. Here's an example:
Domain one (Salary review system) - We have a Salary Review statistic system which conduct evaluation on employees salary and how they related to their experience, age and performance. The Core is questionnaire form, work evaluation, questionnaire answers, rating. salary modification advices etc.
Domain two (Employee system) - Here you manage your employee, register new employees, handle rehab, maybe personal development, salary, employee contract, employee benefits etc.
Domain three (Performance management) - Here you handle history of employee experience, goals, achievements, and agreements between boss and employees about personal development, rating and grade of performance.
As you notice the Core of each domain is different but they share some concerns. Depending on deployment, infrastructure and requirement on how tight they should relate/respond to each other - the tech how to solve this could differ.
I Prefer to do this tech independent. We used NServiceBus for synchronizing domain through Domain Events (Udi Dahn's Domain Event Pattern).
For instance, Once we have completed a salary review for an employee and boss should be informed that Joe should get a chance of salary increase with 200 - 500 $ this year.
The method ApplySalaryReview on entity aggregate root Employee do not only save the review result, it also trigger domain event NotifySalaryReviewSubscribers which trigger an eventhandler HandleNotifySalaryReviewSubscribersEvent in Application layer that takes a infrastructure service in ctor. That service puts result in a message queue that all systems that need this info can subscribe on this message.
In our case, it is Domain two (Employee system). The employee system import result and notify employee's boss that he got new info for the upcoming salary talk with this particular employee.
I hope I may have shread some light on one way of doing it. There are so many other ways as well...
You might want to (re-)read the strategic design patterns in the blue book.
In my domain, I have 2 bounded contexts that are relevant to this question:
Purchasing - where the customer orders services
Fulfillment - where services are assigned to vendors to be completed
It's a requirement that an order is editable by the customer at any given time throughout the life of the order.
If a customer removes a service from an order (i.e. within the purchasing context), if that service has already been assigned to a vendor to be performed (but has not already been performed) that service must also be removed in the fulfillment context.
There's a couple of options here, and I'd like the community's opinion:
I have my contexts wrong because this will create a cross-context transaction.
I may not need transactional consistency here. Of course, that's for the business stakeholder to decide, which begs 2 questions: What are the implementation options? How do I pose this question to the business stakeholder?
This is an acceptable violation of the "no cross-context transactions" rule.
EDIT
This is all happening within a single process, so the likelihood of mid-transaction failure is very low.
Here's the question to ask your stakeholder, re: an order being editable at all times - what does it mean for an order to be edited after it has already been fulfilled?
Why is it necessary that when an order is edited, this impacts the fulfillment service?
This, in my mind, crosses the bounded contexts. An order, while being edited, should not leave its domain unless there is good reason to. Why would any order information be propagated to the fulfillment service before it is complete?
Based on my obviously very limited understanding of your domain, I would think that you would complete the order first, then send a creation event to the service bus, where it is picked up by the fulfillment service. Therefore, no transactions are taking place that cross contexts.