I'm getting confused on how to define bounded contexts where there are shared concerns between them, and how to represent this with Domain Entities.
For example:
A customer has many products in a Customer context
A company has and a list of products in the Company context
So the customer is managed via the customer context, and the company via the company context
Given the contexts are in differnt modules.
If I want to provide the Company's address details with a product, how should this be handled?
Do I reference the module containing the Company context in the module containing the customer, or do I create a Company entity in the customer context specifically for use when interacting with customers?
Thank you
You can have different representations of the same entity in different bounded contexts. Company in Company BC can be very different from company in User BC. All they have to share is some kind of correlation Id.
This is how we approached it in our project as well.
For one bounded context we used a contract as an Aggregate Root, while in another bounded context we used the contract as a value object/entity
In the first module/BC we had a big contract class with a lot of behavior in it, while in the second module/BC we had another contract class, which only contained a few properties with private setters.
This way it would be possible to separate the 2 BC's into separate assemblies of services in a SOA design even.
Related
We have an aggregate for a company without a specific context, because we migrated an older CRUD implementation to CQRS/ES. This aggregate contains basic information about the company, like name, email, etc. It also acts as the foreign key for many other entities that refer to companies (we acknowledge that this is not the best approach, and that the company aggregate could be the root of those other entities).
We are implementing a feature for blocking defaulting customers. Our idea was to create a new and more specific Billing context, in which the Company appears, containing logic and data for this purpose of blocking/unblocking the company only.
So the first, older aggregate is the "main" one for all use cases, and the new one is only for the blocking feature.
Our questions are:
Is this approach sensible?
Is it a good practice to reflect the company in two contexts, in each with its specific company aggregate?
In this case, should we create the two aggregates beforehand or is it reasonable to defer the creation of the new aggregate until we effectively need it, when we block a company for the first time? (And until the Billing Company aggregate is created, we assume a default value for the company being blocked or not).
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.
I'm struggling to understand how to model my problem:
A Company can have many Teams.
Each Team must have a unique name per Company.
Reports for a particular Team must be retrievable, along with a list of all reports for a Company.
Just now, I have 3 Bounded Contexts's - Company, Team and Report. I believe I should move Team inside Company to enforce my unique name invariant - however, as I understand it:
"Nothing outside the Aggregate boundary can hold a reference to
anything inside, except to the root Entity".
If I can only reference an AR from my Report AR, I cannot store which Team my report belongs to - just the company.
I have considered that Team may exist as it's own BC and also within the Company BC. Creation of a Team would then only happen from within the Company BC as an Entity. Here, the naming and invariant enforcement of that Team name can be ensured. The Team BC would then still exist and a Report can still hold reference to the TeamId from the Report AR.
However, this would result in duplication of TeamId and TeamName - both within the Company BC and Team BC.
Does this approach sound ok, or am I missing something?
I'm confused if I have 3 BC's that should be 2 BC's, or missing a Team Entity concept within Company BC.
Maybe I'm confusing Bounded Contexts I only have/need Aggregate Roots - I'm not sure!
Gulp, help!
In your example Company and Team cannot be Bounded Contexts, it is entity (Company or Team can be Aggregation Root, it depends on the task), Company has Name identity, Team has CompanyName + TeamName identity.
Bounded Context is a cohesive set of models, which should reflect the meaning of the selected subdomain. Team and Company can form one BC, Reporting is another context.
If in your example Reporting is simply aggregate some information for easy display to the user, then this Reporting Bounded Context doesn't contain any Aggregation Roots, because there's no business logic and rules. In Reporting you should use simple DTOs to display the data.
Here is an example:
I have the generic type called "Account". I wish to use this account to represent multiple business entities:
1. Customer
2. Client
3. Company
I wish to use the Account type for the above 3 entities (as they are all types of accounts in my system - where the type is an attribute of the Account). How would I represent this relationship?
The only relationship you've described is that 'type' is an attribute of the Account. If Customer, Client, or Company are not strong enough entities on their own to deserve their own box on the Domain diagram, then you are done. In that case, you can include a note box associated with Account and say "Examples of values for the Type field: Customer, Client, Company, etc.".
If that is not strong enough, you may think about creating an AccountType class which have as sub-classes Customer, Client, Company. In that case you would draw an association from Account to AccountType, which replaces the need for the 'Type" attribute.
When I get a chance, I'll draw examples and post links to them.
You can model the template class (Account) and then bind it to create three different classes using the association link and the bind stereotype on the link, as you can see here, under the "Class Template" title.
I believe the diagram I would use to communicate these relationships between diffrent objects is the "Collaboration" diagram, as what the relationships show is how the different objects are instantiated (Account is instantiated as Customer, Client and Company) and how they (the instances) would interact with each other
I've got a system that allows classroom instructors and graders to log in and manage classes and grade papers. A user can be both an instructor and a grader, and can be so for particular semesters. Other users, like students, are also bound to this semester scheme. Still others, like administrators, have accounts that don't run by semester.
When someone is no longer a grader or instructor, she still needs to be able to access past grading or classroom records, albeit with fewer privileges (view only).
I've thought about implementing a roles table with a semester as a part of the key, but that doesn't apply to all users. I've also thought about keeping the semester data separate from the roles, but making roles like "PastGrader" and "PastInstructor" to cover those people who need to have access to past information but should not be allowed to participate in this semester.
What is the optimal data model/roles model for this application?
I think you're on the right track. I would keep the semester out of the roles table, but use them together where needed.
Here is what I did recently that will also work in your scenario:
Create a FunctionalRole table that has the following columns:
FunctionalRoleId, FunctionalRoleName
These roles will be like jobs. Teacher, Grader, etc.
Add another table called FeatureRole, with the following columns:
FeatureRoleId, FeatureRoleName
These roles will be for specific features in the application. GradePapers, ViewPapers, etc.
Then create a third table... call it RoleMember, that has these columns:
FunctionalRoleId, FeatureRoleId
That way, the admin can assign roles more simply by the job and all of the feature roles will automatically be assigned.
And like I said, keep the semester information separate.
Gabriel
I think that you need an additional entity to help you out. You clearly have the domain object of a CLASS to represent a specific class (ie: Composition II is a class). You also clearly have a domain object for PARTICIPANT to represent the people that attend the class. I think you have already identified those two.
Next, you need a domain object to represent a specific semester/timeslot/classroom where a CLASS will be held. Let’s call that domain object a CLASSSCHEDULE. You will need a relationship from CLASS to CLASSSCHEDULE to show what topic will be taught in that room during that semester.
Now you need a domain object to represent how a PRATICIPANT interacts with a CLASSSCHEDULE. We can call this domain object an ENROLLMENT. The ENROLLMENT object is where you put your privileges for the PARTICIPANT. The PARTICIPANT is ENROLLed in the CLASSSCHEDULE as a learner or a grader. Your role is attached to the ENROLLMENT object. In this way, each PARTICIPANT will have a different privilege level for each CLASSSCHEDULE that they are involved with.