modular-monolith-laravel icon indicating copy to clipboard operation
modular-monolith-laravel copied to clipboard

[Question] Contracts

Open robsontenorio opened this issue 2 years ago • 11 comments

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 ?

robsontenorio avatar Feb 10 '22 13:02 robsontenorio

@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.

avosalmon avatar Feb 11 '22 05:02 avosalmon

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?

ashourms avatar Feb 11 '22 18:02 ashourms

@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.

avosalmon avatar Feb 12 '22 07:02 avosalmon

Noted! Thanks for your feedback!

ashourms avatar Feb 12 '22 08:02 ashourms

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 avatar Feb 19 '24 12:02 inkomomutane

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)

robsontenorio avatar Feb 19 '24 13:02 robsontenorio

@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?

inkomomutane avatar Feb 19 '24 13:02 inkomomutane

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

robsontenorio avatar Feb 19 '24 14:02 robsontenorio

Thanks

inkomomutane avatar Feb 19 '24 18:02 inkomomutane

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.

avosalmon avatar Feb 20 '24 05:02 avosalmon

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.

inkomomutane avatar Feb 20 '24 06:02 inkomomutane