4 ms·
Another answer: > Imagine I want to fetch user data by id from Galactus, the user data service. I know what shape of data I want from it, and Galactus knows wh
by Misdicorl 3y ago
Another answer:
> Imagine I want to fetch user data by id from Galactus, the user data service. I know what shape of data I want from it, and Galactus knows what shape of data it provides. Should both my service and Galactus have full, individual copies of this data structure?
No. Galactus should have the full shape of the "user object" but should never put that on the wire or expose it. The wire API should expose sensible things like "what is the billing and shipping address(es) of this user id". Galactus is responsible for maintaining the mapping between the "user object" and whatever the relevant return format is for those data.
Edit: This allows you to run API migrations and data migrations independently. Which is crucial for any service that will last longer than 1 year.
- mjr00 3y agoAgreed with all of this. I consider the API structure (which might be defined by protobuf/Avro/Thrift/etc) to be separate from anything that is used by either the server or client services. The API structure is the only thing that should be shared. When you start out, it will feel very repetitive because your client object structure matches your API structure matches your server object structure. You might even think "DRY!" and want to combine these, but IMO, resist the temptation. You will eventually have a case where these need to evolve independently. For the Galactus case, imagine that for compliance (or whatever) reason, you need to start soft-deleting users, and you do that via the simple case of an `IsDeleted` flag on the User table. You'll need that flag on the User object on the Galactus side, but you don't want to add this to the API and expose it to clients. > Edit: This allows you to run API migrations and data migrations independently. Which is crucial for any service that will last longer than 1 year. Totally agreed here too.
- bcrosby95 3y agoIs it normal for people to just splat their database across the wire? Because that seems pretty terrible. We wrap every API response in a DTO and are deliberate about picking and choosing which fields we want to expose. Anything else sounds like a recipe for bad times.
- mjr00 3y agoI think it is both an awful idea and very common. In the early stages your database looks very similar (if not identical) to what you want your API to look like, so it's very tempting to reduce boilerplate by having your API and database objects use the same data structures internally.
- jdkoeck 3y agoYep, it’s a terrible idea but that’s exactly what frameworks like Rais push you to do.
- charlierguo 3y ago> This allows you to run API migrations and data migrations independently. Which is crucial for any service that will last longer than 1 year. I've felt nervous for years about going all-in with Django Rest Framework, and you've articulated exactly why.
- trashburger 3y agoWe use it at work. We always define the exact fields we want, and can swap them for SerializerMethodFields if we need to do something different/funky. It works very well, imo.
- kdazzle 3y agoYeah, I wish every language had something as nice as DRF. I’ve never had issues with it for a few different multi-year codebases.
- Scarblac 3y agoYes, but that's not his point. Obviously Galactus has some internal user data structure that is private to it. But there's also something going over the wire, as a response from Galactus' API, and consumed by one of more other services. His question was, shouldn't the knowledge of the structure of that be in some type of shared code?
- dvd23 3y agoIMO if that structure is autogenerated from the API specs (like protobuf, OpenAPI, ...), it's not needed to share it. Plus you can make it evolve at the pace of each service, if your API keeps backwards compatibility.