0

I am new to DDD and I am having trouble structuring an object. I have a cart, where I can add products to it. Each product has some properties like image, title, price, etc. Whenever a product is added to the cart, the database stores this relation in a separate table, called cart_products. This new table allows me to add some new properties to the cart product, like an observation, it has an id different from that of the product in the products table, it can have additionals like "fries for a cheeseburguer", so on. So, if I am working on a cart object, which has products (which come from the cart_products table), should I have a cart.products, which would be an array of products, where each product will be a cart_product, with an id, observation and then a property product which has all the properties of product, like image, title, price, or I can have all these properties directly inside my product? Basically.

cart = {
  products = [                        // this product comes from `cart_products` table
   id = 1
   observation = 'text text text'
   product = {                        // this product comes from `products` table
    image: 'url'
    name: 'Cheese'
    price: 2.0
   }
  ]
}

or

cart = {
  products = [
    {                       // this product comes from `cart_products` table
      id = 1
      observation = 'text text text'
      image: 'url'                       // this property comes from `products` table
      name: 'Cheese'                     // this property comes from `products` table
      price: 2.0                         // this property comes from `products` table
    }
  ]
}

Using the idea of Ubiquitous Language, it seems like the second fits better, but I don't know it that's correct (or, at least, makes more sense)

4
  • How is your proposed data structure going to be used, and which part of the application will this data structure be used in? If this is the result of a REST API call, then you can structure it however you want based on the abstraction provided by the HTTP "resource." Sep 13, 2023 at 15:46
  • Why not send a cart_product array for the particular cart instead? Sep 13, 2023 at 16:17
  • @GregBurghardt, this object is part of a Vue component: Cart.vue. Inside this component, there is another component: CartItem.vue, which receives as a prop an item inside cart.products. For my use case, it seems like both ideas apply well, but I'd like to know if there's any "better" solution, since the cart product is actually made of a product and additional info from the cart_product table, something like an aggregate. Sep 13, 2023 at 17:12
  • if a cart_product is put back on the shelf, is it still a cart_product? At home, do they become shelf_product when in the cupboard? . Composing products as part of a collection is not cause to change type. Here there is a fatal flaw of corrupting domain design because the data store has a join-table.
    – radarbob
    Sep 17, 2023 at 21:56

2 Answers 2

1

There are multiple ways to structure this, which are independent of Domain Driven Design. The Ubiquitous Language mentioned in DDD guides you in naming things. Within the realm of e-commerce, products, cart and prices are all concepts in that domain. Nothing stands out as incorrect from an outsider's perspective, but my perspective is not the one that counts. Your organization and customer will drive the ubiquitous language.

DDD does not provide guidance on the data structure. For that, consider which part of the application architecture you are operating in. One of your comments mentions this is data used in a View component, which is likely pulled in from a REST API call. The needs of the user interface and the abstraction provided by the REST endpoint are more relevant here.

The choice to decompose the product information from the shopping cart item information is up to you. It should be a balance between ease of implementation on the backend and frontend. If your view has a component to render product details, it might make sense to have a separate object for the product and shopping cart information. If there is no need to reuse view components at this level, the KISS principal can apply: put all of the necessary properties in a single object.

3
  • Got it. Just to be clear, this data doesn't come from a REST API, it comes from a prop passed to the cart; this prop comes from a Laravel Controller. It's not called, but received. And I also have a factory that transforms the prop data I receive into the data I want; that's why I can choose what structure I'll have. Also, because I don't have a product's details, but rather just basic info of the product, I will use the second option. Thanks a lots :) Sep 13, 2023 at 18:13
  • Also, I'll wait to mark your answer as correct because I want to see if any other ideas pop up from different people. Sep 13, 2023 at 18:14
  • Replace "REST API" with "Laravel controller" and my answer still stands. The fact is you are requesting data from the server and rendering it using ViewJS. I would argue that if you are sending a GET request and you are getting data as a response, you are using REST without intending to. Sep 13, 2023 at 20:58
1

Actually, you get to choose. Whatever makes the most sense to you.

This is one of the beauties of properly separated code. You are able to define what your persistence CartProduct (i.e. the table entity) looks like, completely unrelated to what the domain CartProduct looks like. You don't need to consider one when considering the other.

It is perfectly possibly for your domain CartProduct to choose to not explicitly reveal the underlying Product, instead opting to pretend like these are its own properties. This is possible because there is nothing that tells you that your domain model structure somehow "must" stay true to the table structure. Doing so would be a form of tight coupling, which is what you don't want.

Loose coupling gives you the freedom of choice here whether you choose to replicate the same structure in your domain or to create a different structure that better suits your needs in the domain logic.

Your Answer

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

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