Praveen Kumar
Praveen Kumar

Reputation: 815

Domain Driven Implementation - Updating a single property inside Aggregate Root

I am new to DDD and I would like to have some advice on a few challenges I am facing in the implementation of it.

I am using Typescript to develop the application. The data is persisted in a Relational DB. We are not following CQRS pattern and our reads and writes happen in the same database.

Let's assume I have an aggregate User roughly like below,

class User extends AggregateRoot {

id: number;
phone: Phone;
email: Email;
address: Address;

private constructor(id, phone, email, address){
    //setting the values
}

public static create(props) {

    return new User({...props});
}

public static update(props) {

    return new User({...props});
}

}

Here, Phone and Email are ValueObjects and Address is an Entity.

class Phone extends ValueObject {

phNumber: string;

private constructor( ph ) {

    phNumber = ph;
}

public static create(ph){

    //do validations
    return new Phone(ph);
}
}

The class Email is also similar to Phone.

Now, once the update phone request is received in the controller, the request is forwarded to the User Service layer and the service will look roughly like this,

public updatePhone( updatePhNoDto ) {

const userEntity = userRepository.getUser(updatePhNoDto.userId);

const userModel = User.update({
    id: updatePhNoDto.userId,
    phone: Phone.create(userEntity.phone),
    email: Email.create(userEntity.email),
    address: Address.create(userEntity.address)
});

userRepository.updateUser(userModel)
}

Here each time the user requests for updating the phone number, I am fetching the user data from the RDBMS and doing all the validations for all the fields which are already validated and then calling the method User.update(). So, here are my questions:

  1. Not sure if the above is the right way since I am validating the stuffs that I have already validated and possibly an unnecessary DB call. So, please suggest me on the best practices to deal with the situations like this where a single or only a few fields are being requested to be updated.
  2. A user can update his Address independent of his other information. So, should the Address entity be an Aggregate Root by itself? If yes, how should it be handled if both UserInfo and Address are requested to be updated in a single http-request?
  3. What is the role of the Aggregate Root in deletion? How should that be modeled inside it?

Please let me know if you find any other flaws in the design.

Thanks!

Upvotes: 1

Views: 1140

Answers (1)

Brad Irby
Brad Irby

Reputation: 2542

Just like the controller has an UpdatePhone endpoint, the User will have an UpdatePhone method that only verifies and updates the phone number. The User AR will also have UpdateEmail, UpdateAddress, etc.

If a user can change multiple User properties at a time on the front end, you use the Controller to figure that out. You would have an UpdateUser endpoint on the controller that would decide what was changed and what wasn’t, then call all necessary methods on the User. Some pseudo code:

If (PhoneInfoUpdated) User.UpdatePhone({user submitted phone fields});
If (EmailInfoUpdated) User.UpdateEmail({user submitted email field});
If (AddressInfoUpdated) User.UdateAddress({user submitted address info});

(You probably just deleted this for brevity in the post, but remember there are 2 levels of data validation here. The controller validates data types, such that if you’re expecting integers you actually get integers, dates are dates, phone numbers and emails are the proper format, etc. Then inside the User.UpdateWhatever method you validate that business rules are satisfied, such as email address is not a duplicate of an existing one, etc.)

I don’t understand how an address can have a life of its own without being owned by a User, but if that is your business case then it should be an AR. Therefore to change the Address you should have a separate Address API endpoint that does the proper manipulations instead of trying to send that through the User endpoint. The front end should make this decision of the proper endpoint to call if it is calling APIs directly, or if you're using MVC the controller receives the postback and can then either call the proper APIs or appropriate methods on the ARs.

As for deletions, I’ve never been a fan of actual deletion so I would recommend adding an Active flag (or Deleted flag depending on which side of that interminable debate you are on). Whether you actually delete or just set a flag, you should have a User.Delete method. If you are really deleting the row, I prefer that to be a static method on the User class so you don’t have to retrieve a user just to then delete it. If you are using a flag, the Delete method should be public on the class because it’s really just setting a property like any other property.

Upvotes: 1

Related Questions