I'm building an application using DDD. Its an employee appraisal application. As part of the Domain layer I have an Appraisal Document. What can be done to this document is dependant on the role the user plays in relation to the Appraisal Document but also is dependant on the document status.
Are these Domain concepts or is this the cross cutting concern - Security???
How do you relay to the UI what actions are permissible???
This is a somewhat tricky question. The problem might be that your business experts have already settled with the concept of an Appraisal Document, which is a relic of pre-computer eras or old applications that they are already used to. However, an Appraisal Document is a merely a pre-computer era tool that people use to document the actual appraisal process, but it is most probably not a concept that actually occurs in the real business of appraisals. For example, if you replaced the Appraisal Document with mouth-to-mouth communication, your appraisal process would most probably change only very little, and those security concerns on the Appraisal Document would translate to policies such as "a supervisor must not talk about an employee's appraisal with other employees" or "always get a 2nd opinion".
(I sometimes see a related problem in the area of medical health records where most doctors are already used to software, such that they seem to confuse the Electronic HR -- that documents something -- with the actual treatment/diagnosis -- to be documented.)
To solve this, your business experts should liberate from the concept of an Appraisal Document and focus on the actual appraisal process. As you said already, there are certain roles that people play during the appraisal, e.g., Supervisor, Participant, Employee, Referee, and the document status actually refers to a concept in the process (2nd eye principle or similar). These roles and the process should be modeled explicitly and precisely in your Appraisal BC, possibly involving a saga/long running process. It then also becomes clear that those security concerns that shall restrict access the Appraisal Document are actually constraints within the actual domain and are strongly tight to the respective roles and process state in your domain.
The application interface of your Appraisal BC could offer services to your application that uses the respective roles, e.g.,
gradeEmployee(String supervisorId, String employeeId, Integer grade)
or viewAppraisal(String viewingSuperVisorId, String appraisalId)
or involveReferee(...).
It is then the duty of the application interface of the Appraisal BC to ensure that the actions are actually allowed; for, it would call business methods of the domain model, e.g. AppRaisalDomainService.mayPublishReport(supervisor, appraisal)
All that is left to do in your Application is to map the users of your application to the respective supervisorId/employeeId. For an example, you may want to take a look at Vaughn Vernon's "Collaboration" bounded context in the [IDDD_Samples][1] repository, where people have roles such as Moderator, Author etc, and how the collaboration context is used from other related BCs.
Finally, in your UI you can then present the current state of the appraisal process to your users. The "details" page of a single appraisal will automagically become the "Appraisal Document" people are used to. You can even entitle your UI view by "Appraisal Document" or similar in order to satisfy your users, and if they print out that view, they actually hold such a document in their hand. In the underlying application, however, access is not restricted to the "Appraisal Document", but rather to the underlying appraisal process, and the access restrictions are a domain concept.
Related
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.
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 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.
Generally in UML, you model roles as opposed to people however if there is a use case to model people (along with their names, contact details, etc), is there a known way of depicting this?
For example do I create a superclass called "Person" and generalize the roles followed by a specialization of a real person?
I took a look at some of your other questions and now I realise I completely misunderstood and you're probably trying to model an organization and the people in it.
ArchiMate is a semantic layer on top of UML that is intended for architecture modelling. Real people get described in the business layer, as actors.
A business actor is defined as an organizational entity capable of (actively) performing behavior.
A business actor performs the behavior assigned to (one or more) business roles. Examples of business actors are humans, departments, and business units. A business actor may be assigned to one or more business roles. The name of a business actor should preferably be a noun.
Now generally the person fills a spot in the organization that in a couple years could be filled by another person. The structure / architecture of the organization would not change and as such the actor can be described by the name of their position, say, "Head of department" rather than by their name and phone number.
Still, I understand that it may be handy to have this sort of information available when you want to contact them.
UML-model-wise, I'd think that the actor Head of Department is a class, realizing a business role that's also a class, and that Joe with phonenumber 12345 is an object of that class.
But practically, I'd think this is too much detail for the level at which you're describing the organization. I'd suggest you stick a UML note on those few actors of key contacts whose names you think are worth mentioning in the diagram. But administrate the rest of them in a system that's more fit for this, like your company's ADS or Contacts in Microsoft Outlook.
We are trying to model an RBAC-based user maintenance system using DDD principles. We have identified the following entities:
Authorization is an Aggregate Root with the following:
User (an entity object)
List<Authority> (list of value objects)
Authority contains the following value objects:
AuthorityType (base class of classes Role and Permission)
effectiveDate
Role contains a List<Permission>
Permission has code and description attributes
In a typical scenario, Authorization is definitely the Aggregate Root since everything in user maintenance revolves around that (e.g. I can grant a user one or more Authority-ies which is either a Role or Permission)
My question is : what about Role and Permission? Are they also Aggregate Roots in their own separate contexts? (i.e. I have three contexts, authorization, role, permission). While can combine all in just one context, wouldn't the Role be too heavy enough since it will be loaded as part of the Authorization "object graph"?
Firstly I can't help but feel you've misunderstood the concept of a bounded context. What you've described as BC's I would describe as entities. In my mind, bounded contexts serve to give entities defined in the ubiquitous language a different purpose for a given context.
For example, in a hospital domain, a Patient being treated in the outpatients department might have a list of Referrals, and methods such as BookAppointment(). A Patient being treated as an Inpatient however, will have a Ward property and methods such as TransferToTheatre(). Given this, there are two bounded contexts that patients exist in: Outpatients & Inpatients. In the insurance domain, the sales team put together a Policy that has a degree of risk associated to it and therefore cost. But if it reaches the claims department, that information is meaningless to them. They only need to verify whether the policy is valid for the claim. So there is two contexts here: Sales & Claims
Secondly, are you just using RBAC as an example while you experiment with implementing DDD? The reason I ask is because DDD is designed to help solve complex business problems - i.e. where calculations are required (such as the risk of a policy). In my mind RBAC is a fairly simple infrastructure service that doesn't concern itself with actual domain logic and therefore doesn't warrant a strict DDD implementation. DDD is expensive to invest in, and you shouldn't adopt it just for the sake of it; this is why bounded contexts are important - only model the context with DDD if it's justifiable.
Anyway, at the risk of this answer sounding to 'academic' I'll now try to answer your question assuming you still want to model this as DDD:
To me, this would all fit under one context (called 'Security' or something)
As a general rule of thumb, make everything an aggregate that requires an independent transaction, so:
On the assumption that the system allows for Authorities to be added to the Authorization object, make Authorization an aggregate. (Although there might be an argument for ditching Authorization and simply making User the aggregate root with a list of Authorities)
Authorities serve no meaning outside of the Authorization aggregate and are only created when adding one, so these remain as entities.
On the assumption that system allows for Permissions to be added to a Role, Role becomes an aggregate root.
On the assumption that Permissions cannot be created/delete - i.e. they are defined by the system itself, so these are simple value objects.
Whilst on the subject of aggregate design, I cannot recommend these articles enough.