1

I've been practicing DDD and refactoring an app to understand it's principles and applications better. However I can't fully grasp some of the ideas and how to implement them in my business domain.

Let me start with stating a business requirement: A user can place and order and this order would need to be verified by a sales manager who is responsible for the orders of that specific product. User can be a registered user or an anonymous user. In both cases order comes from a request form that contains all the required information for order to be placed. Users can purchase their orders with different supported payment methods.

Now this requirement only belongs to the "placing an order" context. Other parts of the app includes how to process this order after it's verified, and then when the processing is complete, eventually deliver the order.

For this requirement I'm trying to think of my domain entities. First I think it'd be logical to have Customer aggregate, because from the original requirement it's clear that a Customer can place an order so my code could be something like the following:

class Customer {
   Key Id
   void PlaceOrder(OrderRequest request) {...}
}

However, business requirement states that this user can be an anonymous user in that case I have no "Customer" instance that I can map the incoming request to. So I change my model and come up with the following aggregate:

class OrderContext {
   Key OrderId;
   void PlaceOrder(OrderRequest request, Nullable<Customer> customer) {...}
}

But then DDD examples and books state that domain entities should correspond to their use cases. In this context, it's not very clean when you read this code and out loud state "an Order can place itself" - errm what?

How do you model your domain for a business requirement like the above? Who is actually responsible for creating this order? On top of that, an order can be placed from the sales manager's if, for example we want to gift to a customer for compensation. In this case, a "SalesManager" entity would also have "placeOrder" method in it. I'm totally confused and lost about how to translate this kind of business logic into my domain models.

How would be the relation between orders and customers and sales managers then? I could have "orders" collection in all of those entities and then it'd be a nightmare to keep all of them in a consistent state considering this is a web app and aggregates are loaded - consumed and then destroyed per request basis.

2
  • What does it mean for a Customer to be anonymous? Is that a Customer who refuses to leave any details (like name and shipping address)? Or is that a Customer who is not on file with an account (thus not known as a returning Customer)? Talk to your sales people what for them the difference is between an anonymous Customer and a Customer who is a registered user. Jan 2, 2021 at 14:22
  • A registered customer is a customer that we have a record of him and both the system and the user itself can track their orders when they are logged in. An anonymous / unregistered customer is simply a "shopper" which we don't have any information in our database about them. Jan 2, 2021 at 14:54

1 Answer 1

0

For this requirement I'm trying to think of my domain entities. First I think it'd be logical to have Customer aggregate, because from the original requirement it's clear that a Customer can place an order so my code could be something like the following:

class Customer {
  Key Id
  void PlaceOrder(OrderRequest request) {...}
}

However, business requirement states that this user can be an anonymous user in that case I have no "Customer" instance that I can map the incoming request to.

You should realize that a Customer and a Registered User are two (related but) distinct entities. The Registered User is a person who has gone through the trouble of creating an account. A Customer is a person who places an order.

To model your entities, I would do it like this

class Customer {
  Key Id
  Nullable<Account> Account

  static Customer CreateForAccount(Account registeredUser) { ... }
  static Customer CreateAnonymous() { ... }

  void PlaceOrder(OrderRequest request) { ... }
}

The Customer class has a link to the Account that was used when placing the order. That link is Nullable to cater for anonymous customers who don't have an account. For good measure, I included two Factory Methods to create the two kinds of customers.

This Customer class would probably grow to have additional properties, such as the customer's name, billing address and shipping address, which are all needed when fulfilling an order and might be different for this order from the defaults that a registered user might have on file (for example, when they are purchasing on behalf of a friend). An anonymous customer would, off course, have nothing on file.

2
  • So according to this model, can I assume if I want to create an order for an unregistered user, or create an order from a sales manager's logged in user I should still create a Customer domain object and call it's method to enforce domain invariants am I getting this right? PlaceOrder method should put the order in customer's "orders" list (for registered users obviously) and then fire a domain event for further order processing is that right? Jan 2, 2021 at 22:02
  • Yes that is right Jan 3, 2021 at 7:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.