1

I have DTO and DOMAIN models:

@Data
public class CarDomain {
    private String name;
    private int year;
    private String color;
}

and

@Data
public class CarDto {
    private String name;
    private int year;
    private String color;
}

I have 3 microservices(MS) communicate with each other through RabbitMq. And I have models module with all DTO classes. Each MS include models module in maven.

1 MS send carDto 2 MS recive CarDto and convert to Domain. For this I can use Several variants:

  1. use library for example mapstruct:
@Mapper
public interface CarMapper {
    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class );
    CarDto carToCarDto(CarDomain car);
}

and use:

CarDto carDto = CarMapper.INSTANCE.carToCarDto(carDomain);
  1. Create manual mapper:
class CarMapper {
        public static CarDto toDto(CarDomain car) {
            CarDto carDto = new CarDto();
            carDto.setName(car.getName());
            carDto.setYear(car.getYear());
            carDto.setColor(car.getColor());
        }
    }

Now we use 2 variant. Becouse when we build microservice and in models module some field of DTO model change we get error on compile time. For example somebody change name this dto model in models module

private String name; 

to

private String name1;

When we build project we get error on this line:

carDto.setName(car.getName());// getName not found becose now getName1

But this way hard. For each dto/domain models we need create mapper and write each field. In 1 variants it easier but if dto change we get error on runtime.

Tell me the best approach how to match/mapping models dto/domain?

VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
user5620472
  • 2,722
  • 8
  • 44
  • 97
  • Perhaps have a look at this video if you have not already done so: https://www.youtube.com/watch?v=yPvef9R3k-M – Eben Roux Jul 09 '17 at 19:00

2 Answers2

6

Becouse when we build microservice and in models module some field of DTO model change we get error on compile time.

The problem you are facing is generally recognized as message versioning.

A key idea in microservices is that they can be redeployed independently of each other; you should be able to change them at any time without breaking everything else. To achieve this, we limit the coupling between microservices to the messages that they have in common.

As a consequence of this; it follows that it is really important to get the message schemas "right".

Right in this circumstance doesn't mean that you figure out the correct messages to send the first time, but rather than you invest upfront design capital in understanding how messages change, and what message structures support those changes.

The best single reference on the topic I know of is Greg Young's book Versioning in an Event Sourced System.

Greg makes a case for using "weak schemas" to support forward and backwards compatibility; the basic ideas are

  • The meaning of a field never changes
  • The consumer must ignore and must forward fields it doesn't understand
  • Most (all?) fields should be optional; the consumer must be prepared for the event that some data element is missing from the message. That might mean having an acceptable default value prepared, or alternative processing.

With the basics in mind; you can look at the details of Avro, Thrift, Protocol Buffers to get a sense for how the standardized formats tend to evolve. Martin Kleppmann's discussion of Schema Evolution in Avro, Protocol Buffers, and Thrift might be a good intermediate step.

Message discipline is really important -- the schema is part of the API of the microservice. Introducing a backwards incompatible change to the API introduces a lot of risk, and should not be undertaken lightly.

I have models module with all DTO classes.

That may be an error; it's hard to say. It is certainly an error to have a common core that routinely evolves in a way that isn't backwards compatible. That habit should change.

VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
0

Consider using a Java bean mapper. See any tool for java object to object mapping?

Such mappers are flexible and can bridge minor differences between models without requiring the boilerplate code.

tkruse
  • 10,222
  • 7
  • 53
  • 80