Search code examples
javascopepackagedomain-driven-designmicroservices

Designing java project for monoliths and microservices at same time


I would like to know how you divide project modules in java for monolith with possibility of transforming modules to micro-services later?
My personal naming looks like this:

com.company.shopapp.product
...product.domain (ddd, services, repositories, entities, aggregates, command handlers - everything with package scope)
...product.api (everything with public scope)
...product.controller (CQRS endpoints for commands in web perspective - (package scope))
...product.query(CQRS - package scope)

com.company.shopapp.sales
- domain
- api 
- controller
- query 

What we have here is basically product management context and sales context as packages.

Modules communicate each other using public interfaces (api package) only. In my project I use "..api.ProductFacade" to centralize communication points.

When my "sales" module grow i will turn it into microservice by implementing "..api.ProductFacade" interface as a "rest" or "soap" client and on the other side I will create Endpoint/RestController based on ProductFacade interface. Package "com.company.shopapp.product.api" will be transformed into extended library and added to both projects.

Edit: I can achive this out of the box using @Feign library. https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html#spring-cloud-feign-inheritance

The whole idea feels nice, but maybe you have better way to design project and ensure that breaking it into micro-services will not break whole application.


Solution

  • I think your module structure is good. But I would suggest you create a real 'multi module' project (link). This way, using code from another module will generate a compile-error. This will help you to keep your good intentions!

    In order to do this, you'll have to split each module in a private (implementations) and public (api, only interfaces) module (By doing this, you don't need an 'api'-package). An implementation module can depend on any public-module, but not a private-module.

    If you wire your application together in the private module, with dependency injection, the private modules will have no 'internal' dependencies! The private modules will not have any 'compile-time' dependencies, only 'runtime' dependencies.

    Here quick module dependency graph: enter image description here

    I hope you find this usefull!

    Edit: You will need an extra module only to bootstrap the application!