How can I create this component from root in DDD? - domain-driven-design

I have a question about how to solve the following scenario using DDD.
I have 2 entities Person and Email with one to many relationship. A person can have zero or more email address(es).
Person is an aggregate root of Email which is a component.
class Person{
Set<Email> emails = new HashSet<Email>
}
Class Email {
String value;
Email(String value){
}
}
I have 2 requirements in the system:
User can send a request to add a new Email to person
User can create a list of emails temporarily and may or may not add them to person.
Does having 3 methods make sense in DDD? Or is there a better way to do meet my requirements above.
To create Email from party but not add it to the emails list (see createEmail() below).
Having a seperate method just to add email to the list (see setEmail() below).
A method to create email for a person and add it to the emails list (see addEmail() below).
public Class Person{
Set<Email> emails = new HashSet<Email>
public void addEmail(String value){
Email email = createEmail(value);
emails.add(email);
}
public Email createEmail(String value){
return new Email(value);
}
public void setEmail(Email email){
emails.add(email);
}
}

Personally, I would see it different:
I would only see 'Person' as being an entity. Email is a value type (component) and not an entity, since it has no identity.
Then, I would expose the eMail adresses of a person as a read-only collection of the Person entity.
public class Person
{
public void AddEmail( Email mail ) {}
public void AddEmail( string mailAddress) {}
public void RemoveEmail( Email mail ){}
public void RemoveEmail( string mailAddress ){}
Email[] GetEmailAdresses() {};
}
public struct Email
{
public Email( string address ){}
public string Address
{
get {return _address; }
}
}

Personally I would think that a method called setEmail() would likely add a special email to the person. For example a person has a primary email address. I think it is better to overload addEmail to clarify this point.
Furthermore I would use a factory to create a temporary email. It is not the responsibility of a person to create email addresses in the real world. A good DDD in my imagination is a image of reality so that it is easier to use and in some way self documenting. My code would look something like this:
public Class Person {
Set<Email> emails = new HashSet<Email>
public void addEmail(String value){
Email email = EmailFactory.createEmail(value);
emails.add(email);
}
public void addEmail(Email email){
emails.add(email);
}
}
public class Email {...}
public class EmailFactory {
public static Email createEmail(String value) {
return new Email(value);
}
}

Related

What are the real world, production grade cases for domain events (understood as events within same bounded context & process)?

