Since Java is a statically typed language, both sides need to have the
exact same model
if you get data from a service, change a property, then post it back
to the service, you will lose data if your model was missing a
property since Jackson will have silently ignored the missing property
in the deserialization process.
Because we usually bind the service data model to DTOs. That's it.
Recently, I have started to play with Tolerant Readers instead of data bindings. 1
Not a silver-bullet of course, but the goal here is to shrink the coupling surface to the minimum.2
Because they need to have a dependency on the exact same version of
the domain model, the services have to be built (whenever the model
changes just a bit) and deployed together, making the architecture
look more like a distributed monolith.
Few things here.
Assume that there is going to be coupling. Allways. Somewhere. Don't look for the coupling zero because it doesn't exist. Our battle against coupling is reduced to: looking for the right place and keeping it as loosely as possible.
In the line with these arguments, we have to find out how much coupling/decoupling are we willing to afford.
At this point don't be dogmatic, be pragmatic, because we are not managing an architecture of the scale of Amazon or Netflix. Neither our needs for decoupling are the same.
Sharing data models
Shared data models are the root of the evil. Ideally, we only map/bind/read the essential and we will never allow our bindings to go beyond the anti-corruption layer. In other words, if our DTOs are reaching upper layers, the problem is not Java. The problem is the lack on abstraction layers.
It's utterly important to keep domain data models unaware one another. This's the key of the bounded contexts and the SRP they represent.
This is why some API providers do versioning. For a while, the old version coexist with the new one and consumers are encouraged to shift progressively from one to another.
Ultimatelly, we are speaking about Microservices here, we should be able to deploy as many as we need and as many versions as we deem appropiate. Any time.
If we can't, we are right saying that ...
the architecture looks more like a distributed monolith.
1: Not totally I have to say. I still bind messages to DTOs but only those I consider unlikely to change or relatively small.
2: Take in account that every new DTO we map contributes to more coupling. Let's say that DTOs increase the coupling surface.