Not quite sure how to approach this problem regarding DDD.
Say you have 2 domains:
A Product domain which is responsible for creating new and managing existing Products which a person has created. Product Aggregate Root
A Store domain which is responsible for assigning all created Products to a given Store to be sold, and other stuff. But the Store can also create new Products which will be assigned to themselves but also available for other Stores so that they can assign the Product to themselves. Store Aggregate Root
A Product can exist without belonging to a Store. A Store can exist without having any Products in it whatsoever (doesn't make sense I know, but this is just a simple example of a complex solution I'm working on atm.)
So when a Person comes along into the system, they can start at either end. They can start by creating new Products or they can start by adding a new Store.
Here is where it gets complicated, when they create a new Store, they are given the option to add existing Products or they can create a new Product and add it to the Store.
How do you deal with this use case. is the does the Store have a behavior to CreateNewProduct where it's responsible to setting up the new Product and then adding it to the Store. Or do you simply create a new Product outside the Store Domain as part of the Product domain, and tell the Store to AddProduct / AddExistingProduct?
UPDATE: Would something like this be appropriate as a Domain Service
public class StoreProductService {
public Store CreateNewStoreProduct (Store store, string sku, string name, etc){
Product newProduct = ProductFactory.CreateNewProduct(sku, name, etc);
store.AddProduct(newProduct);
return store;
}
}
You need the two domains to communicate with each other. You can communicate using various methods but one common way is to use a REST API. In your Store domain, you need something that communicates or knows how to communicate with the API. I have generally implemented these as a service that wraps api calls. The service will be able to understand your domain Ubiquitous language and will translate that into API commands. You can use domain events to possibly listen for when the product has been created and then you can associate the store with the product or you can implement some kind of polling mechanism.
An example was requested, so here goes:
Call from UI (probably from a controller)
StoreService.CreateStore(storeName: String, newProduct : StoreProduct)
You could pass in primitives to represent the newproduct. This allows you to create a new product without the need for a new class for it. You subsequently don't need a shared infrastructure class or converter between your domain and UI layers.
StoreService
public StoreService
{
public StoreService(ProductApiClient productApiClient...)...
public void CreateStore(string StoreName, StoreProduct prod...)
{
var newStore = StoreFactory.Create(storeName);
//below might be better as an asynch call but for simplicity
//keeping it all synchronous
var newProd = productApiClient.CreateProduct(prod);
//check if product was created successfully, if so
newStore.Add(newProd);
//save
StoreRepo.Create(newStore);
//check if store was created successfully
}
The main points to take from here:
Create your aggregate entity using a factory (at this state it has not being persisted).
You need a repo to serialize and persist your new store to your data store.
productApiClient will translate between your domain model and a request to the productApi. It knows how to generate an Api request (if REST for example) given domain entities.
ProductApiClient will return a domain entity from the Api Response.
You add a new product to a store using the store entity.
You persist your store using the repo
You may choose to pick a more asynchronous approach if the call to the api is time consuming.
This example illustrates the power of DDD and the separation of concerns. Depending on the size of your project and your requirements, this might be overly tedious so fit it to your needs, skills and requirements.
This business problem is very common. You surely can find some of examples about eCommerce systems with DDD.
Typical situation is that you have not finished developing your UL. If you discuss the Store (I won't mark it as code since I am talking about UL terms, not classes) with your domain experts, you can find out that Store only cares about Product Availability, not the Product itself.
Typically, your Product that belongs to a Product Catalogue, has little to do with the availability. It might have general description, manufacturer details, country of origin, picture, package size and weight and so on.
Product Availability, however, has, well, the availability, i.e. count of available product items. It might have some extra details, for example a count of reserved items, expected to arrive items and so on.
The fact is that often both of these concepts, despite they are rather different, are referred by domain experts as "Product". This is a typical example of two separate Bounded Contexts.
As soon as you have two different things that are called Product in two different Bounded Contexts (and physical places), you will need to keep them in sync. This is usually done by publishing domain events outside of the Bounded Contexts and updating the other side by subscribing to these events there and doing internal domain command handling inside the Bounded Context.
Related
In DDD, you're strongly encouraged to have all business logic within the domain entities instead of separate from it. Which makes sense.
You also have the idea of Domain Services to encapsulate certain pieces of logic.
What I can't work out is how to have the domain entities perform their business logic that itself depends on external services.
Take, for example, a user management system. In this there is a User domain entity, on which there are various business actions to perform. One of these is verify_email_address - which sends an email to the users email address in order to verify that it's valid.
Except that sending an email involves interactions with external services. So it seems reasonable for this logic to be encapsulated within a Domain Service that the User entity then makes use of. But how does it actually do this?
I've seen some things suggest that the User entity is constructed with references to every domain service that it needs. Which makes it quite big and bloated, and especially hard to test.
I've seen some things that suggest that you should pass in the domain service to the method that you are calling - which just feels weird. Why would someone outside of the domain entity need to pass in the EmailClient service when calling verify_email_address?
I've also then seen the suggestion that you instead pass the User entity in to the domain service, except that this seems to imply that the logic is in the domain service and not the entity.
And finally, I've seen suggestions that the entity should raise a domain event to trigger the email, which the domain service then reacts to. That means that all of the logic for whether to send the email or not - no need if it's already verified - and which email address to send it to are in the right place, and it also means that the user only needs a way to raise events and nothing more. So it feels less tightly coupled. But it also means you need a whole eventing mechanism, which is itself quite complicated.
So, am I missing something here? How can I achieve this?
(I'm working in Rust if that matters, but I don't see that it should)
What I can't work out is the best way to have the domain entities perform their business logic that itself depends on external services.
That's not your fault; the literature is a mess.
In DDD, you're strongly encouraged to have all business logic within the domain entities instead of separate from it.
That's not quite right; the common idea is that all business logic belongs within the domain layer (somewhere). But that doesn't necessarily mean that the logic must be within a domain entity.
Evans, in Chapter 5, writes:
In some cases, the clearest and most pragmatic design includes operations that do not belong to any object. Rather than force the issue, we can follow the natural contours of the problems space and include SERVICES explicitly in the model.
There are important domain operations that can't find a natural home in an ENTITY or VALUE OBJECT....
It's a very Kingdom of Nouns idea; we have code that actually does something useful, so there must be an object it can belong to.
Having a module (in the Parnas sense) in the domain layer that is responsible for the coordination of an email client and a domain entity (or for that matter, a repository) to achieve some goal is a perfectly reasonable option.
Could that module be the domain entity itself? It certainly could.
You might find, however, that coupling the management of the in-memory representation of domain information and the orchestration of a domain process that interacts with "the real world", as it were, complicates your maintenance responsibilities by introducing a heavy coupling between two distinct concepts that should instead be lightly coupled.
Clean Architecture (and the predecessors in that lineage) suggests to separate "entities" from "use cases". Ivar Jacobson's Objectory Process distinguished "entities" from "controls". So the notion of a service that is decoupled from the entity shouldn't be too alien.
Ruth Malan writes:
Design is what we do when we want to get more of what we want than we'd get by just doing it.
Finding the right design depends a lot on finding the right "what we want" for our local context (including our best guess at how this local context is going to evolve over the time window we care about).
VoiceOfUnReason has a perfectly valid answer.
I just want to boil down your question to the grits.
What I can't work out is how to have the domain entities perform their business logic that itself depends on external services.
I've also then seen the suggestion that you instead pass the User entity in to the domain service, except that this seems to imply that the logic is in the domain service and not the entity.
That's the key. All logic that belongs to domain entities should be done on domain entities. But at the same time, domain entities MUST be independent of the outside world (even other domain entities).
That's why we have domain services and application services.
Domain services are used to coordinate things between multiple entities, like transferring money between two accounts:
public class TransferService
{
IAccountRepos _repos;
public void Transfer(string fromAccountNumber, string toAccountNumber, decimal amount)
{
var account1 = _repos.Get(fromAccountNumber);
var account2 = _repos.Get(fromAccountNumber);
var money = account1.Withdraw(amount);
account2.Deposit(money);
_repos.Update(account1);
_repos.Update(account2);
}
}
That's a domain service since it's still only using the domain only.
Application services on the other hand are used to communicate over boundaries and with external services.
And it's an external service that you should create in this case. It looks similar to domain services but are at a layer over it (it can use domain services to solve its purpose).
To summarize:
Entities must be used to perform actions on themself (the easiest way is to make all setters private which forces you to add methods).
Domains services should be used as soon as two or more entities must be used to solve a problem (can even be two entities of the same type as in the example above)
Application services are used to interact with things outside the domain and can use entities and/or domain services to solve the problem.
Suppose I have a domain service which implements the following business rule / policy:
If the total price of all products in category 'family' exceeds 1 million, reduce the price by 50% of the family products which are older than one year.
Using collection-based repositories
I can simply create a domain service which loads all products in the 'family' category using the specification pattern, then check the condition, and if true, reduce the prices. Since the products are automatically tracked by the collection-based repository, the domain service is not required to issue any explicit infrastructure calls at all – as should be.
Using persistence-based repositories
I'm out of luck. I might get away with using the repository and the specification to load the products inside my domain service (as before), but eventually, I need to issue Save calls which don't belong into the domain layer.
I could load the products in the application layer, then pass them to the domain service, and finally save them again in the application layer, like so:
// Somewhere in the application layer:
public void ApplyProductPriceReductionPolicy()
{
// make sure everything is in one transaction
using (var uow = this.unitOfWorkProvider.Provide())
{
// fetching
var spec = new FamilyProductsSpecification();
var familyProducts = this.productRepository.findBySpecification(spec);
// business logic (domain service call)
this.familyPriceReductionPolicy.Apply(familyProducts);
// persisting
foreach (var familyProduct in familyProducts)
{
this.productRepository.Save(familyProduct);
}
uow.Complete();
}
}
However, I see the following issues with this code:
Loading the correct products is now part of the application layer, so in case I need to apply the same policy again in some other use case, I need to repeat myself.
The cohesion between the specification (FamilyProductsSpecification) and the policy is lost, essentially allowing someone to pass the wrong products into the domain service. Note that filtering the products (in-memory) again in the domain service does not help either, as the caller might have passed only a subset of all products.
The application layer has no clue which products have changed, and therefore is forced to save all of them, which might be a lot of redundant work.
Question: Is there a better strategy to deal with this situation?
I thought about something complicated like adapting the persistence-based repository such that it appears as a collection-based one to the domain service, internally keeping track of the products which were loaded by the domain service in order to save them again when the domain service returns.
First of all, I think choosing a domain service for this kind of logic - which does not belong inside one specific aggregate - is a good idea.
And I also agree with you that the domain service should not be concerned with saving changed aggregates, keeping stuff like this out of domain services also allows you to be concerned with managing transactions - if required - by the application.
I would be pragmatic about this problem and make a small change to your implementation to keep it simple:
// Somewhere in the application layer:
public void ApplyProductFamilyDiscount()
{
// make sure everything is in one transaction
using (var uow = this.unitOfWorkProvider.Provide())
{
var familyProducts = this.productService.ApplyFamilyDiscount();
// persisting
foreach (var familyProduct in familyProducts)
{
this.productRepository.Save(familyProduct);
}
uow.Complete();
}
}
The implementation in the product domain service:
// some method of the product domain service
public IEnumerable<Product> ApplyFamilyDiscount()
{
var spec = new FamilyProductsSpecification();
var familyProducts = this.productRepository.findBySpecification(spec);
this.familyPriceReductionPolicy.Apply(familyProducts);
return familyProducts;
}
With that the whole business logic of going through all family products older than a year and then applying the current discount (50 percent) is encapsulated inside the domain service. The application layer then is again only responsible for orchestrating that the right logic is being called in the right order. The naming and how generic you want to make the domain service methods by providing parameters might of course need tuning, but I usually try to make nothing too generic if there is only one specific business requirement anyway. So if that's the current family product discount I would than already know where exactly I need to change the implementation - in the domain service method only.
To be honest, if the application method is not getting more complex and you don't have different branches (such as if conditions) I would usually start off like you originally proposed as the application layer method also simply makes calls to domain services (in your case the repository) with the corresponding parameters and has no conditional logic in it. If it get's more complicated I would refactor it out into a domain service method, e.g. the way I proposed.
Note: As I don't know the Implementation of FamilyPriceRedcutionPolicy I can only assume that it will call the corresponding method on the product aggregates to let them apply the discount on the price. E.g. by having a method such as ApplyFamilyDiscount() on the Product aggregate. With that in mind, considering that looping through all the products and calling the discount method will be only logic outside the aggregate, having the steps of getting all products from the repository, calling the ApplyFamilyDiscount() method on all products and saving all changed products could indeed just reside in the application layer.
In terms of considering domain model purity vs. domain model completeness (see discussion below concerning the DDD trilemma) this would move the Implementation again a little more in the direction of purity but also makes a domain service questionable if looping through the products and calling the ApplyFamilyDiscount() is all it does (considering the fetching of the corresponding products via the repository is done beforehand in the application layer and the product list is already passed to the domain service). So again, there is no dogmatic approach and it is rather important knowing the different options and their trade-offs. For instance, one could also consider to let the product always calculate the current price on demand by applying all applicable possible discounts when asking for the price. But again, if such a solution would be feasible depends on the specific requirements.
Which is suggested way to implement _customRoleRepository in the following examples?
Following code is executed in the application service.
var user = _userRepository.GetById(1);
var customRole = _customRoleRepository.GetById(user.CustomRoleId);
or
var user = _userRepository.GetById(1);
var customRole = _customRoleRepository.GetForUser(user);
Given the two options I would probably go for the first one, which keeps consistency of accessing by an ID.
If possible, it might be preferable to load the custom role when you load the user to avoid another round trip to the database, especially if this is a common operation. This could be implemented as a read model.
This is presuming you have modelled your aggregates correctly... :)
Hate to say it but in a DDD environment, my answer would be neither.
In your first example, the role repository can be ignorant of the user domain which is good but it means the application needs to know that to get the role it needs to pull an id out of the user and then query another repository. In other words, the application is acting as a mapper between user and role.
In the second example, the roles repository now needs to know about the user domain. Not great but on the other hand the application no longer needs to know about roleId. So that is good. Classic sort of trade off between the two approaches.
But in both cases the application still needs two repositories to get it's information. What happens when more relations are needed? The number of repositories can quickly grow and things become a mess.
In Domain Driven Design you should try to think in terms of aggregate roots(AR) and domain contexts. For your example context, the user is an AR and the role becomes a child. So you might have:
var user = _userFinder.GetById(1);
var customRole = user.CustomRole;
That hides most of the implementation details from you application and allows you to focus on what your domain entities actually need to do.
Both are equally valid, depending on your needs. GetForUser would be good if you want to ensure the calling code has a valid User aggregate before you try and retrieve the roles - while it does couple the customRoleRepository to knowledge of the User aggregate, if you want to require the calling code to have a valid User aggregate, then that coupling has a purpose.
GetByUserId is more consistent with GetById and has less coupling, so if in your context it doesn't matter to call GetByUserId even if the client doesn't have a valid User aggregate, then that's fine too.
If you are loading ById, I've also found using typed identity valueobjects can be quite helpful in providing an extra level of type safety - some conversation about the pros and cons here https://stackoverflow.com/a/5377460/6720449 and here https://groups.google.com/forum/#!topic/dddcqrs/WQ9zRtW3Gbg
Our application sends/receives a lot of data to/from a third party we work with.
Our domain model is mainly populated with that data.
The 'problem' we're having is identifying a 'good' candidate as domain identity for the aggregate.
It seems like we have 3 options:
Generate a domain identity (UUID or DB-sequence...);
Use the External-ID as domain identity that comes along with all data from the external source.
Use an internal domain identity AND External-ID as a separate id that 'might' be used for retrieval operations; the internal id is always leading
About the External-ID:
It is 100% guaranteed the ID will never change
The ID is always managed by the external source
Other domains in our system might use the external-id for retrieval operations
Especially the last point above convinced us that the external-id is not an infrastructural concern but really belongs to the domain.
Which option should we choose?
** UPDATE **
Maybe I was not clear about the term '3th party'.
Actually, the external source is our client who is active in the Car industry. Our application uses client's master data to complete several 'things'. We have several Bounded Contexts (BC) like 'Client management', 'Survey', 'Appointment',
'Maintenance' etc.
Our client sends us 'Tasks' that describe something needs te be done.
That 'something' might be:
'let client X complete survey Y'
'schedule/cancel appointment for client X'
'car X for client Y is scheduled for maintenance at position XYZ'
Those 'Tasks' always have a 'task-id' that is guaranteed to be unique.
We store all incoming 'Tasks' in our database (active record style). Every possible action on a task maps with a domain event. (Multiple BCs might be interested in the same task)
Every BC contains one or more aggregates which distribute some domain events to other BCs. For instance, when an appointment is canceled a domain event is triggered, maintenance listens to that event to get some things done.
However, our client expects some message after every action that is related to a Task. Therefore we always need to use the 'task-id'.
To summarize things:
Tasks have a task-id
Tasks might be related to multiple BCs
Every BC sends some 'result message' to the client with the related task-id
Task-ids are distributed by domain events
We keep every (internally) persisted task up-to-date
Hopefully, I was clear enough about the use of the external-id (= task-id) and our different BCs.
My gut feeling would be to manage your own identity and not rely on a third party service for this, so option 3 above. Difficult to say without context though. What is the 3rd party system? What is your domain?
Would you ever switch the 3rd party service?
You say other parts of your domain might use the external id for querying - what are they querying? Your internal systems or the 3rd party service?
[Update]
Based on the new information it sounds like a correlationId. I'd store it alongside the other information relevant to the aggregates.
As a general rule, I would veto using a DB-sequence number as a identifier; the domain model should be independent of the choice of persistence; the domain model writes the identifier to the database, rather than the other way around (if the DB wants to be tracking a sequence number for its own purposes, that's fine).
I'm reluctant to use the external identifier, although it can make sense in some circumstances. A given entity, like "Customer" might have representations in a number of different bounded contexts - it might make sense to use the same identifier for all of them.
My default: I would reach for a name based uuid, using the external ID as part of the seed, which gives a simple mapping from external to internal.
Despite having studied Domain Driven Design for a long time now there are still some basics that I simply figure out.
It seems that every time I try to design a rich domain layer, I still need a lot of Domain Services or a thick Application Layer, and I end up with a bunch of near-anemic domain entities with no real logic in them, apart from "GetTotalAmount" and the like. The key issue is that entities aren't aware of external stuff, and it's bad practice to inject anything into entities.
Let me give some examples:
1. A user signs up for a service. The user is persisted in the database, a file is generated and saved (needed for the user account), and a confirmation email is sent.
The example with the confirmation email has been discussed heavily in other threads, but with no real conclusion. Some suggest putting the logic in an application service that gets an EmailService and FileService injected from the infrastructure layer. But then I would have business logic outside of the domain, right? Others suggest creating a domain service that gets the infrastructure services injected - but in that case I would need to have the interfaces of the infrastructure services inside the domain layer (IEmailService and IFileService) which doesn't look too good either (because the domain layer cannot reference the infrastructure layer). And others suggest implementing Udi Dahan's Domain Events and then having the EmailService and FileService subscribe to those events. But that seems like a very loose implementation - and what happens if the services fail? Please let me know what you think is the right solution here.
2. A song is purchased from a digital music store. The shopping cart is emptied. The purchase is persisted. The payment service is called. An email confirmation is sent.
Ok, this might be related to the first example. The question here is, who is responsible for orchestrating this transaction? Of course I could put everything in the MVC controller with injected services. But if I want real DDD all business logic should be in the domain. But which entity should have the "Purchase" method? Song.Purchase()? Order.Purchase()? OrderProcessor.Purchase() (domain service)? ShoppingCartService.Purchase() (application service?)
This is a case where I think it's very hard to use real business logic inside the domain entities. If it's not good practice to inject anything into the entities, how can they ever do other stuff than checking its own (and its aggregate's) state?
I hope these examples are clear enough to show the issues I'm dealing with.
Dimitry's answer points out some good things to look for. Often/easily you find yourself in your scenario, with a data shoveling from db up to GUI through different layers.
I have been inspired by Jimmy Nilsson's simple advice "Value objects, Value objects and more Value objects". Often people tend to focus to much on Nouns and model them as entity. Naturally you often having trouble in finding DDD behavior. Verbs are easier to associate with behavior. A good thing is to make these Verbs appear in your domain as Value objects.
Some guidance I use for my self when trying to develop the domain (must say that it takes time to construct a rich domain, often several refactoring iterations...) :
Minimize properties (get/set)
Use value objects as much as you can
Expose as little you can. Make you domain aggregates methods intuitive.
Don't forget that your Domain can be rich by doing Validation. It's only your domain that knows how to conduct a purchase, and what's required.
Your domain should also be responsible for validation when your entities make a transition from one state two another state (work flow validations).
I'll give you some examples:
Here is a article I wrote on my blog regarding your issue about anemic Domain http://magnusbackeus.wordpress.com/2011/05/31/preventing-anemic-domain-model-where-is-my-model-behaviour/
I can also really recommend Jimmy Bogard's blog article about entity validations and using Validator pattern together with extension methods. It gives you the freedom to validate infrastructural things without making your domain dirty:
http://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/
I use Udi's Domain Events with great success. You can also make them asynchronous if you believe your service can fail. You also wrap it in a transaction (using NServiceBus framework).
In your first example (just brainstorming now to get our minds thinking more of value objects).
Your MusicService.AddSubscriber(User newUser) application service get a call from a presenter/controller/WCF with a new User.
The service already got IUserRepository and IMusicServiceRepository injected into ctor.
The music service "Spotify" is loaded through IMusicServiceRepository
entity musicService.SignUp(MusicServiceSubscriber newSubsriber) method takes a Value object MusicServiceSubscriber.
This Value object must take User and other mandatory objects in ctor
(value objects are immutable). Here you can also place logic/behavior like handle subscriptionId's etc.
What SignUp method also does, it fires a Domain Event NewSubscriberAddedToMusicService.
It get caught by EventHandler HandleNewSubscriberAddedToMusicServiceEvent which got IFileService and IEmailService injected into it's ctor. This handler's implementation is located in Application Service layer BUT the event is controlled by Domain and MusicService.SignUp. This means the Domain is in control. Eventhandler creates file and sends email.
You can persist the user through eventhandler OR make the MusicService.AddSubscriber(...) method to this. Both will do this through IUserRepository but It's a matter of taste and perhaps how it will reflect the actual domain.
Finally... I hope you grasp something of the above... anyhow. Most important is to start adding "Verbs" methods to entitys and making the collaborate. You can also have object in your domain that are not persisted, they are only there for mediate between several domain entities and can host algorithms etc.
A user signs up for a service. The user is persisted in the
database, a file is generated and saved (needed for the user account),
and a confirmation email is sent.
You can apply Dependency Inversion Principle here. Define a domain interface like this:
void ICanSendConfirmationEmail(EmailAddress address, ...)
or
void ICanNotifyUserOfSuccessfulRegistration(EmailAddress address, ...)
Interface can be used by other domain classes. Implement this interface in infrastructure layer, using real SMTP classes. Inject this implementation on application startup. This way you stated business intent in domain code and your domain logic does not have direct reference to SMTP infrastructure. The key here is the name of the interface, it should be based on Ubiquitous Language.
A song is purchased from a digital music store. The shopping cart
is emptied. The purchase is persisted. The payment service is called.
An email confirmation is sent. Ok, this might be related to the first example. The question here is, who is responsible for orchestrating this transaction?
Use OOP best practices to assign responsibilities (GRASP and SOLID). Unit testing and refactoring will give you a design feedback. Orchestration itself can be part of thin Application Layer. From DDD Layered Architecture:
Application Layer: Defines the jobs the software is supposed to do and directs the
expressive domain objects to work out problems. The tasks this layer
is responsible for are meaningful to the business or necessary for
interaction with the application layers of other systems.
This layer is kept thin. It does not contain business rules or
knowledge, but only coordinates tasks and delegates work to
collaborations of domain objects in the next layer down. It does not
have state reflecting the business situation, but it can have state
that reflects the progress of a task for the user or the program.
Big part of you requests are related to object oriented design and responsibility assignment, you can think of GRASP Patterns and This, you can benefit from object oriented design books, recommend the following
Applying UML and Patterns