The next thing is to define our model. Here we will try to apply domain-driven design. In domain-driven design, we model our classes based on the business domain and terminology. Obviously, if you have read the user stories, we already have a lot of clues about our domain, classes, and their properties.
For the time being, we can model our domain with 5 classes: Product, Order, User, OrderItem, and StockAmount. In this case, product and user are separate aggregates. An aggregate is a domain-driven development concept. Aggregates are used to designate independent parts of our domain classes. Typically, each aggregate consists of one or more classes and each represents a set of independent invariants. We have the following invariants:
- An order has at least 1 order item.
- An order has a create date and a user ID.
- An order item denotes a quantity and price and product ID.
- For an order item, quantity and price cannot be zero.
- An unconfirmed order denotes the current shopping cart.
- A customer can have maximum 1 unconfirmed order. (Drops to zero when checkout is completed)
- For an order item, the product ID must be valid. For a product, stock amount and price must be greater than or equal to zero.
- For StockAmount, the quantity must be equal to the quantity in an order item.
In the preceding diagram, we have defined three aggregates as Order, Product, and User. The dash lines above show indirect reference via the ID field whereas the solid line between Order and OrderItem refers to a direct reference. The very reason we have chosen this approach is that different modules of the application, such as the administration module, may want to deal with an aggregate independently. Changing a user's postal address should not affect the user's existing orders and order items. They are very much independent from each other. We can also move these entities to different micro services. After all, our business invariants and constraints should only hold per an aggregate. Again, there is no absolute right way to do this, it depends on the project and how much you invest in future. As for the shopping cart itself, we will use the Order entity if the order is unconfirmed.