avosalmon / modular-monolith-laravel

Sample application for Laracon Online 2022.
https://youtu.be/0Rq-yHAwYjQ?t=4070
168 stars 36 forks source link

[Question] Contracts #3

Open robsontenorio opened 2 years ago

robsontenorio commented 2 years ago

Nice speak and thanks for sharing!

I got the idea about contracts between modules. But consider this scenario:

The Order module has a OrderLine product_id FK for Inventory and it is great interface usage on your example.

But, by “Laravel way”, to display an OrderLine with product names I would make OrderLine::with(“product”)->….

It would be a violation ? How do you deal with that ?

avosalmon commented 2 years ago

@robsontenorio Thanks for watching my talk! I think it's considered a violation since the OrderLine directly accesses the Product model which would expose all the properties and functionalities of the Product model. By accessing the Product model, the order module would be able to trigger whatever actions against the products table. e.g. update, delete Also, when you test the order module, you won't be able to create a record for the order_lines table without creating a product. However, you shouldn't need to know the details of database tables of the inventory module when you are testing the order module so that the order module can be tested independently.

To deal with this, I would create a contract (i.e. interface) in the inventory module and the order module can get the product by calling the method. This will cause an additional DB query but we can keep the modules decoupled.

ashourms commented 2 years ago

I really enjoyed your awesome talk during the conference! well done!

I am wondering about the same thing, what if we have a model that is having relationships with many other models in different modules. When using Laravel eager loading "i.e. with method" you will get one collection that have all the related properties of other models.

So using the explained approach in your presentation, does this mean that we need to create a contract in each related module and get the related model information using those services?

avosalmon commented 2 years ago

@ashourms Thank you for watching the talk!

Basically, a model shouldn't have relationships with models of different modules. If a module needs to get data from different modules, we need to create a contract and get the required data using the contracts (i.e. interfaces). The contract should return a DTO instead of a related eloquent model to avoid exposing all the properties and methods to different modules. Alternatively, a module can dispatch an event and other modules handle it accordingly, which is a more decoupled approach.

If a module needs to get many different data from other modules, you might want to see if there is a better way to define your domain boundaries.

ashourms commented 2 years ago

Noted! Thanks for your feedback!

inkomomutane commented 8 months ago

Hi @avosalmon i liked you talk on laracononline of 2year ago. And i face the same problem, i have a Item model in Inventory model that has relation with Account Model (using sales_account_id) in General-Ledger modules.

How can i design the relationship in database of this tables in correct way for modules? Or the database level isn't must relevant at this point, the modularization is on application level Thanks.

robsontenorio commented 8 months ago

TLDR: you will have additional DB query for each line you want to fetch , just like N+1

According its approach models can’t have relationships outside its module.

foreach orderline as line line->product = ProductService::fetch(line->product_id)

inkomomutane commented 8 months ago

@robsontenorio

TLDR: you will have additional DB query for each line you want to fetch , just like N+1

According its approach models can’t have relationships outside its module.

foreach orderline as line line->product = ProductService::fetch(line->product_id)

But should the db structure change?

robsontenorio commented 8 months ago

DB structure is the same. The change is about the fetch N+1 thing.

inkomomutane commented 8 months ago

Thanks

avosalmon commented 8 months ago

Hi @avosalmon i liked you talk on laracononline of 2year ago. And i face the same problem, i have a Item model in Inventory model that has relation with Account Model (using sales_account_id) in General-Ledger modules.

How can i design the relationship in database of this tables in correct way for modules? Or the database level isn't must relevant at this point, the modularization is on application level Thanks.

@inkomomutane Can I have more context about your modules? What kind of interactions would happen between the modules? The solution depends on the problem you are facing.

inkomomutane commented 8 months ago

Hi @avosalmon i liked you talk on laracononline of 2year ago. And i face the same problem, i have a Item model in Inventory model that has relation with Account Model (using sales_account_id) in General-Ledger modules. How can i design the relationship in database of this tables in correct way for modules? Or the database level isn't must relevant at this point, the modularization is on application level Thanks.

@inkomomutane Can I have more context about your modules? What kind of interactions would happen between the modules? The solution depends on the problem you are facing.

Yap.

I have 2 modules Inventory where are managed all items of purchasing, sales, etc... and every item have transactions account, like sales account, purchasing account like this

+---------------------------------+ | items | +---------------------------------+ | purchase_account_id | | sale_account_id | ....

+-------------------------------+ | accounts | +-------------------------------+ | id ....

But the accounts are managed on General Ledger Module And Items in Inventory module am looking for best approach to design the database schema for that case. Because in your point of view model classes of one module should not have relationships with another outside of.