TL;DR - Is it ok to share a POJO library between services?

Generally we like to keep the sharing between services strictly limited to none if possible. There has been some debate whether or not the service that is sharing data should provide a client-library for clients to use. The client-lib is generally optional for a client of the service to use and can consume the API however they please, whether to use the client-lib, or use an alternative language and use the general aspects of the library and such.

In my case - I am consider a service that create an object of data. Let's assume this object is a PET. It is NOT the database entity, but strictly a POJO that implicitly represents the underlying data. This POJO is what the API has defined. Assume: Pet - Age, Weight, Name, Owner, Address, Species, etc.

Service 1 - PetKeeper: It will generate a pet for whatever reason and retain all of the data and must reference this service to obtain the pet, or make modifications to the Pet, lets say the name changes, or address change must be done through an API call to this service.

Service 2 - PetAccessor: This services gathers the pet's and does validation checks

Service 3,4 - More intermediate service calls

Service 5 - User Inteface

These are very arbitrary but the point is simple. The UI or some user-facing service wishes to present in some way this "PET" object. It must call through an API a service, which calls a service, which calls a service, etc until it reaches the service which gathers the required information and begins the relay back. Finally the UI service has the PET object to display.

This is pretty common - but with our absolute mentality, we duplicated the PET object in every service. DRY (don't repeat yourself) principle only applies to code INSIDE a service and doesn't apply across services but the point is still there. What if we add a field... we must modify 5 services of the POJO in each.

--OR-- We can provide a Pet-Objects-Library which contains some of the pojo's from the API and each service can import/dependency on the library. There is no dependency on the service(s) themselves, but just the general library. I like this idea so that each service has the same type of object and updates are easier. But I'm concerned about God-Objects.

What are the pro's/con's - what's the best design? What have you done to pass data between services to minimize repeating the same POJO classes while also staying de-coupled?

  • God-Object? en.wikipedia.org/wiki/God_object – Dai Kaixian Nov 28 '16 at 7:00
  • @DaiKaixian: Surely you're not suggesting that the OP go with a God object, are you? That's routinely considered an anti-pattern. – Makoto Nov 28 '16 at 7:01
  • I agree with @javaguy 's answer. – Dai Kaixian Nov 28 '16 at 7:08
  • And I also want to say , you can consider visitor-pattern .en.wikipedia.org/wiki/Visitor_pattern . Make all the field and setter/getter in a POJO, and share it between microservices.If you want to do some operation on the POJO in different microservice, write some VisitorClass. – Dai Kaixian Nov 28 '16 at 7:16
  • Thanks. My hesitation with having this 'common library' is that it will grow. And there will be objects in there that only services 1 & 3 care about, or 2 & 4, or all, or any combination there of. A type of general DTO library package that has all DTO's whether I use a vistor pattern or simple DTO POJO or what-not. Is this acceptable to include all these objects but to try to maintain it as best as possible? At least the objects are provided to any who need them IF they wish to use them... – Aerith Nov 28 '16 at 8:12

What's the best design?

You can reuse the same Pet DTO object among the backend services (which process the typical business logic), but when it comes to the presentation tier (User Interface), it is generally a good practice to use a FormBean (a different bean with added fields for presentation logic) so that there will be a clear separation between presentation logic and business logic.

This is required because services should be reusable and a single service can be exposed/reused by multiple/different endpoints (like frontend or could be a different webservice, etc.. ) and each of those endpoints might require additional fields which will be populated by the respective Controllers or layers (like adapters) above the services.

What have you done to pass data between services to minimize repeating the same POJO classes while also staying de-coupled ?

If you use a single bean between business and web tiers then you are tightly coupling the presentation logic with business logic which is not good practice and you will end up changing the services for a requirement in the Frontend (like for example, a different date format to be shown in User Interface). Also, to make this process of populating/copying the data across the beans (like DTO to FormBean or Viceversa), you can use libraries like Apache BeanUtils.copyProperties() or Dozer to avoid the boilerplate code.

| improve this answer | |
  • I agree the presentation layer should probably deserialize the incoming payload as a presentation bean with different attributes as needed. But in general is it ok to reuse the same DTO object(s) in all the backend services? We would generally try to separate out these DTO packages in smaller packages for only the few services that need them. I'm weary of having some junk-drawer of a DTO library package that has DTO's for some 75+ microservices that all services depend on. Unless that's ok since it's just DTO objects that are optional in the first place? – Aerith Nov 28 '16 at 8:13
  • Yes, you can obviously reuse the same DTO object across all same kind of backend services like your PetServices to avoid duplication. But my point is don't tightly couple backend and frontend, that's it. – developer Nov 28 '16 at 8:37

If the DTO represents the same business entity in all the microservices there should be only one class, shared among the services. It's (almost) never correct to have duplicate code for the same object.

| improve this answer | |
  • 3
    Sharing DTOs across microservices is a nightmare. "Does this version has already this field? Hm maybe?" You will end up with a real mess after a while. Duplicated code is good in this case. – Mejmo Oct 25 '18 at 22:21

The way how I plan to do it now, is that each service packages only DTOs and put them into Nexus as jar lib. When other service need those, it will get thos DTO lib(s) as dependency in manve/gradle. If new DTO version is released on one service, its fine as long as old version is also supported at the same time, so don't break backwards compatibility, versioning, etc.. so this is backend-to-backend area. Also to prevent circural dependency you are better to separate service from dto packaging

Now look at backend-to-frontend and vice versa I disagree with previous comments that UI as presentation layer is different. IT IS NOT!!! UI is just another microservice to me which also consumes and produces events.

Backend-to-frontend direction What I do is to convert POJO(dtos) to Typescript interfaces and package into NPM and load them into Nexus as well. UI nodejs based project then consumes and uses those. This is way service to UI.

Frontend-to-backend direction For UI to service layer events I convert Typescript interfaces and convert them to POJOs(dtos), package as jar and upload to Nexus (or some repo) in form of jar to be consumed by backend services.

These processes are easily handled by CI processes (Travis, Gitlab CI, etc.)

Any comments to this approach welcomed.

| improve this answer | |

Not the answer you're looking for? Browse other questions tagged or ask your own question.