If we have a bounded context with lets say 2 aggregates where aggregate1 publishes event1 and aggregate2 wants to react to it, we have 1 ways of doing it:
in process raising event1 > aggregate2 reacting to it
publish event1 to message bus and have some separate process pick it up & invoke aggregate2 method(s)
regardless of being within the same bounded context, if we want to make sure we don't lose event1 (application crashes between aggregate1 is saved, and aggregate2 is saved in reaction to event1, e.g.) i have a hard time finding examples of when would option 1 be better than option 2 (beyond maybe validation)?
i must be missing something but at this point of my knowledge, it seems like a pure theoretical concept to me without some real world value in terms of reliability and ability to maintain correct state.
of course that publishing a message and having separate process listen/react to it might seem like an overkill but is there any practical use of domain events that are not persisted somewhere (even within local DB which gets polled in which case i'd call that a primitive message bus)?
what am i missing?
What is a real world application of domain events within a bounded
context and process?
Requirements:
User can create categories.
Category names must be unique.
User can rename categories.
(Category will have a number of other properties unrelated to naming).
DDD Concepts:
A Category aggregate should be responsible for its own internal invariants, but cannot know the details about other Category aggregates.
How are you going to ensure that the Category Name for the current Category is globally unique without the Category having access to all other categories?
Answer: Domain Events
DomainEvent
public CategoryRenamed : DomainEvent
{
public Category Category { get; }
internal CategoryRenamed(Category category)
{
this.Category = category;
}
}
DomainEventHandler
public CategoryRenamedHandler : IDomainEventHandler<CategoryRenamed>
{
public CategoryRenamedHandler(CategoryRenamed domainEvent)
{
string proposedName = domainEvent.Category.Name;
// query database to ensure that proposedName is not already in use
if (inUse)
throw new Exception($"Name {proposedName} already in use." ;
}
}
Entity
public abstract class Entity
{
List<DomainEvent> _domainEvents = new List<DomainEvent>();
protected AddDomainEvent(DomainEvent domainEvent)
{
_domainEvents.Add(domainEvent);
}
public List<DomainEvent> DomainEvents => _domainEvents;
}
Category
public class Category : Entity
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public Category(Guid id, string name)
{
Id = id;
SetName(name);
}
public Rename(string name)
{
SetName(name);
}
void SetName(string name)
{
// Local Invariants
if (string.IsNullOrWhitespace(name))
throw new Exception("Invalid name");
Name = name;
// Add a domain event for the infrastructure to process
AddDomainEvent(new CategoryRenamed(this));
}
}
Command
public class AddCategoryCommand
{
public Guid Id { get; set; }
public string Name { get; set; }
}
CommandHandler
public class CommandHandler : ICommandHandler<AddCategoryCommand>
{
readonly ICategoryRepository _categoryRepository;
public CommandHandler(ICategoryRepository categoryRepository)
{
_categoryRepository = categoryRepository;
}
public void HandleCommand(AndCategoryCommand command)
{
Category newCategory = new(command.Id, command.Name);
// Check for domain events before committing to repository
DomainEventDispatcher.DispatchEvents(newCategory.DomainEvents);
// Dispatcher will find the CategoryRenamed event and send 'in-process'
// to CategoryRenamedHandler
// If name was is in use an error will be thrown by the handler (see above)
_categoryRepository.Add(newCategory);
}
}
Outcome
Your Category aggregate has enforced its own local invariants and the domain command and domainevent handling infrastructure has been leveraged to ensure uniqueness of name across all categories.

How to initialize sub-collections along with aggregate root in abp.io

What I want to achieve is to figure out where to initialize my sub-collections with aggregate root itself and validate business rules in a best practice way.
Here is my AppService:
public async Task<ReservationDto> CreateReservationAsync(CreateReservationInputDto input)
{
var reservation = await _reservationSystemManager.CreateAsync(
input.ReserverNotes
);
//should i send them directly to manager's createasync method but RequestedItems are dto objects.
//should i iterate through RequestedItems here and send them to manager one by one.
// where to throw business exception if RequestedItems count is 0.
}
Here is my inputdto:
public class CreateReservationInputDto
{
public string ReserverNotes { get; set; }
public Enum.Status Status { get; set; }
public List<CreateReservationItemInputDto> RequestedItems { get; set; }
}
Here is my aggregate root:
public class Reservation : FullAuditedAggregateRoot<Guid>
{
public Enum.Status Status { get; private set; }
public string ReserverNote { get; private set; }
public ICollection<ReservationItem> ReservationItems { get; set; }
public ICollection<OverduePayment> OverduePayments { get; set; }
private Reservation() { }
internal Reservation(
Guid id,
Enum.Status status,
[NotNull] string reserverNote,
) : base(id)
{
ReserverNote = reserverNote;
Status = status;
ReservationItems = new Collection<ReservationItem>();
OverduePayments = new Collection<OverduePayment>();
}
//I could not decide where and how to call this function from Domain Service.
internal void AddReservationItem(ReservationItem reservationItem)
{
if (ReservationItems.Any(r => r.Id == reservationItem.Id))
{
return;
}
ReservationItems.Add(reservationItem);
}
}
Well, depends on your business rules and your use cases. For example, if a reservation must have some reservation items, then I would create it in reservation constructor. Otherwise, if after creating reservation I can add new reservation items then I would be another use case and then AddReservationItem has sense for me.
Generally, if you need to inject more than one service (E.g. IUserRepository and IReservationItemsRepository) for validating your collection or any other property, you can create a domain service and implement your business logic and validate your collection with your needs.
If you don't need to inject any service to implement your business rules you can do it directly in your application service methods. In such cases, you can use data annotations for validating your properties in DTO classes as stated in here.
//should i send them directly to manager's createasync method but RequestedItems are dto objects.
//should i iterate through RequestedItems here and send them to manager one by one.
//where to throw business exception if RequestedItems count is 0.
In these three questions you've asked, should take it separately.
For instance, If you create a domain service class, it could be better to throw an exception if the RequestedItems count is 0 in that class' method. (And you can call, your AddReservationItem method from the domain service's method in that case.)
You can also check the best-practices documents of ABP.

Product, Category, Attributes modelling in DDD

