#Modular design - Decoupling

9 messages · Page 1 of 1 (latest)

tender juniper
#

Hello! I'm looking into designing a modular monolith project. On researching it appears as though its best practice to also try decouple the data layer? I was wondering what other peoples opinions on this were.

I've seen a lot of talk about keeping things modular in the services, modules etc but not a huge amount when it comes to selecting data from the db etc. One post I saw mentioned using schemas or separate databases to split out each modules/service data to keep things decoupled. This might help if there's a future requirement to split out into dedicated microservice projects?

It seems a bit backward to go to lengths on decoupling your domains but share a single db. I've also seen some people decouple the services with event driven stuff over directly calling each service.

I feel like this has probably been reposted in 100 different ways on this discord server D: Sorry if this is a duplicate, I did have a quick search but found nothing related to the terms

Thanks!

#

I think this might go hand in hand with designing services to be less CRUD and more Service oriented, that might also help drive separated database design or at least to a point where you're only sharing high level keys across them

#

Still not 100% sure though! New to this space

rich snow
#

So, I'll try to give you my take on this. There are two types of coupling that can happen with databases.

One, is the simpler coupling to a data source. I say simpler, because this one is more about code than anything else and basically the idea being, you should have your services calling other "data services" and not a particular database. In other words, your database solution is 100% abstracted away from your services, so they have no clue at all what kind of data storage systems are in use. A common pattern for this is the repository pattern.

The other is knowledge about the data and more importantly state of another service. If you have services that know about or can change the state directly in another service's data store, then you have a really bad coupling between the two services. I'm not even sure if there is a name for this. It is also a practice mainly for microservices. You might be able to get away with this working as a small team in a monolith, so it might not be as important. But, if you know you are heading to microservices at some point, trying to follow the "each service has its own data store" rule should be followed. You also noted too how to keep things in sync. Share ids to the data. Another is, share knowledge of state changes across services i.e. you need some type of bus system.

The next and main challenge to such an architecture is when multiple services need to make changes and those changes have to be 100% done for the work to be considered accomplished i.e. transactional. This adds another layer of complexity too (and why doing microservices is so hard).

This is one of the articles I read on the subject: https://microservices.io/patterns/data/database-per-service.html

Good luck! 🙂

tender juniper
# rich snow So, I'll try to give you my take on this. There are two types of coupling that c...

Thanks for the detailed reply, it's really helping me understand the options here. What we're doing at the moment is shifting from CRUD style services to more domain based ones and with that refactoring any duplicate prisma queries across services into a dedicated domain service and using this central point for other services to talk to it rather than having prisma queries that access the same data across many services. I think this is what you spoke about with the "bad coupling between two services".

I think what is making it hard is that we're using a single database with FK's, most of the "isolation" on data access is in our head with no real enforcement from the code.

I want to avoid a spaghetti mess but I also don't want to go down the full microservices route either. I'm thinking perhaps starting with tidying up and isolating services is a start, then moving onto looking at reshaping the database schema and split it where I can see clear domains, then look to implement schema based separation for each domain.

I hope that's sort of on the right tracks

#

Another thing I've noticed is that in Prisma and SQL its super easy to start joining data left and right, I think this starts to cut into what should possibly be access from another service, if all the data lives together. Making it harder to realise the split of data

#

I guess one question would be should I be striving to carve out tables into their own data store or is it okay to just keep it all one big lump (with good code/service modularity)

tender juniper
#
Challenges of a modular monolith

The main challenge of a modular monolith for you might be shared database. Although application layer tends to decompose the modules from one another, database is still shared between all the modules [1]. The constraint you need to have is that: each module is responsible for handling its own data. Like microservices, one module cannot directly call data of another module. This has to be greatly enforced in your application layer for each module.

Module data isolation can be achieved by: same database (might be problematic), same database but different schema (no use of foreign keys), different databases (can be on same server or different), and different database and database types (for e.g. relational for one and Graph for another)[5].
rich snow
#

implement schema based separation for each domain.

My take is simply, make the service(s) work with their own data. If a service needs data from some other place (module), can that data be stored locally to the service too? Or, must the data come from that other service all the time? Then I'd be asking, why and when does it need that data? For instance, if it is always necessary and it is with every call of the service, then that poses the next question, should the two services belong together in the same module? To me, a module in Nest is at the level of a microservice, not the services in the module. It's the module that offers the services within it. The module holds the interfaces. Keep that in mind too, when developing your application.