As per the title, I have the following classes:
public class Company : AggregateRoot {
public AddressBook AddressBook { get; set; }
}
public class AddressBook {
public List<Address> Addresses { get; set; }
public Address GetPrimaryAddress() {
return Addresses.FirstOrDefault();
}
}
Is it acceptable for me to call:
company.AddressBook.GetPrimaryAddress();
Or should I expose a GetPrimaryAddress() method on Company that in turn calls the AddressBook method?
I know I shouldn't have references to entities within an AggregateRoot but I wasn't sure what the rulings are on calling operations.
Update
For what it's worth, below is a diagram (click here for full size) of my actual model. ContactList contains rules for how all types of contact (Person/Business Location) should be managed, such as what happens when a primary contact is removed. It also works around some caveats of how RavenDB stores nested entities (essentially we need to provide our own Id strategy - hence the LastContactId property).
First of all, it's all depending on the context and I assume that Company really is the AR for that specific context. The same Company can be a simple object in other contexts. Now, I'm not a fan of dogmatic use of rules and patterns so it is not important what the 'rule' says.
In this case I won't expose the Address as it seems to be an internal of the Company. As a coosnumer of the Company, I want its primary address, I don't care you're using the AddresBook to organize them.
To give a not so common example: the AR Human has two Eye objects. Will you ask the Person to give one of his eyes so you can check their color or you ask the Person directly what color his eyes are?
According to the Aggregate pattern:
Transient references to the internal members can be passed out for use within a single operation only.
Meaning - a Company can pass a reference to its Address object to other objects outside the aggregate, but Address cannot be a member of any other object outside the aggregate.
For example, an object User can ask a reference to an Address from a Company, but User cannot have Address as one of its members.
And why is that so important?
Because the root controls access, it cannot be blindsided by changes to the internals.
If an object User would have Address as one of its members, it might pull it out of the database without its Company and thus, Company would be blindsided by changes to its internals.
Please see a post I've wrote in which i demonstrate why is this principle so important.
Good question, this is one of the things I've always found hard to get right in DDD - do you always access entities through their aggregate root and probably violate the Law of Demeter at some point (AggregateRoot.EntityX.EntityY.DoStuff()) ? Do you short-circuit the aggregate root ? Do you add at the aggregate root level one direct accessor for each sub-sub-entity you want to access, muddling the aggregate root ?
One way to solve that could be : try to make every object talk only to its immediate or nearby neighbors and not to some distant stranger. Use multiple objects that each know a small part of the path from the aggregate root to the final entity you want to access.
The first object knows only the aggregate root,
It injects AggregateRoot.SubEntity1 into a second object,
Second object in turn injects SubEntity1.SubEntity2 into a third object
and so on.
Interestingly enough, one thing this reveals is the (ir)relevance of some of your domain entities. In the Address example, ask yourself if it feels right for every object that wants to access the primary Address of a Company to be injected an AddressBook. If it seems too convoluted, maybe you should not have an AddressBook in the first place. Maybe it isn't such a strong notion that it deserves to be part of the ubiquitous language after all.
Or, maybe you'll find out an AddressBook is precisely the right object to be used by your client object, and that this client object tries to do too many things at a time in manipulating both a Company and an Address.
Related
We are starting a new project and we are keen to apply DDD principles. The project is using dotnet core, with EF core providing the persistence to SQL Server.
Initial view of the domain
I will use an example of a task tracker to illustrate our issues and challenges as this would follow a similar structure.
In the beginning we understand the following: -
We have a Project
Users can be associated to Projects
A Project has Workstreams
A Workstream has Tasks
Users can post Comments against a Task
A User is able to change the status of a Task (in progress, complete etc)
A Project, with associated Worksteams and Tasks is initially created from a Template
The initial design was a large cluster aggregate with the Project being the root aggregate holding a collection of ProjectUsers and Workstreams, Workstreams has a collection of Tasks etc etc
This approach was obviously going to lead to a number of contention and performance issues due to having to load the whole Project aggregate for any changes within that aggregate.
Rightly or wrongly our next revision was to break the Comments out of the aggregate and to form a new aggregate using Comment as a root. The motivation for this was that the business envisaged there being a significant number of Comments raised against each Task.
As each Comment is related to a Task a Comment needs to hold a foreign key back to the Task. However this isn't possible following the principle that you can only reference another aggregate via its root. To overcome this we broke the Task out to another aggregate. This also seemed to satisfy the need that the Tasks could be Completed by different people and again would reduce contention.
We then faced the same problem with the reference from the Task to the Workstream the Task belongs to leading to us creating a new Workstream aggregate with the foreign key in the Task back to the Workstream.
The result is: -
A Project aggregate which only contains a list of Users assigned to the project
A Workstream aggregate which contains a foreign key to the Project
A Task aggregate which contains a foreign key to the Project
A Comments aggregate which contains a foreign key back to the Task
The Project has a method to create a new instance of a Workstream, allow us to set the foreign key. I.e. slightly simplified version
public class Project()
{
string _name { get; private set;}
public Project(Name)
{
_name = Name;
}
public Workstream CreateWorkstream(string name)
{
return new Workstream(name, Id);
}
....+ Methods for managing user assignment to the project
}
In a similar way Workstream has a method to create a Task
public class Workstream()
{
string _name { get; private set;}
public int ProjectId { get; private set; }
public Workstream(Name, Id)
{
_name = Name;
_projectId = Id;
}
public Task CreateTask(string name)
{
return new Task(name, Id);
}
private readonly List<Task> _activities = new List<Task>();
public IEnumerable<Task> Activities => _activities.AsReadOnly();
}
The Activities property has been added purely to support navigation when using the entities to build the read models.
The team are not comfortable that this approach, something doesn't feel right. The main concerns are:-
it is felt that creating a project logically should be create project, add one or more workstreams to the project, add task to the workstreams, then let EF deal with persisting that object structure.
there is discomfort that the Project has to be created first and that the developer needs to ensure it is persisted so it gets an Id, ready for when the method to Create the template is called which is dependent on that Id for the foreign key. Is it okay to push the responsibility for this to a method in a domain service CreateProjectFromTemplate() to orchestrate the creation and persistence of the separate objects to each repository?
is the method to create the new Workstream even in the correct place?
the entities are used to form the queries (support by the navigation properties) which are used to create the read models. Maybe the concern is that the object structure is being influence by the how we need to present data in a read only
We are now at the point where we are just going around in circles and could really use some advice to give us some direction.
The team are not comfortable that this approach, something doesn't feel right.
That's a very good sign.
However this isn't possible following the principle that you can only reference another aggregate via its root.
You'll want to let go of this idea, it's getting in your way.
Short answer is that identifiers aren't references. Holding a copy of an identifier for another entity is fine.
Longer answer: DDD is based on the work of Eric Evans, who was describing a style that had worked for him on java projects at the beginning of the millennium.
The pain that he is strugging with is this: if the application is allowed object references to arbitrary data entities, then the behaviors of the domain end up getting scattered all over the code base. This increases the amount of work that you need to do to understand the domain, and it increases the cost of making (and testing!) change.
The reaction was to introduce a discipline; isolate the data from the application, by restricting the application's access to a few carefully constrained gate keepers (the "aggregate root" objects). The application can hold object references to the root objects, and can send messages to those root objects, but the application cannot hold a reference to, or send a message directly to, the objects hidden behind the api of the aggregate.
Instead, the application sends a message to the root object, and the root object can then forward the message to other entities within its own aggregate.
Thus, if we want to send a message to a Task inside of some Project, we need some mechanism to know which project to load, so that we can send the message to the project to send a message to the Task.
Effectively, this means you need a function somewhere that can take a TaskId, and return the corresponding ProjectId.
The simplest way to do this is to simply store the two fields together
{
taskId: 67890,
projectId: 12345
}
it is felt that creating a project logically should be create project, add one or more workstreams to the project, add task to the workstreams, then let EF deal with persisting that object structure.
Maybe the concern is that the object structure is being influence by the how we need to present data in a read only
There's a sort of smell here, which is that you are describing the relations of a data structure. Aggregates aren't defined by relations as much as they are changes.
Is it okay to push the responsibility for this to a method in a domain service CreateProjectFromTemplate
It's actually fairly normal to have a draft aggregate (which understands editing) that is separate from a Published aggregate (which understands use). Part of the point of domain driven design is to improve the business by noticing implicit boundaries between use cases and making them explicit.
You could use a domain service to create a project from a template, but in the common case, my guess is that you should do it "by hand" -- copy the state from the draft, and then send use that state to create the project; it avoids confusion when a publish and an edit are happening concurrently.
Here is a different perspective that might nudge you out of your deadlock.
I feel you are doing data modeling instead of real domain modeling. You are concerned with a relational model that will be directly persisted using ORM (EF) and less concerned with the actual problem domain. That is why you are concerned that the project will load too many things, or which objects will hold foreign keys to what.
An alternative approach would be to forget persistence for a moment and concentrate on what things might need what responsibilities. With responsibilities I don't mean technical things like save/load/search, but things that the domain defines. Like creating a task, completing a task, adding a comment, etc. This should give you an outline of things, like:
interface Task {
...
void CompleteBy(User user);
...
}
interface Project {
...
Workstream CreateWorkstreamFrom(Template template);
...
}
Also, don't concentrate too much on what is an Entity, Value Object, Aggregate Root. First, represent your business correctly in a way you and your colleagues are happy with. That is the important part. Try to talk to non-technical people about your model, see if the language you are using fits, whether you can have a conversation with it. You can decide later what objects are Entities or Value Objects, that part is purely technical and less important.
One other point: don't bind your model directly to an ORM. ORMs are blunt instruments that will probably force you into bad decisions. You can use an ORM inside your domain objects, but don't make them be a part of the ORM. This way you can do your domain the right way, and don't have to be afraid to load too much for a specific function. You can do exactly the right things for all the business functions.
I'm trying to follow some of the more current design principles including SOLID and Domain Driven Design. My question is around how people handle "Initializing" Domain Objects.
Here's a simple example:
Based on SOLID, I should not depend on concretions, so I create an interface and a class. Since I'm taking advantage of Domain Driven Design, I create an object with relevant methods. (i.e. not anemic).
Interface IBookstoreBook
{
string Isbn {get; set;}
int Inventory {get; set;}
void AddToInventory(int numBooks);
void RemoveFromInventory(int numBooks);
}
public class BookstoreBook : IBookstoreBook
{
public string Isbn {get; set;}
public int Inventory {get; private set;}
public void AddToInventory(int numBooks);
public void RemoveFromInventory(int numBooks);
}
To help with testing and be more loosely coupled, I also use an IoC container to create this book. So when the book is created it is always created empty. But, if a book doesn't have an ISBN and Inventory it is invalid.
BookstoreBook(string bookISBN, int bookInventory) {..} // Does not exist
I could have 4 or 5 different classes that use a BookstoreBook. For one,
public class Bookstore : IBookstore
{
...
public bool NeedToIncreaseInventory(BookstoreBook book) { ...}
...
}
How does any method know is getting a valid book? My solutions below seem to violate the "Tell Don't Ask" principle.
a) Should each method that uses a Bookstore book test for validity? (i.e. should NeedToIncreaseInventory test for a books validity? I'm not sure it should have to know what makes a BookstoreBook valid.)
b) Should I have a "CreateBook" on the IBookstoreBook object and just "assume" that clients know they have to call this anytime they want to initialize a BookstoreBook? That way, NeedToIncreaseInventory would just trust that "CreateBook" was already called on BookstoreBook.
I'm interested in what the recommended appreach is here.
First off, I think your BookstoreBook doesn't have any really relevant methods, which means it doesn't have any relevant behavior, no business rules at all. And since it doesn't contain any business rules it actually is anemic. It just has a bunch of Getters and Setters. I would argue that having a method like AddToInventory that ends up just adding +1 to a property is no meaningful behavior.
Also, why would your BookstoreBook know how many of its type are in your Bookstore? I feel like this is probably something the Bookstore itself should keep track of.
As for point a): no, if you're creating books from user input you should check the provided data before you even create a new book. That prevents you from ever having invalid books in your system.
As for the creation of the object, the question is will you ever have more than one book type? If the answer is no you can drop the interface and just instantiate a book in a class that is responsible for creating new books from user input for example. If you need more book types an abstract factory may be useful.
First of all, a great way to make sure that entity state only can be set by behavior (methods) so to make all property setters private. It also allows you to make sure that all related properties are set when the state changes.
But, if a book doesn't have an ISBN and Inventory it is invalid.
There you have two business rules. Let's start with ISBN. If a book is not valid without it it HAVE to be specified in the constructor. Otherwise it's fully possible to create a book which is invalid. An ISBN also have a specified format (at least the length). So that format have to be validated too.
Regarding the inventory I believe that it's not true. You might have books that are sold out or books that can be booked before their release. Right? So a book CAN exist without an inventory, it's just not likely.
If you look at the relation between inventory and books from the domain perspective they are two separate entities with different responsibilities.
A book is representing something that the user can read about and use that information to decide whether it should be rented or purchased.
An inventory is used to make sure that your application can fulfill your customers request. Typically it can be done by a delivery directly (decrease the inventory) or by a backorder (order more copies from your supplier and then deliver the book).
Thus the inventory part of the application do not really need to know everything there is to know about the book. Thus I would recommend that the inventory only knows about the book identity (that's typically how root aggregates can reference each other according to Martin Fowler's book).
An inversion of control container is typically used to to manage services (in DDD the application services and the domain services). It's job is not to act as a factory for domain entities. It will only complicate things without any benefit.
To help with testing and be more loosely coupled, I also use an IoC container to create this book.
Why is your IoC container creating books? That's a bit strange. Your domain model should by container agnostic (wiring together the interfaces and the implementation is the concern of your composition root).
How does any method know is getting a valid book?
The domain model knows it is getting a valid book, because it says so right there in the interface.
The data model knows it is producing a valid book, because the constructor/factory method accepted its arguments without throwing an exception.
Should each method that uses a Bookstore book test for validity?
No, once you have a Book, it is going to stay valid (there shouldn't be any verbs defined in your domain model that would create an invalid data model).
Should I have a "CreateBook" on the IBookstoreBook object and just "assume" that clients know they have to call this anytime they want to initialize a BookstoreBook? That way, NeedToIncreaseInventory would just trust that "CreateBook" was already called on BookstoreBook.
It's normal to have a factory for creating objects. See Evans, chapter 6.
books can be created from a database and many other places. I'm assuming others have had to solve this issue if they are using DDD and I am wondering about their approach. Should we all be using factories - as you suggest that take the needed data as input?
There are really only two sources for data -- your own book of record (in which case, you load the data via a repository), and everywhere else (where you need to make sure that the data conforms to the assumptions of your model.
Based on SOLID, I should not depend on concretions
If you're referring to the Dependency Inversion principle, it does not exactly say that.
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
- Abstractions should not depend on details. Details should depend on abstractions.
No domain entity is of a higher level than another and normally no object in the Domain layer is a "detail", so DIP usually doesn't apply to domain entities.
I also use an IoC container to create this book
Considering that BookstoreBook has no dependency, I'm not sure why you would do that.
How does any method know is getting a valid book?
By assuming that the book is Always Valid, always consistent. This usually requires having a single Book constructor that checks all relevant rules at creation time, and state-changing methods that enforce invariants about the Book.
a) ...
b) ...
You're mixing up two concerns here - making sure that Book is in a consistent state wherever it is used, and initializing a Book. I'm not sure what your question is really about in the end, but if you apply the "always valid" approach and forget about Book being an interface/higher level abstraction, you should be good to go.
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 am building a system to manage person information. I have an ever growing aggregate root called Person. It now has hundreds of related objects, name, addresses, skills, absences, etc. My concern is that the Person AR is both breaking SRP and will create performance problems as more and more things (esp collections) get added to it.
I cannot see how with DDD to break this down into smaller objects. Taking the example of Absences. The Person has a collection of absence records (startdate, enddate, reason). These are currently managed through the Person (BookAbsence, ChangeAbsence, CancelAbsence). When adding absences I need to validate against all other absences, so I need an object which has access to the other absences in order to do this validation.
Am I missing something here? Is there another AR I have not identified? In the past I would have done this via an "AbsenceManager" service, but would like to do it using DDD.
I am fairly new to DDD, so maybe I am missing something.
Many Thanks....
The Absence chould be modeled as an aggregate. An AbsenceFactory is reposible for validating against other Absence s when you want to add a new Absence.
Code example:
public class AbsenceFactory {
private AbsenceRepository absenceRepository;
public Absence newAbsenceOf(Person person) {
List<Absence> current =
absenceRepository.findAll(person.getIdentifier());
//validate and return
}
}
You can find this pattern in the blue book (section 6.2 Factory if I'm not mistaken)
In other "modify" cases, you could introduce a Specification
public class SomeAbsenceSpecification {
private AbsenceRepository absenceRepository;
public SomeAbsenceSpecification(AbsenceRepository absenceRepository) {
this.absenceRepository=absenceRepository;
}
public boolean isSatisfiedBy(Absence absence) {
List<Absence> current =
absenceRepository.findAll(absence.getPersonIdentifier());
//validate and return
}
}
You can find this pattern in the blue book(section 9.2.3 Specification)
This is indeed what makes aggregate design so tricky. Ownership does not necessarily mean aggregation. One needs to understand the domain to be able to give a proper answer so we'll go with the good ol' Order example. A Customer would not have a collection of Order objects. The simplest rule is to think about deleting an AR. Those objects that could make sense in the absence of the AR probably do not belong on the AR. A Customer may very well have a collection of ActiveOrder objects, though. Of course there would be an invariant stating that a customer cannot be deleted if it has active orders.
Another thing to look out for is a bloated bounded context. It is conceivable that you could have one or more bounded contexts that have not been identified leading to a situation where you have an AR doing too much.
So in your case you may very well still be interested in the Absence should the Customer be deleted. In the case of an OrderLine it has no meaning without its Order. So no lifecycle of its own.
Hope that helps ever so slightly.
I am building a system to manage person information.
Are you sure that a simple CRUD application that edit/query RDBMS's tables via SQL, wouldn't be a cheaper approach?
If you can express the most of the business rules in term of data relations and table operations, you shouln't use DDD at all.
I have an ever growing aggregate root called Person.
If you actually have complex business rules, an ever growing aggregate is often a syntom of undefined (or wrongly defined) context boundaries.
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.