I'm trying to model online shop catalog using Domain Driven Design.
There are three main concepts I have right now: Product, Category, Attribute.
Attribute is a characteristic of a product. For instance things such as color, weight, number of CPU cores etc. There are attributes which possible values are fixed, for instance "condition" - can be new or used. Some of them are within some range of values, for instance "number of CPU cores". Some are freely created like "color".
Category have required attributes which every product within that category needs to have, and optional ones. Categories can have parent categories.
Product belongs to a single category which needs to be a leaf category(no children categories).
Now the problem I have is to model these three concepts as aggregates.
One option is to have three different aggregates: Product, Attribute, Category.
Product will have it's attribute values(each with parent id to Attribute AR). Attribute will be in different types(fixed, freely choosen, range). Category will have a list of IDs of Attributes which are required, and list of IDs
The issue here is that whenever I need to create a new product I would need to check if it has all of the required attributes, check the values, and then store the product. This validation would span three aggregates. Where should it go ? It should be domain service ?
Other option is to have 2 AR. Category, with it's products and Attributes. The issue here is again validation of correct values for a single attribute added to a product. The other huge issue I see here, is that I should fetch the whole aggregate from the repository. Given that category can have hundreds of products, I don't think that's a good idea. However it makes sense as a conceptual whole, as If I would like to delete a category, all of it's products should be deleted as well.
What I am missing here ?
In "Implementing Domain Driven Design", Vaugh Vernon uses the "specification pattern" to handle entity/aggregate validation. Without quoting the entire chapter, you have different possibilities : (Java is used in my example, I hope you get the overall idea)
Validating Attributes / Properties
If it is a simple validation process field by field, then validate each attribute separately inside the setter method.
class Product {
String name;
public Product(String name) {
setName(name);
}
public void setName(String name) {
if(name == null) {
throw new IllegalArgumentException("name cannot be null");
}
if(name.length() == 0) {
throw new IllegalArgumentException("name cannot be empty");
}
this.name = name;
}
}
Validating Whole Object
If you have to validate the whole object, you can use a kind of specification to help you. To avoid having the entity having too much responsibilities (dealing with the state, and validate it), you can use a Validator.
a. Create a generic Validator class, and implement it for your Product Validator. Use a NotificationHandler to deal with your validation error (exception, event, accumulating errors and then sending them ? up to you) :
public abstract class Validator {
private ValidationNotificationHandler notificationHandler;
public Validator(ValidationNotificationHandler aHandler) {
super();
this.setNotificationHandler(aHandler);
}
public abstract void validate();
protected ValidationNotificationHandler notificationHandler() {
return this.notificationHandler;
}
private void setNotificationHandler(ValidationNotificationHandler aHandler) {
this.notificationHandler = aHandler;
}
}
NotificationHandler is an interface, that you could implement given your requirements in term of validation error handling. Here is the interface proposed by Vaugh Vernon :
public interface ValidationNotificationHandler {
public void handleError(String aNotificationMessage);
public void handleError(String aNotification, Object anObject);
public void handleInfo(String aNotificationMessage);
public void handleInfo(String aNotification, Object anObject);
public void handleWarning(String aNotificationMessage);
public void handleWarning(String aNotification, Object anObject);
}
b. Implements this class with a specific validator ProductValidator:
public class ProductValidator extends Validator {
private Product product;
public ProductValidator(Product product, ValidationNotificationHandler aHandler) {
super(aHandler);
this.setProduct(product);
}
private void setProduct(Product product) {
this.product = product;
}
#Override
public void validate() {
this.checkForCompletness();
}
private void checkForCompletness() {
if(product.getName().equals("bad name") && anotherCondition()) {
notificationHandler().handleError("This specific validation failed");
}
...
}
}
And then, you can update your entity, with a validate method, that will call this validator to validate the whole object:
public class Product {
private String name;
public Product(String name) {
setName(name);
}
private void setName(String name) {
if (name == null) {
throw new IllegalArgumentException("Name cannot be null");
}
if (name.length() == 0) {
throw new IllegalArgumentException("Name cannot be empty");
}
this.name = name;
}
// Here is the new method to validate your object
public void validate(ValidationNotificationHandler aHandler) {
(new ProductValidator(this, aHandler)).validate();
}
}
Validating multiple aggregates
And finally, which is your direct concern, if you want to validate multiple aggregates to have something coherent, the recommendation is to create a Domain Service and a specific validator. The domain services can either have injected the repositories to look up for the different aggregates, or I everything is created by the application layers, then inject the different aggregates as method parameter:
public class ProductCategoryValidator extends Validator {
private Product product;
private Category category;
public ProductCategoryValidator(Product product, Category category, ValidationNotificationHandler aHandler) {
super(aHandler);
this.setProduct(product);
this.setCategory(category);
}
private void setCategory(Category category) {
this.category = category;
}
private void setProduct(Product product) {
this.product = product;
}
#Override
public void validate() {
this.checkForCompletness();
}
private void checkForCompletness() {
// Count number of attributes, check for correctness...
}
}
And the domain service that will call the Validator
public class ProductService {
// Use this is you can pass the parameters from the client
public void validateProductWithCategory(Product product, Category category, ValidationNotificationHandler handler) {
(new ProductCategoryValidator(product, category, handler)).validate();
}
// Use This is you need to retrieve data from persistent layer
private ProductRepository productRepository;
private CategoryReposiory categoryReposiory;
public ProductService(ProductRepository productRepository, CategoryReposiory categoryReposiory) {
this.productRepository = productRepository;
this.categoryReposiory = categoryReposiory;
}
public void validate(String productId, ValidationNotificationHandler handler) {
Product product = productRepository.findById(productId);
Category category = categoryReposiory.categoryOfProductId(productId);
(new ProductCategoryValidator(product, category, handler)).validate();
}
}
Like I said, I think you might be interested into the solution 3. As you have guessed it, you can use a Domain Service. But, add a specific validator to ensure the "responsibilities" are not mixed.
The issue here is that whenever I need to create a new product I would need to check if it has all of the required attributes, check the values, and then store the product. This validation would span three aggregates. Where should it go ? It should be domain service ?
The usual answer is that the retrieval of information (aka I/O) is done in an application service. Copies of that information are then passed, like other inputs, into the domain model.
A single "transaction" might include multiple calls to aggregate methods, as we fetch inputs from different places.
These copies of information are generally treated as data on the outside - we have an unlocked copy of the data here; while we are using that copy, the authoritative copy might be changing.
If you find yourself thinking that "the authoritative copy of the data over there isn't allowed to change while I use it over here" - that's a big red flag that either (a) you don't actually understand your real data constraints or (b) that you've drawn your aggregate boundaries incorrectly.
Most data from the real world is data on the outside (Bob's billing address may change without asking your permission - what you have in your database is a cached copy of the Bob's billing address as of some point in the past).

