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.
Related
I am incredibly new to Domain Models and I am trying to build up my understanding. I have created this domain model around a scenario which I will provide. I feel this model is simple and as a result, feels incorrect and might be missing elements I might not have thought of although, I cannot think of what else might need to be included in a domain model given the scenario. The idea is to demonstrate the relationship between real world class entities which I feel I have managed to achieve.
Scenario: Management Application that allows you to create users, projects, companies and issue tickets. The projects are assigned to companies, the users are assigned to projects and the issue tickets are assigned to the users. Tickets have a status which can be changed.
Changes
Implementing proposed changes. I think this is a better way to represent the idea based on the feedback returned, especially in regards to the use of composition. I have also updated the multiplicities to better represent the scenario.
Further changes
The diagram should stay as simple as possible, but not more.
In this specific case:
The two specializations of User might be too complex for the need: a User stays a User, isn’t it? If you really need to take into account differences between categories of users, and especially if the category changes over time, you'd better consider (object) composition over inheritance (or better worded for UML: prefer association over inheritance).
The associations might be too simple or incomplete. For example, before an Issue ticket gets assigned to a User, isn’t it also associated to a Project or a Company? It is not clear either if User is also associated to Company (e.g. multi-tenant cloud scenario) or if there is no such association (e.g service provider scenario, where the company is in fact a customer company).
Some associations may hide association classes, e.g. do you expect to monitor how many time a user worked on a ticket?
It entirely depends on the purpose of your model.
Some models might be created to stimulate discussion and further discovery. Some might be required for the senior stakeholders to approve. Some might be for developers to work from. Others might be for marketing material.
Your model is ok for stimulating discussion and further discovery.
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.
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.
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.
Pardon the length here...hopefully I didn't go overboard...
I'm in the process of working on my first production MVC application and I'm trying to stick to DDD principles in the process. I've run into some questions related to how to deal with the security requirements of the application and thought I'd see if the SO community could offer some best-practice suggestions.
Domain Information
To use a simplified explanation, this application will have AffiliateCompanies, Users, and Customers.
AffiliateCompanies are hierarchal, so one affiliate can sign up and be tied to the activities of another affiliate. The root is the main company providing the products/services.
Users all belong to an Affiliate entity.
Customers are organizations to which the products/services are sold. Affiliates are assigned to customers such that it is possible for two hierarchically-unrelated affiliates to split a Customer.
Security Information
Rights to perform certain actions in the application will be determined based on an ACL-type of arrangement. Each User object has a property that is a collection of SystemAccessRules that determine what actions they can perform and what the scope of their permissions are (their own objects, their affiliate's objects, or their entire hierarchy's objects). Users can also belong to roles, which themselves have that same collection of SystemAccessRules.
As a result, if a user logs in and wants to see a list of "their" customers, the list could be comprised of customers they are individually assigned to, customers anyone in their affiliate organization is assigned to, or customers anyone in their organization or any of their child affiliate organizations are assigned to.
Database Considerations
DDD aside, at some point the storage strategy has to come into play. In this simple scenario, the tables align with the objects above (including a roles table), with a few support tables to support the relationships between the objects:
AffiliateCustomers - this table allows for a many-to-many relationship between affiliates and customers by storing the PK of each entity as a pair of FKs that are themselves a composite PK for this table.
ACL - this table stores the security information, specifically the subject of the entry (either a user or a role), the action in question (e.g. "CreateCustomer"), the permission (allow or deny), and a scope (their own stuff, their organization's, or their network's).
The Question...Finally
I'm using a combination of repositories and services. I'm trying to keep business logic in the services and out of the repositories or database, but due to the security design here, a simple request for the list of "their" customers could be immensely burdensome, especially as the data set grows. I was trying to use Linq where possible, but this architecture seems not to be very suited. As I see it, here are my choices:
Accept the requesting user as an argument for service methods (or determine it by context), and have the service method populate a list through multiple queries to Linq repository. This would require pulling the list of customers, then iterating through each customer to issue another query to pull the ACL data, then using that data to filter the first list based on permissions. The hierarchy issue would require some fancy Linq footwork (like this), if it's possible at all.
Even if the hierarchy issue could be made to work, it seems like this solution won't perform very well...
Accept the requesting user as an argument, but pass it and the required permission (e.g. "View Customers") to the repository in order to retrieve appropriate data from the database through a stored procedure that would use several EXISTS clauses in a CTE query that could account for the hierarchical nature of the data and the need to check for role and user security.
This pushes a fair amount of logic to the database, which seems very anti-DDD and generally bad.
I'm leaning more toward the second option, but that may be because in my past projects that's how I've done it. I'm not even sure if my design overall is on the right track (in the past the permission declarations were done using bit flags, so it was even easier to do the DB query using bitwise operator).
Has anyone been in similar situations, and if so can you comment on the performance and maintainability of the solution you pursued? I want to stick to high-minded programming principles, but not at the expense of simplicity and common sense.
Have you considered using the specification pattern to pass your business rules down to your data access layer?
The service constructs a specification tree which it passes to the repository. The repository converts the specification into an Expression<Func<Customer, bool>> which it passes to IQueryable<Customer>.Where(...). When the repository materialises the collection, e.g. by calling ToList(), the business rules are translated into SQL and executed on the database server.
Last time I checked, LINQ to SQL didn't support CTEs, so you may need to use a view to flatten the hierarchy.