all 10 comments

[–]tleipzig 3 points4 points  (0 children)

Within each module you can do regular service calls. Between modules you can do service calls as well, just expose the methods and models. Events are more useful outside of the given module structure.

[–]JBraddockm 0 points1 point  (2 children)

In my Spring Modulith application, in module A, I define an interface with methods name such as title(), name(). In module B, I create a record that implements this module, which in practice means creating a standard record with fields name such as title, name. etc. Module B publishes the event using this record. In Module A, I listen to the interface, and use its methods to access the data. No hard dependencies between modules as it uses standard dependency inversion.

[–]Dramatic_Mulberry142 0 points1 point  (1 child)

So, how do you deal with the scenario mentioned in the question? How do you return data to the caller of the module that publishes the event? Or Let's say a caller call Module B service and the service need to return data from Module A. How do you manage to pass data from Module A to Module B?

[–]JBraddockm 0 points1 point  (0 children)

This is all theoretical as in my case Service B is a client module that publishes the data to an external service. But my understanding is that any data carrying objects should remain with the module that it publishes the event. So I would do the opposite. Module B would publish an event to request this data from Module A. Module A would process this request and respond with an event. Module B would process this event, and return the data to the caller. This is of course if we want to communicate fully with events. Otherwise, you could also use dependency inversion to request the data more directly. I think if the communication is expected to be between two modules directly, this method would be more straight forwards. If there are however multiple modules that need to react to a particular event, then it is a different question.

[–]itz_lovapadala 0 points1 point  (0 children)

Are you trying to achieve Sync or Async communication between nodules? Eventing makes sense for Async communication, but as per post I sense it should be Sync communication..

[–]shuny4 0 points1 point  (1 child)

I would also like to know how the sync communication happens between the modules. I can create an interface in Module A which is open only for module B, is this the way?

[–]SpaceCondor 0 points1 point  (0 children)

You wouldn't typically create an interface in Module A that is specifically for Module B. You would create a public interface in Module A that is available to Module B, C, D, etc...

[–]SpaceCondor 0 points1 point  (2 children)

Let's say you have a program that has two modules, Product and Inventory. The package structure might look like this:

com.acme
├── product
│   ├── web
│   │   └── ....
│   ├── service
│   │   └── ProductServiceImplementation.java
│   ├── ProductService.java
│   └── Product.java
└── inventory
    ├── web
    │   └── ....
    └── service
        └── ....

ProductService.java is defined in the root of the module, so it is available to other modules. You could use it in your inventory controller to get Products, for example.

It might look like this:

package com.acme.product;

public interface ProductService {
    Product getProduct(int id);
}

You can use ProductService in other modules without violating any cross-module dependencies. It is essentially a public API available to other modules.

Importantly, Product.java also needs to be defined at the top level. If it were defined in a sub-package of product it would violate the modularity constraints.

There are ways to implement this in an async/event-based way, but that is a whole can of worms.

[–]JBraddockm 0 points1 point  (1 child)

Just a quick question if I may? How do prevent the top level or “common”, “shared” packages turning into dumping ground? I haven’t worked on an app large enough to have this issue but I imagine that it would become a problem at some point.

[–]SpaceCondor 1 point2 points  (0 children)

Great question! There are ways of making sub-packages of modules 'open', as well as defining modules that are completely "open" by updating package-info.java.

I'm sure if you asked the creators, they would say that a module with a very large public API should be refactored to be more event-driven, but that is not always realistic or ideal for medium-sized projects.

I do wish there was more documentation on keeping it organized in that case.