IMO the serializers should be their own standalone classes/modules which live separately from your application’s core types. You can invoke them when you need to do the serialization and keep parallel versions of them for legacy clients, etc.
ActiveModel::Serializers work like this in Rails, although I haven’t tried any similar approaches in statically-typed languages where protobuf is so commonly used.
For Python there's Marshmallow (https://github.com/marshmallow-code/marshmallow) and Django REST Framework if you're using Django (http://www.django-rest-framework.org/api-guide/serializers/). Both of these work as you described.
Re:When Not to Serialize
by SamReidHughes on Saturday August 11, 2018 @10:14PM
(#17742590)
Serializers are just functions. Why do they need to be classes?
I think this is the right way to do it. Just like how UTF-8 to a string type is kept at the borders. Inevitably, someone comes along with a requirement that implies the first iteration of the data modeling was not only wrong, but backwards-incompatibly wrong.
It's hard to convince coworkers that it isn't code duplication though.
> Protobuf is a foot-gun here because it blends these roles in a way that's hard to get away from.
I'm not sure; in many ways it is just trying to give you a way to supply it the data to serialize with those models. I'd be nice to not have the "foot gun", but I'm not sure what such a serialization framework would look like.