consider I am having an Event with Invitations (each "invited person" represents an Invitation, so multiple Invitations are out for a single Event):
[«aggregate root»;Invitation]<>1..*-[«value object»;EventIdentifier]
[«value object»;EventIdentifier]-<>[«aggregate root»;Event]
[«value object»;Invitee|emailAddress;facebookIdentifier]-<>[«aggregate root»;Invitation]
The Invitee, however, can bei either an Email Address or a facebookIdentifier, that's the nature of the business logic.
Usually I would have made an AbstractInvitee with FacebookInvitee and EmailInvitee, and created an association to the abstract, but that's evil as I know now.
Should I, instead, have actually FacebookInvitee and EmailInvitee and the Invitation has each a facebookInvitee and an emailInvitee property; and a Service or so would merge them together, if necessary?
Thanks for your advice!
Edit
I just came to the following idea which looks rather neat,
[«value object»;Invitee|type;identifier]-<>[«aggregate root»;Invitation]
The type is somehow a constant with FACEBOOK and EMAIL, and the identifier then is the FB UID or the email address respectively.
Usually I would have made an AbstractInvitee with FacebookInvitee and
EmailInvitee, and created an association to the abstract, but that's
evil as I know now.
Inheritance is not that evil.
If your classes FacebookInvitee and EmailInvitee have the same interface I see no reason to avoid inheritance. Inheritance adds complexity if interfaces are different and casting to concrete types is needed.
The type is somehow a constant with FACEBOOK and EMAIL, and the
identifier then is the FB UID or the email address respectively.
Your example is very similar to Replace Subclass with Fields refactoring. Anyway it will be needed to write if-else code-block to check invitee type and use its identifier for sending an invitation somewhere. Who should be responsible for it? In your solution Invitee is simply a DTO without behaviour. If Invitee has behaviour and can Send() an invitation itself then I would use inheritance and implement Send() for every concrete class (e.g. FacebookInvitee, EmailInvitee).
I'd still keep an abstract Invitee value object with 2 derivatives EmailInvitee and FacebookInvitee.
Each type of Invitee can raise its own flavor of WasNotified Domain Event which is then captured by an Infrastructure layer notification service that knows how to handle it.
I like your idea in edit.
You could place a NotificationService in the domain layer and add adapters in the infrastructure layer(FacebookNotificationService / EmailNotificationService).
And a NotificationDispatcher(it is also an adapter but aggregates other adapters) to dispatch notification(by invitee type) to the corresponding adapter.
Related
I have an aggregate root called User.
Here's an example of how it's modelised:
User: {
id: string
username: string,
email: string,
auth: LocalAuth {
password: string
}
}
In my application, I have an API route -
POST /users/id/password - that allow users to change their password.
In order to change their password, we must ensure that users enters their old password. The request model should look like this:
{
oldPassword: string
newPassword: string
newPasswordRepeating: string // in case of user errors
}
The controller that handle this request should do the following:
Check if the oldPassword is equal to the current one
Check if the newPassword is valid
Update the user data
Return the updated user data
In order to handle such business logic, I could create a VO model named PasswordUpdate (idk..). This VO could encapsulate the validation logic in its own model.
Does this kind of implementation faithfully follows the DDD rules?
Because in my case, this VO is never contained in an Aggregate Root and is not stored. The purpose is only to modelise a password update with a domain model.
Does this kind of implementation faithfully follows the DDD rules?
Very short answer: go right ahead.
Short answer: the DDD police are not going to come after you anyway, so don't over think it.
Broad answer: I find that the description of Value Objects by Evans is something of a muddle, polluted by the fact that he was drawing from experience in Java.
But if you look really carefully, what's going on is that Evans is proposing the creation of a domain specific language that you can use to describe the behaviors of the model. Value objects are doing a few things: they are giving you domain specific types (so that the type system can assist, as it it able, in restricting the frequency of certain kinds of errors), they are giving you domain specific semantics (rather than insisting that all domain behaviors are described via operations on domain agnostic primitives), and they are providing an isolation layer between the domain behavior and the in memory representations of domain state.
The value of this is not restricted to the "domain model"; you should feel free to apply this abstraction everywhere it makes sense to do so.
BUT... there is a particular trap in the case that you describe that you should be aware of.
The domain model is something that you are supposed to able to change aggressively to meet the needs of the business, which of course can include changing the implementation of the value objects.
Messages, however, should be changed conservatively. Messages are part of the API. If we want to be able to release compatible clients and servers using a different cadence for each, then we need the interface between them to be stable. The message shouldn't be carrying domain rules with it (those belong in the model), it's just a representation of state.
"Validation" usually happens when we take the message (part of the api) and translate it into values understood by the model.
This question is related, but more specific than this question.
I'm going to use a simple example here. Say we have a User entity in one context and a Customer entity in another context. These are 2 different representations of the same entity.
Let's say the User and Customer both have an email address, but the email address is always changed via the bounded context that the User belongs to. So the user context is the source of truth for the email address. So ideally I would like the email address in the Customer context to be immutable from the point of view of the customer context.
So when the email address is changed in the user context, an EmailAddressChanged event is emitted. This is fine; I subscribe to the event in the Customer context. However, I now need to handle this event by mutating the Customer email address. So I need some sort of command method to make this change.
How can I ensure that the command method is not used, other than when handling the event from the User context?
If I allow mutation in both contexts then they both become sources of truth and I need double the number of events and handlers to ensure that the information remains consistent in both contexts
Maybe there is a hidden customer/supplier relationship between these bounded contexts? If User bc is the source of truth for Customer bc, then User bc might expose an API to be accessed by downstream contexts (Customer, maybe something more?). In your question you said only the email address should be "immutable" and dependent on User context - however, I think it might a hint that entire Customer context is a consumer/customer of User context and should use its public API (which should not expose internal user domain model directly - some facade classes are required to hide the details).
If that's not the case, and there is no such relationship between the contexts - you can use a specialized component in your Customer bc to make changes to the database, without directly invoking domain methods. Then, the repository can be used to query customers and recreate them with updated email address. My point is - if you want customer bc to apply EmailAddressChanged events, you obviously need something to alter the database, but you don't need to do that via domain methods. The component applying EmailAddressChanged events would be part of the infrastructure layer of Customer context. If you use this solution, then there is no risk of modifying customers via business case scenarios.
Btw, isn't your Customer in fact a specialized read model of User context?
In Domain Driven Design, there is an emphasis of placing behaviors where they correctly belong. I'm not always sure what exactly constitutes "correct," though.
Consider this scenario: "The client withdraws an amount of money from a bank account."
Grammatically, we have that:
'client' is a subject
'withdraw' is a verb
'amount' is a direct object
'account' is an affected prepositional object
Classically, the client would execute this: account.withdraw(amount).
This could be read as: "The client commands a bank account to withdraw an amount of money." However, this does not grammatically correspond to the original scenario, since 'bank account' is now the direct object and an infinitive removes 'withdraw' and 'amount' from the main clause so that the primary idea conveyed is that 'client commands account'.
To adhere to DDD, we should regard this code as precisely describing the original scenario. This implies that the 'withdraw' method does not model a behavior performed by the account (the account is not a subject), but rather it models a behavior that indirectly affects it (the account is a prepositional object) and could very well be renamed 'wasWithdrawnFrom'. Moreover, the method argument represents something being affected by the client as opposed to by the object (it is a direct object for a client subject, not an object subject).
If we extrapolate from this example, we can see that methods may represent behaviors that affect the object (object is not the subject) and method arguments may represent direct objects of a client subject.
However, whether or not methods should represent behaviors performed by objects is unclear.
So my question is: How should we use methods to model object behavior?
1) Methods should strictly represent behaviors that affect the object. (The object cannot act as a subject, only a grammatical direct/indirect/prepositional object)
2) Methods may represent both behaviors that affect the object as well as behaviors performed by the object. (The object may act as a subject or a grammatical direct/indirect object)
You seems to be stuck in a theoretical thesis. I'm not sure you can apply a theory that works for every scenario/project. Behaviors usually appears when you start bombarding your Model with Use Cases. I try to let the cases dictate behaviors.
To follow your example:
Actor Customer want to withdraw money from Account. The way to do it is like you do Account.Withdraw(Money amount)
But your question "How should we use methods to model object behavior?" is a common DDD question. How to enrich your model with behavior? My best hints is to find your Value Objects. Value objects usually comes with behavior.
In example Account is and Entity (Aggregate root probably). Money (Value object with Currency and Amount) should be withdrawn from an Account. That should be Account Single Responsible (Principle) to control that Account balance and all access to it.
Regarding your (2) question in the end. Methods are absolutely used for change the objects inner state. But when it comes to behaviors performed by the entity/value object like
Customer.Order(newOrder) or advert.Apply(candidateCV) we can make entities communicate with each other. We can also create chained behaviors through Domain Events which can help us not to leak to much business logic to our application services. See Udi Dahan's blog for that or my blog article regarding Anemic Domain model http://magnusbackeus.wordpress.com/2011/05/31/preventing-anemic-domain-model-where-is-my-model-behaviour/
I Hope you got some ideas. It's difficult to give concrete hints when we are so abstract here.
/Best regards Magnus
I find that scenario too simple to be real, hence too simplistic to model too. I would reformulate the
"The client withdraws an amount of money from a bank account."
to something like
"The client submits withdrawal request of value xxx $ from his account" (when I go to my bank I have to fill out a form in order to withdraw money where I state amount, the account number, date and my signature)
There one can spot a request (command) to a service (withdrawal service) of an client (client identified by ID) from his account (account identified by ID) and the money value (money as value object).
I don't care much about the grammar, as English is my second language so when trying to understand the Domain, I try to understand how the business sees the concepts (Account) and workflows (withdraw an amount) and not to do grammar analysis.
The point of DDD is to model things like they are in the business, so behaviour shows up according to Domain understanding.
in this scenario, for me it's clear that we're working within the Account Operations Bounded Context and at least the Account aggregate root is involved. Of course, in banking terms, probably (I'm guessing here) there will not be a withdrawl but an operation to increase the Debit/Credit part of an account, so most likely the account will register that a debit/credit operation has happened. And a Domain Event is born and published. Then let the domain expert tell you what will happen next.
"The client deletes an order" => order.delete
Probably the order is never deleted, but its status will changed to 'canceled' or similar. However for that case when an order really should be deleted, the order doesn't delete itself, the Orders repository deletes that order.
Let's assume I have two service classes with the following methods:
GroupService
createGroup()
deleteGroup()
updateGroup()
findGroup()
UserService
createUser()
deleteUser()
updateUser()
findUser()
Now, I am thinking about the aesthetics of theses classes.
Imagine we want to implement a method which search for all user of a specific group.
Which service class is responsible for such a method?
I mean, the return value is a user (or maybe a collection of users) but the parameter (which means the name of the group) is a group.
So which service class is the better place to put this method in?
None of both. The method belongs in the class Group, which is returned by createGroup() and findGroup(). If only these two services are your options, though, go with the GroupService, because all arguments of GroupService get group names as arguments. It is more usual to vary the return type of methods than the argument.
I'd suggest the User Service, since you are requesting User entities. A service should shield consumers from implementation details (persistence mechanism etc), if the users were returned from the Group Service, it would require knowledge of how users are persisted.
I would create another class called "Membership" and have the methods that search for users in groups or groups a particular user belongs to. I tend to err on the side of large number of small classes rather than small number of large classes.
Depends on the way of your thinking, If you want to search on users with specific group, So in fact you want do some search on users with specific criteria, so It's better to put it in user service, but if you want to get some property from group, it's better to put it in group service, You should show what's your class signature and their responsibility.
I am new to programming (6 weeks now). i am reading a lot of books, sites and blogs right now and i learn something new every day.
Right now i am using coldfusion (job). I have read many of the oop and cf related articles on the web and i am planning to get into mxunit next and after that to look at some frameworks.
One thing bothers me and i am not able to find a satisfactory answer. Beans are sometimes described as DataTransferObjects, they hold Data from one or many sources.
What is the recommended practice to handle this data?
Should i use a separate Object that reads the data, mutates it and than writes it back to the bean, so that the bean is just a storage for data (accessible through getters) or should i implement the methods to manipulate the data in the bean.
I see two options.
1. The bean is only storage, other objects have to do something with its data.
2. The bean is storage and logic, other objects tell it to do something with its data.
The second option seems to me to adhere more to encapsulation while the first seems to be the way that beans are used.
I am sure both options fit someones need and are recommended in a specific context but what is recommended in general, especially when someone does not know enough about the greater application picture and is a beginner?
Example:
I have created a bean that holds an Item from a database with the item id, a name, and an 1d-array. Every array element is a struct that holds a user with its id, its name and its amount of the item. Through a getter i output the data in a table in which i can also change the amount for each user or check a user for deletion from this item.
Where do i put the logic to handle the application users input?
Do i tell the bean to change its array according to the user input?
Or do i create an object that changes the array and writes that new array into the bean?
(All database access (CreateReadUpdateDelete) is handled through a DataAccessObject that gets the bean as an argument. The DAO also contains a gateway method to read more than one record from the database. I use this method to get a table of items, which i can click to create the bean and its data.)
You're observing something known as "anemic domain model". Yes, it's very common, and no, it's not good OO design. Generally, logic should be with the data it operates on.
However, there's also the matter of separation of concerns - you don't want to stuff everything into the domain model. For example, database access is often considered a technically separate layer and not something the domain models themselves should be doing - it seems you already have that separated. What exactly should and should not be part of the domain model depends on the concrete case - good design can't really be expressed in absolute rules.
Another concern is models that get transferred over the network, e.g. between an app server and a web frontend. You want these to contain only the data itself to reduce badnwidth usage and latency. But that doesn't mean they can't contain logic, since methods are not part of the serialized objects. Derived fields and caches are - but they can usually be marked as transient in some way so that they are not transferred.
Your bean should contain both your data and logic.
Data Transfer Objects are used to transfer objects over the network, such as from ColdFusion to a Flex application in the browser. DTOs only contain relevant fields of an object's data.
Where possible you should try to minimise exposing the internal implementation of your bean, (such as the array of user structs) to other objects. To change the array you should just call mutator functions directly on your bean, such as yourBean.addUser(user) which appends the user struct to the internal array.
No need to create a separate DAO with a composed Gateway object for your data access. Just put all of your database access methods (CRUD plus table queries) into a single Gateway object.