Domain Driven Design - How to handle updates for parts of your aggregrate roots

BACKGROUND: I have a Person domain object. It is an aggregate root. I have included a portion of the class below.
I am exposing methods to perform the objects behaviors. For instance, to add a BankAccount I have the AddBankAccount() method. I have not included all the methods of the class but suffice to say that any public property must be updated using a method.
I am going to create an IPerson repository to handle the CRUD operations.
public interface IPersonRepository
{
void Save(Person p);
//...other methods
}
QUESTION: How do I tell the repository which fields need to be updated when we are updating an existing person? For example, If I add a bank account to an existing person how do I communicate this information to the repository when repository.Save() is called?
In the repository it is easy to determine when a new person is created, but when an existing person exists and you update fields on that person, i'm not sure how to communicate this to the repository.
I don't want to pollute my Person object with information about which fields are updated.
I could have separate methods on the repository like .UpdateEmail(), AddBankAccount() but that feels like overkill. I would like a simple .Save() method on the repository and it determines what needs to update in some manner.
How have others handled this situation?
I have searched the web and stackoverflow but haven't found anything. I must not be searching correctly because this seems like something simple when it comes to persistence within the DDD paradigm. I could also be way off on my understanding of DDD :-)
public class Person : DomainObject
{
public Person(int Id, string FirstName, string LastName,
string Name, string Email)
{
this.Id = Id;
this.CreditCards = new List<CreditCard>();
this.BankAccounts = new List<BankAccount>();
this.PhoneNumbers = new List<PhoneNumber>();
this.Sponsorships = new List<Sponsorship>();
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string Name{ get; private set; }
public string Email { get; private set; }
public string LoginName { get; private set; }
public ICollection<CreditCard> CreditCards { get; private set; }
public ICollection<BankAccount> BankAccounts { get; private set; }
public ICollection<PhoneNumber> PhoneNumbers { get; private set; }
public void AddBankAccount(BankAccount accountToAdd, IBankAccountValidator bankAccountValidator)
{
bankAccountValidator.Validate(accountToAdd);
this.BankAccounts.Add(accountToAdd);
}
public void AddCreditCard(CreditCard creditCardToAdd, ICreditCardValidator ccValidator)
{
ccValidator.Validate(creditCardToAdd);
this.CreditCards.Add(creditCardToAdd);
}
public void UpdateEmail(string NewEmail)
{
this.Email = NewEmail;
}
There is an example of Repository interface from S#arp Architecture project. It is similar to PoEAA Data Mapper because it used to CRUD operations also.
public interface IRepositoryWithTypedId<T, IdT>
{
T Get(IdT id);
IList<T> GetAll();
IList<T> FindAll(IDictionary<string, object> propertyValuePairs);
T FindOne(IDictionary<string, object> propertyValuePairs);
T SaveOrUpdate(T entity);
void Delete(T entity);
IDbContext DbContext { get; }
}
As you can see, there is no update method for specific properties of an entity. The whole entity is provided as an argument into the method SaveOrUpdate.
When properties of your domain entity are being updated you should tell your Unit of Work that entity is 'dirty' and should be saved into storage (e.g. database)
You should not pollute your Person object with information about updated fields but it is needed to track information if entity is updated.
There might be methods of the class DomainObject which tell 'Unit of Work' if entity is 'new', 'dirty' or 'deleted'. And then your UoW itself might invoke proper repository methods - 'SaveOrUpdate' or 'Delete'.
Despite the fact that modern ORM Frameworks like NHibernate or EntityFramework have their own implementations of 'Unit of Work', people tend to write their own wrappers/ abstractions for them.
What I'm doing to solve this problem, is adding an interface to my domain objects:
interface IDirtyTracker {
bool IsDirty {get;}
void MarkClean();
void MarkDirty();
}
The base DomainObject class could implement IDirtyTracker, and then repositories etc. could use IsDirty to check if it's dirty or clean.
In each setter that makes a change:
void SetValue() {
this._value = newValue;
this.MarkDirty();
}
This does not give you fine grain checking, but it's a simple way to avoid some unnecessary updates at the repository level.
To make this a little easier, a GetPropertiesToIncludeInDirtyCheck method could be added, which would retrieve a list of properties which need to be checked.
interface IDirtyTracker {
IENumerable<Object> GetPropertiesToIncludeInDirtyCheck();
}

How update an entity inside Aggregate

I have an aggregate named Campaigns every with a root entity named campaign, this root entity has a list of attempts (entity)
public class Attempts: IEntity<Attempts>
{
private int id;
public AttempNumber AttemptNumber {get;}
//other fields
}
public class Campaign: IEntity<Campaign> //root
{
private int id;
public IList<Attempt> {get;}
//other fields
}
Im using a method to add a campaign attempt
public virtual void AssignAttempts(Attempts att)
{
Validate.NotNull(att, "attemps are required for assignment");
this.attempts.add(att);
}
Problem comes when i try to edit a specific item in attempts list. I get Attempt by AttempNumber and pass it to editAttempt method but i dont know how to set the attempt without deleting whole list and recreate it again
public virtual void EditAttempts(Attempts att)
{
Validate.NotNull(att, "attemps are required for assignment");
}
Any help will be appreciated!
Thanks,
Pedro de la Cruz
First, I think there may be a slight problem with your domain model. It seems to me like 'Campaign' should be an aggregate root entity having a collection of 'Attempt' value objects (or entities). There is no 'Campaigns' aggregate unless you have a parent concept to a campaign which would contain a collection of campaigns. Also, there is no 'Attempts' entity. Instead a collection of 'Attempt' entities or values on the 'Campaign' entity. 'Attempt' may be an entity if it has identity outside of a 'Campaign', otherwise it is a value object. The code could be something like this:
class Campaign {
public string Id { get; set; }
public ICollection<Attempt> Attempts { get; private set; }
public Attempt GetAttempt(string id) {
return this.Attempts.FirstOrDefault(x => x.Number == id);
}
}
class Attempt {
public string Number { get; set; }
public string Attribute1 { get; set; }
}
If you retrieve an Attempt from the Campaign entity and then change some of the properties, you should not have to insert it back into the campaign entity, it is already there. This is how the code would look if you were using NHibernate (similar for other ORMs):
var campaign = this.Session.Get<Campaign>("some-id");
var attempt = campaign.GetAttempt("some-attempt-id");
attempt.Attribute1 = "some new value";
this.Session.Flush(); // will commit changes made to Attempt
You don't need an Edit method. Your code can modify the Attempts in-place, like so:
Attempt toModify = MyRepository.GetAttemptById(id);
toModify.Counter++;
toModify.Location = "Paris";
MyRepository.SaveChanges(); // to actually persist to the DB
Of course how you name the SaveChanges() is up to you, this is the way Entity Framework names its general Save method.

Resources