Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DDD Customer, Contacts, and Addresses (aggregate root)

I'm building an application that manages most of the LOB stuff at my company. I'm trying to wrap my head around DDD... starting with customer management. Many examples are very, very simple in regards to the domain model which doesn't help me much.

My aggregate root is a Customer class, which contains a collection of Addresses (address book), a collection of Contacts, and a collection of communication history.

Seems like this aggregate root is going to be huge, with functions to modify addresses, contacts (which can have x number of phone numbers), and communication.

E.G.

UpdateCustomerName(...)
SetCustomerType(...) // Business or individual
SetProspect(...) // if the customer is a prospect
SetDefaultPaymentTerms(...) // line of credit, etc. for future orders
SetPreferredShippingMethod(...) // for future orders
SetTaxInfo(...) // tax exempt, etc.
SetCreditLimit(...)
AddAddress(...)
RemoveAddress(...)
UpdateAddress(...)
VerifyAddress(...)
SetDefaultBillingAddress(...)
SetDefaultShippingAddress(...)
AddContact(...)
UpdateContact(...)
RemoveContact(...)
SetPrimaryContact(...)
AddContactPhoneNumber(...)
RemoveContactPhoneNumber(...)
UpdateContactPhoneNumber(...)
AddCommunication(...)
RemoveCommunication(...)
UpdateCommunication(...)
etc.

I've read that value objects don't have identity. In this system, each address (in the database) has an ID, and has a customerId as the foreign key. If Address is it's own aggregate root, then I wouldn't be able to have my business logic for setting default billing / shipping. Many examples have value objects without an ID... I Have no idea how to persist the changes to my Customer table without it.

Anywho, feels like I'm going down the wrong path with my structure if its going to get this ginormous. Anyone do something similar? Not sure how I can break down the structure and maintain basic business rules (like making sure the address is assigned to the customer prior to setting it as the default billing or shipping).

like image 478
Chris Klepeis Avatar asked Jul 06 '16 18:07

Chris Klepeis


People also ask

What is aggregate and aggregate root in DDD?

An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. Each AGGREGATE has a root and a boundary. The boundary defines what is inside the AGGREGATE. The root is a single, specific ENTITY contained in the AGGREGATE.

How is aggregate DDD defined?

Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate.

Can an aggregate root reference another aggregate root?

[Evans] states that one Aggregate may hold references to the Root of other Aggregates. However, we must keep in mind that this does not place the referenced Aggregate inside the consistency boundary of the one referencing it. The reference does not cause the formation of just one whole Aggregate.

What are aggregates in bounded context?

Aggregates represent business entities, and thus are smaller in scope than Bounded Contexts, which represent entire domains. Aggregates encapsulate data, whereas Bounded Contexts encapsulate services, team members, and their shared language(s)


1 Answers

The reason that you're butting up against the issue of where business logic should lie is because you're mixing bounded contexts. LoB applications are one of the typical examples in DDD, most of which show the application broken up into multiple bounded contexts:

  • Customer Service
  • Billing
  • Shipping
  • Etc.

Each bounded context may require some information from your Customer class, but most likely not all of it. DDD goes against the standard DRY concept when approaching the definition of entities. It is OK to have multiple Customer classes defined, one for each bounded context that requires it. In each bounded context, you would define the classes with properties and business logic to fulfill the requirements within that bounded context:

  • Customer Service: Contact information, contact history
  • Billing: Billing address, payment information, orders
  • Shipping: Line items, shipping address

These bounded contexts can all point to the same database, or multiple databases, depending on the complexity of your system. If it is the same database, you would set up your data access layer to populate the properties required for your bounded context.

Steve Smith and Julie Lerman have a fantastic course on Pluralsight called Domain-Driven Design Fundamentals that covers these concepts in depth.

like image 73
Larry Avatar answered Sep 28 '22 07:09

Larry