I'm on a small team working with microservices. I have different complaints than yours. The main issue I run into with microservices is I lose the benefit of my Go compiler. I don't like in dynamic languages because of all the runtime errors I run into. With microservices, even using a statically typed language becomes a nightmare of runtime errors.
If I change the type on a struct that i'm marshaling and unmarshaling between services, I can break my whole pipeline if I forget to update the type on each microservice. This feels like something that should be easy to catch with a compiler.
If your services need a shared, implicit understanding of types, you're not respecting the microservice boundaries. Each microservice needs to offer a contract describing what inputs it accepts and immediately reject a request that doesn't meet that contract. Then type mismatches becomes very obvious during development when you start getting 400s when testing against the DEV endpoint. Don't pass around opaque structs.
If you use code gen like gRPC or thrift, it is easy for a compiler to catch. Even if you're using microservices with a shared DTO library, its easy for the compiler to catch.
If I change the type on a struct that i'm marshaling and unmarshaling between services, I can break my whole pipeline if I forget to update the type on each microservice. This feels like something that should be easy to catch with a compiler.