I have recently started exploring Domain driven design and have a question. Suppose I have a Product, Category, Manufacturer domain models in my application. And Product looks like this:
public class Product
{
int ProductId;
string Title;
string Description;
double Price;
int CategoryId;
Category Category;
Manufacturer Manufacturer;
}
Generally on a detail view where a product is displayed, Category Name and Manufacturer name is shown (rather than their Ids). But Category and Manufacturer are different Aggregates. Question is how to fetch Manufacturer and Category Name along with Product Domain Model. ProductRepository will only return Product domain Model (along with categoryId and ManufacturerId).
Either my Product Service raise another request to fetch the
CategoryId and ManufacturerId
Or I can fetch them while Product is fetch from Product repository.
But I don't need all the attributes, I just need their title. And I am facing similar issues with all the domain model.
Please help how should I solve this problem.
There are various ways you can handle this:
Local Caching / View Models
Keep an in-memory cache locally in your service that maps between CategoryId and CategoryTitle (same for Manufacturer) - this can either be through:
listening to an event (i.e. CategoryCreated). This would be preferred if you are have an event-driven system. You could also listen to other events (i.e. CategoryTitleUpdated) if relevant.
by making a web request to the external services. You would query your local cache first, and then decide if to call the external service. You'd need to think about how stale you allow your cache to become.
Denormalising the data
You could duplicate the data by saving the CategoryTitle alongside the CategoryId. This way you have no call to an external service. The tradeoff is you need to consider how often the CategoryTitle is likely to change, and how you handle that change.
Reporting "domain"
You could have a completely separate service that listens for data from other services and maintains view models for UIs. This would keep your other services ignorant of other service's concerns. When using an event-driven system, you'd be listening for events form other services that allow you to build a view model for the UI
Generally on a detail view where a product is displayed, Category Name and Manufacturer name is shown (rather than their Ids). ... Question is how to fetch Manufacturer and Category Name along with Product Domain Model. ProductRepository will only return Product domain Model (along with categoryId and ManufacturerId)
As I see, Category Name and Manufacturer Name are used for displaying so it is presentation concern. I'd suggest having a separate read model for Product which serves that screen only (see Command Query Responsibility Segregation (CQRS)):
public class ProductReadModel
{
int ProductId;
string Title;
string Description;
double Price;
string CategoryName;
string ManufacturerName;
}
There are different ways to fill/build that model:
If our aggregates are persisted in relational data base using ORM (e.g. NHibernate) then you can directly query your data base using raw SQL or a light-weight ORM (e.g. Dapper). You do not need repository for it, you need just QueryHandler
If our aggregates are event sourced, then you simply listen to Domain Events (e.g. CategoryNameChanged/ManufacturerNameChanged ) and then project (denormalise) them into ProductReadModel and store it in any storage (even in memory).
You can also fire and project/denormalise Domain Events if your aggregates are persisted in relational data base.
In addition to #tomliversidge's answer I recommend looking into the Composite UI pattern (you can find an example here).
There you would have a Service Gateway building a composite View Model consisting of information from the 3 services (Product, Manufacturer and Category).
Related
I have a microservice called reward. When a customer does a certain activity in a different microservice(spent a specific amount of money), that service publishes an event, lets say SpentRewardingMoney.
In reward service, my aggregate root is Customer.
public class Customer: Entity, IAggregateRoot
{
// some properties
public List<CustomerReward> UserRewards { get; private set; } // rewards already given
}
Now in SpentRewardingMoneyConsumer, I have to give reward to that customer.
Problem is, there is some configuration, for simplification suppose a table RewardRule(reward amount, is reward active etc) to disburse reward. According to DDD rule, I have to pull everything through aggregate root but this configuration is not part of aggregate root.
How should I pull this table from the database?.
The rewards can be loaded from a database or any other persistence that you use. It'll be loaded through a repository.
The question other part of your question is: Where should it live in your model?
It depends on your ubiquitous language (UL).
To my understanding, it sounds like "reward amount" and "is reward active" are all values of the Customer Reward object. (This is an educated guess based on my guess about your requirement and UL).
Rewards could also be it's own aggregate (also depends on UL). In which case communicating between aggregates in the same context is straight forward. You might use a service to simplify the interactions in such a case.
I need some clarification on modelling a user for Identity and access domain. The user domain model has a contact information entity (entity because it is mutable), the customer can register with a phone number, but can choose to change it when needed.
The phone number once used by a customer can never be used by any other user. So the model I believe must allow querying the phonenumber table(since it is many to one with the customer, as the old numbers are deactivated and archived).
If creating a domainservice is ok, what should be the Repository as there is no aggregate identified.
With these cases I have a customer(user) aggregate, but to allow querying all the users to see if the phone number provided by the customer is already been used by anyone else, what should be the aggregate, or can I write a DomainService that just can query the database directly to the phonenumber table to check for the uniqueness, am I violating any DDD principle doing so, what are the cleaner alternatives.
An alternative would be to create an Aggregate that makes it explicit in which scope you intend the unique constraint to hold.
As a (contrived) example, a phone number might be unique across a country but not internationally. Thus :
// An Aggregate Root
public class Country {
// Store a lookup structure (userId, phoneNumber) here
public void addUser(userId, phoneNumber) {
// check phone uniqueness here
}
public void changeUserPhone(userId, phoneNumber) {
// check phone uniqueness here
}
}
Since you're using CQRS, phone numbers being in a separate Aggregate doesn't matter because on the Query side, Read Models will reassemble the User and their phoneNumber together.
This also plays well with the "don't create Aggregate Roots" approach since you have a starting point from where to create your User (User is probably an AR) and not just create it out of thin air.
You could have your repository check if the phone number exists, if it does then throw a rule exception else save the change. The key here is to inject an instance of the repository through the application layer and run rule inside the domain layer.
I am struggling to find the best solution to the following. I need to determine whether a Country is "InUse", (e.g. currently referenced by an Address).
I have the following simplified model mapped in NHibernate:
class Address
{
public Country Country {get; set;}
}
class Country
{
public List<Address> Addresses {get; set;}
bool IsInUse()
{
return Addresses.Any();
}
}
Using the IsInUse method on Country is inefficient, as it would result in a load of all countries (the .Any() is executed in memory). In addition, Country doesn't really need to know about Addresses, it's purely there for the IsInUse method. So, I like the above example from a consumer point of view, it feels like the domain object should expose an IsInUse method, but it will not perform and contains unnecessary relationships.
Other options I can think of are;
Just use a repository and call that directly from service layer. The repository could encapsulate a call that simply issued a SELECT COUNT(*), rather than SELECT *, as would be the case with the lazy load option above. This options leave the IsInUse logic entirely outside of the domain layer.
Inject a repository into IsInUse(), which calls out to the same as above. I have read that this is VERY bad DDD practise.
Does anyone have any advice or better solutions to this problem.
Hope the above makes sense... Thanks.
I would suggest that you not calculate it each time you perform the query. Denormalize the IsInUse. Each time an address is added or removed from a country you can determine whether the country is in use and save that value.
How you go about determining that value is another story and there are various techniques ranging from immediately determining it when you save the address and updating the country's IsInUse value or even using messaging if these happen to be entities in different BCs.
It feels like you're making up domain concepts to solve your issue. Could you tell us why you need to know if a country is in use?
Repositories are great for capturing the language and aggregate persistence, not so much for querying. You're basically asking your data a question. Maybe move this logic altogether to the query side? Also see http://www.jefclaes.be/2014/01/repositories-where-did-we-go-wrong_26.html.
Maybe there is another way to keep track of all the countries in use. Where are those addresses coming from? Maybe you can introduce domain events - when an address is registered, add the country to the list of countries in use, so you can query a smaller list.
I'd design your domain entities without concepts from NHibernate or any other persistence mechanism. If this means that by using NHibernate you need to introduce 2-way mapping properties as standard, then I would only use your NHibernate entities within your repositories and design a separate set of entities for your domain model and map between the two. It's seems plausible to me, from your business's point of view, that a Country shouldn't know anything about Address.
Injecting the repository into your domain entity or using lazy loading typically go against DDD and cause issues when you serialize your entities or they lose database context.
Your IsInUse problem can be solved by either caching a query (not everything religiously has to be in a repository), maybe you could create a CountryStatistics class that handles this? Or you could keep a separate persisted country list, which gets updated every time a new address is created with a never-used-before country.
I'm building a new application and am new to Domain Driven Design. I've been reading through the documentation and I've managed to model most of the domain model but I would like some advice about two queries:
I have two domain objects channel and program. I've modelled these both as entities as both can be accessed independantly. A channel can have a list of programs so I have put this as an attribute of channel. My query is how should I populate the program list. Is it OK for the getChannerById method in ChannelService to first get the channel information and then call the ProgramService to get the list of programs for the channels e.g:
Channel {
String channelId
List <Program> programList
}
Program {
String programId {
}
ChannelService {
Channel getChannelById(String channelId)
}
ProgramService {
Program getProgramById(String programId)
List <Program> getProgramsByChannelById(String channelId)
}
I have a product domain object but some of its attributes (e.g. specification and compatability) involve quite time consuming operations. These attributes are not required all the time so is it OK to put these as part of the domain object and have seperate service methods that populate these attributes when required e.g.
Product {
String productId
Specification specification
List <Product> compatibleProducts
}
ProductService {
Product getProduct(String productId);
void getProductSpecifications(Product product);
void getCompatibleProducts(Product product);
}
Any advice would be very much appreciated.
When designing entities in DDD you shouldn't create associations from one entity to another such that the association is used for display or query purposes alone. While it is true that a channel has a set of programs, is the association between channel and the set of its programs required for the channel entity? More importantly, if you're only considering the query aspect then you may not need be forcing DDD upon your code. Instead, when designing entities consider the behavior that these entities need to implement. If your entities have no behavior but are only used as data containers then you don't need DDD. To answer your question, I would use read model classes that satisfy requirements of each query. For example, for your product model, if one query requires the specification attribute and another doesn't, create distinct read-model classes for those queries. These classes are not entities, they are simple read-only value objects, they don't have any behavior and their job is to represent data. In regards to implementing the query you have several options. Calling both the ChannelService and the ProgramService is one option. However, if the data is all stored together in a single database, why not just create a repository that returns all required data with one call? Take a look at my post on read-models in DDD for more on this topic.
I need to clarify something.
Have Person Aggreagate , 2 VOs (Country, StateProvince).
I want to load all country in my presentation layer (i am using mvc)
Evan says you only use repository (IPersonRepository) to work with root entity (it should always return just a reference to the Aggregate Root)
public interface IPersonRepository()
{
void savePerson(Person p);
void removePerson(Person p);
Ilist<Person> getPerson();
}
what i usually do to solve this :
Add in IPersonRepository this method
IList<Country> LookupCountrysOfPerson();
In Infra layer implement the Domain interfaces like this:
public IList<Person> LookupCountrysOfPerson()
{
return Session.CreateQuery("from Countrys").List<Person>());
}
My partner says im wrong.
Sometimes you have to sacrifice your domain model in order to accomplish some task
What is the best way to do this?
with code please! :)
I would say it's unlikely that you need country to be an entity. I suspect that country is nothing more than reference data, much like a person's title would be. Is there any behavior associated to country in your domain? I suspect it's just what's printed onto letters/envelops.
This question is somewhat similar to this one which I answered a while back:
Simple aggregate root and repository question
My suggestion is that you implement a Lookup service that your client can make use of and which is cached. Ignore the rules of DDD and anything to do with aggregates or repositories for this. As someone else has mentioned, this is where CQRS's ideology comes into play; the client shouldn't have to go through the domain in order to get data. The domain is purely transactional, not designed for queries.
This article explains how to build a generic lookup service for reference data for things that typically fill dropdowns in the UI (i.e. Title, Country etc)
http://wtfperminute.blogspot.com/2011/02/working-with-reference-data-lookups.html
Evans also says (pg 170) "An entity as basic as Location may be used by many objects for many reasons..."
I would also consider making Country an entity for the reasons given above. Perhaps more importantly, it is a low level object. You probably are also even supplying Country by configuration rather than through any actual domain activities. Therefore I would remove it from the Person and make it a standalone entity.
Also for this type of object you may not really need a dedicated repository, consider creating a single lookup service that provides query access for a group of similar objects of this nature.
If in your domain country is actually a VO (you don't want to maintain a thread of identity in the country name was changed etc.) which is the most common scenario, I would add a specialized class in the data access layer to return a list of all countries as VOs. I would also add caching (2nd level cache in NHibernate) to the country entity and list all countries query so that I don't have to hit the DB each time.
Actually, this is where CQRS really shines. CQRS acknowledges that you don't have to go through the domain layer in order to get some data for presentation purposes. In CQRS you just grab some data.
It sounds like countries are not in fact value objects here; they have distinct identities and are important for business purposes outside of your Person objects. They should become entities, and be treated in the fashion appropriate to them.
Think of it this way: let's say some volatile country had their current dictator overthrown and got a name change. The Person object's reference to a Country should still be valid, because the Country is not defined by its attributes (i.e. the string denoting its name), but by its identity.