top | item 40798740

gRPC: The Bad Parts

228 points| temp_praneshp | 1 year ago |kmcd.dev

223 comments

order

bunderbunder|1 year ago

All good points. But I'd argue that the single worst part of gRPC is the impenetrability of its ecosystem. And I think that, in turn, is born of complexity. The thing is so packed with features and behaviors and temporal coupling and whatnot that it's difficult to produce a compatible third-party implementation. That means that, in effect, the only true gRPC implementation is the one that Google maintains. Which, in turn, means that the only languages with good enough gRPC support to allow betting your business on it are the ones that Google supports.

And a lot of these features arguably have a poor cost/benefit tradeoff for anyone who isn't trying to solve Google problems. Or they introduce painful constraints such as not being consumable from client-side code in the browser.

I keep wishing for an alternative project that only specifies a simpler, more compatible, easier-to-grok subset of gRPC's feature set. There's almost zero overlap between the features that I love about gRPC, and the features that make it difficult to advocate for adopting it at work.

jakjak123|1 year ago

As someone in a very small company, no affiliation with any Google employees, gRPC and protobuf has been a godsend in many, many ways. My only complaint is that protoc is cumbersome af to use, and that is almost solved by buf.build. Except for our most used language, Java.

Protobufs has allowed us to version, build and deliver native language bindings for a multitude of languages and platforms in a tiny team for years now, without a single fault. We have the power to refactor and design our platform and apis in a way that we never had before. We love it.

doctorpangloss|1 year ago

> But I'd argue that the single worst part of gRPC is the impenetrability of its ecosystem

I have had the opposite experience. I visit exactly two repositories on GitHub, which seem to have the vast majority of the functionality I need.

> The thing is so packed with features and behaviors and temporal coupling and whatnot that it's difficult to produce a compatible third-party implementation.

Improbable did. But who cares? Why do we care about compatible third party implementations? The gRPC maintainers merge third party contributions. They care. Everyone should be working on one implementation.

> features arguably have a poor cost/benefit tradeoff for anyone who isn't trying to solve Google problems.

Maybe.

We need less toil, less energy spent reinventing half of Kubernetes and half of gRPC.

PaulHoule|1 year ago

People complain about any system which is more complex and performant than plain ordinary JSON. Remember how Microsoft pushed "Web Services" and introduced AJAX where the last letter was supposed to be XML?

Microsoft could make the case that many many features in Web Services were essential to making them work but people figured out you could just exchange JSON documents in a half-baked way and... it works.

arccy|1 year ago

> I keep wishing for an alternative project that only specifies a simpler, more compatible, easier-to-grok subset of gRPC's feature set. There's almost zero overlap between the features that I love about gRPC, and the features that make it difficult to advocate for adopting it at work.

Perhaps connect: https://connectrpc.com/

neonsunset|1 year ago

It is possible to do quite well, as demonstrated by .NET.

Edit: and, if I remember correctly, gRPC tooling for it is maintained by about 1-3 people that are also responsible for other projects, like System.Text.Json. You don't need numbers to make something that is nice to use, quite often, it makes it more difficult even.

cyberax|1 year ago

I'm surprised the author doesn't mention ConnectRPC: https://connectrpc.com/

It solves ALL the problems of vanilla gRPC, and it even is compatible with the gRPC clients! It grew out of Twirp protocol, which I liked so much I made a C++ implementation: https://github.com/Cyberax/twirp-cpp

But ConnectRPC guys went further, and they built a complete infrastructure for RPC. Including a package manager (buf.build), integration with observability ( https://connectrpc.com/docs/go/observability/ ).

And most importantly, they also provide a library to do rich validation (mandatory fields, field limits, formats, etc): https://buf.build/bufbuild/protovalidate

Oh, and for the unlimited message problem, you really need to use streaming. gRPC supports it, as does ConnectRPC.

sudorandom|1 year ago

Author here: I definitely should have been more explicit for my love of connectrpc, buf, protovalidate, etc. I do mention ConnectRPC but maybe not as loud as I could have. I definitely try to avoid confessing my love for ConnectRPC in every post, but sometimes it's hard not to because they've made such good strategic decisions that just make sense and round out the ecosystem so well.

jscheel|1 year ago

The tooling around gRPC with bazel when using python is so bad it’s almost impossible to work with, which is hilarious considering they both come from Google. Then I had additional problems getting it to work with Ruby. Then I had more problems getting it to work in k8s, because of load balancing with http/2. Combine those issues with a number of other problems I ran into with gRPC, and I ended up just building a small JSON-RPC implementation that fit our needs perfectly.

doctorpangloss|1 year ago

Another point of view is, don't use Bazel. In my experience, Gradle is less of a headache and well supported.

dcow|1 year ago

At Google scale, I’m sure excruciatingly horrible builds are no worry because they’re some other team’s problem. I hope JSON-RPC eats the world.

lalaithion|1 year ago

We use the textproto format extensively at work; it's super nice to be able to define tests of your APIs by using .textpb inputs and golden .textpb outputs. We have so many more tests using this method than if we manually called the APIs by in a programming language for each test case, and I wouldn't want to use JSON for test inputs, since it lacks comments.

jvolkman|1 year ago

If you use intellij, you can annotate your text protos with some header comments and unlock schema validation, completion, etc.

sudorandom|1 year ago

Author here: Sorry that I was so harsh on textproto. You are right that it has some strengths over JSON... I'm actually a fan of JSONC for this reason. It does limit you on tooling... but so does textproto, right?

I think the bigger thing that I'm worried about is that gRPC has so many mandatory features that it can become hard to make a good implementation in new languages. To be honest there are some languages where the gRPC implementation is just not great and I blame the feature bloat... and I think textproto was a good demonstration of that feature bloat to me.

jeffbee|1 year ago

"Adds a build step" is just not a thing you notice in any way if you also use Bazel, which I imagine Google imagines everyone doing. I don't really agree with any of the complaints in this article since they are sort of vague and apparently from the point of view of browsers, whereas I am a backend developer, but I think there is a large universe of things to complain about with gRPC. First and foremost, it seems as though bazel, protobuf C++, and gRPC C++ developers have never spoken to each other and are apparently not aware that it is almost impossible to build and link a gRPC C++ server with bazel. The bazel people have made it impossible to build protobuf with bazel 7 and the protobuf people have made it impossble to use bazel with protobuf 27, while the gRPC people and the rules_proto people are not even in the conversation. The other complaint from the C++ side is that the implementation is now so slow that Go and Java beat it easily, making C++ people look stupid at work.

rstat1|1 year ago

The last time I attempted to use GRPC++ it was pretty hard to build even without the heaping monstrosity that is Bazel.

mattboardman|1 year ago

My biggest complaint with gRPC is proto3 making all nested type fields optional while making primitives always present with default values. gRPC is contract based so it makes no sense to me that you can't require a field. This is especially painful from an ergonomics viewpoint. You have to null check every field with a non primitive type.

dudus|1 year ago

If I remember correctly the initial version allowed required fields but it caused all sorts of problems when trying to migrate protos because a new required fields breaks all consumers almost by definition. So updating protos in isolation becomes tricky.

The problem went away with all optional fields so it was decided the headache wasn't worth it.

tantalor|1 year ago

RPC/proto is for transport.

Required/validation is for application.

jakjak123|1 year ago

It was a little weird at first, but if you just read the 1.5 pages of why protobuf decided to work like this it made perfect sense to me. It will seem over complicated though to web developers who are used to being able to update all their clients at a whim at any moment.

hot_gril|1 year ago

proto3 added support for optional primitives sorta recently. I've always been happy without them personally, but it was enough of a shock for people used to proto2 that it made sense to add them back.

ainar-g|1 year ago

Re. bad tooling. grpcurl[1] is irreplaceable when working with gRPC APIs. It allows you to make requests even if you don't have the .proto around.

[1]: https://github.com/fullstorydev/grpcurl

abdusco|1 year ago

> make requests even if you don't have the .proto around

Like this?

    > grpcurl -d '{"id": 1234, "tags": ["foo","bar"]}' \
        grpc.server.com:443 my.custom.server.Service/Method
How is that even possible? How could grpcurl know how to translate your request to binary?

CommonGuy|1 year ago

One can use Kreya for a GUI version

jakjak123|1 year ago

I just build a cli in Java or Go. It literally takes minutes to build a client.

hamandcheese|1 year ago

I remember being surprised at how hard it was to read the source code for grpc Java. There's an incredible amount of indirection at every turn.

This made it extremely hard to get answers to questions that were undocumented.

It's a shame because I know Google can put out easy to read code (see: the go standard library).

ot|1 year ago

> It's a shame because I know Google can put out easy to read code (see: the go standard library).

My guess is that the difference is that go is managed by a small group of engineers that have strong opinions, really care about it, and they have reached "fuck you level", so they can prioritize what they think is important instead of what would look good on a promo packet.

hinkley|1 year ago

Sass was the first code generator I ever met that produced decent output. I’d been coding for 15 years at that point. Less is the second one.

That’s the end of this story. There are basically two people in the world who have demonstrated that they can be trusted to generate code that isn’t an impenetrable quagmire of pain and confusion.

I doubt it’s an accident that both emitted declarative output rather than imperative, but I would be happy to be proven wrong.

jakjak123|1 year ago

Some of the details inside protobuf in Java can be very convoluted, but they are also the result of intense benchmarking, years of experiences and a long tail with deep legacy support for old java.

Honestly I found the Java bindings to be way better designed and thought out than Golang. On a consumer level, the immutable message builders are fantastic, the one-ofs are decent compared to what Java can offer, and the service bindings actually provide a beautiful abstraction with their 0-1-many model. In Golang, if you only have to deal with Unary rpc they are OK I guess, but I really miss the immutable messages.

cjensen|1 year ago

The generated C++ interfaces to gRPC are also filled with an incredible amount of indirection and unnecessary concepts. I'd say it's a "bad at writing complex things simply" culture rather than being Java-specific.

delusional|1 year ago

I think it's partly a culture thing. Java developers love indirection, and they're used to an ecosystem that doesn't want to be understood. An ecosystem that wants you to google whatever obtuse error message it decides to spit out, and paste whatever half thought out annotation some blog post spits back, into your code to make it work.

I've worked with people who considered anything that wasn't programmed with annotations to be "too advanced" for their use-case.

austin-cheney|1 year ago

Yes, all of it.

Google claims gRPC with protobuf yields a 10-11x performance improvement over HTTP. I am skeptical of those numbers because really it comes down to the frequency of data parsing into and out of the protobuf format.

At any rate just use JSON with WebSockets. Its stupid simple and still 7-8x faster than HTTP with far less administrative overhead than either HTTP or gRPC.

doctorpangloss|1 year ago

> JSON with WebSockets. Its stupid simple and still 7-8x faster than HTTP with far less administrative overhead than either HTTP or gRPC.

Everyone doing what you are saying ends up reinventing parts of gRPC, on top of reinventing parts of RabbitMQ. It isn't ever "stupid simple." There are ways to build the things you need in a tightly coupled and elegant way, but what people want is Next.js, that's the coupling they care about, and it doesn't have a message broker (neither does gRPC), and it isn't a proxy (which introduce a bajillion little problems into WebSockets), and WebSockets lifetimes don't correspond to session lifetimes, so you have to reinvent that too, and...

leetharris|1 year ago

> At any rate just use JSON with WebSockets. Its stupid simple and still 7-8x faster than HTTP with far less administrative overhead than either HTTP or gRPC.

gRPC is not supposed to be a standard web communication layer.

There are times where you need a binary format and extremely fast serialization/deserialization. Video games are one example where binary formats are greatly preferred over JSON.

But I do agree that people keep trying to shove gRPC (or similar) into things where they aren't needed.

perezd|1 year ago

Protobuf can typically be about 70-80% smaller than the equivalent JSON payloads. If you care about Network I/O costs (at a large scale), you'd probably want to realize a benefit in cost savings like that.

Additionally, I think people put a lot of trust into JSON parsers across ecosystems "just working", and I think that's something more people should look into (it's worse than you think): https://seriot.ch/projects/parsing_json.html

dbmikus|1 year ago

To get feature parity, you still need an IDL to generate types/classes for multiple languages. You could use JSON Schema for that.

Websockets do not follow a request/reply semantics, so you'd have to write that yourself. I'd prefer not to write my own RPC protocol on top of websockets. That said, I'm sure there are some off the shelf frameworks out there, but do they have the same cross-language compatibility as protobuf + gRPC? I don't think "just use JSON with websockets" is such a simple suggestion.

Of course, gRPC does have some of its own problems. The in-browser support is not great (non-existent without a compatibility layer?) last time I checked.

kentonv|1 year ago

> Google claims gRPC with protobuf yields a 10-11x performance improvement over HTTP.

That... doesn't make any sense, since gRPC is layered on top of HTTP. There must be missing context here.

jakjak123|1 year ago

I dont even care about the performance. I just want some way to version my messages that is backward and forwards compatible and can be delivered in all the languages we use in production. I have tried to consume json over websockets before and its always a hassle with the evolution of the data format. Just version it in protobuf and push the bytes over websocket if you have a choice. Also, load balancing web socket services can be a bitch. Just rolling out our web socket service would disconnect 500k clients in 60 seconds if we didnt make huge amounts of work.

nevir|1 year ago

> because really it comes down to the frequency of data parsing into and out of the protobuf format.

Protobuf is intentionally designed to NOT require any parsing at all. Data is serialized over the wire (or stored on disk) in the same format/byte order that it is stored in memory

(Yes, that also means that it's not validated at runtime)

Or are you referencing the code we all invariably write before/after protobuf to translate into a more useful format?

jayd16|1 year ago

Its pretty ironic but Microsoft decided to lean into gRPC support for C#/ASP.NET and its honestly really well done and has great devx.

PaulWaldman|1 year ago

Why is this ironic?

bitzun|1 year ago

My main problems with grpc are threefold:

- The implementation quality and practices vary a lot. The python library lacks features that the go library has because they are philosophically opposed to them. Protobuf/grpc version pinning between my dependencies has broken repeatedly for me.

- If you are a services team, your consumers inherit a lot of difficult dependencies. Any normal json api does not do this, with openapi the team can use codegen or not.

- The people who have been most hype to me in person about grpc repeat things like "It's just C structs on the wire" which is completely fucking wrong, or that protobuf is smaller than json which is a more situational benefit. My point being their "opinion" is uninformed and band-wagoning.

This article gave me some new options for dunking on grpc if it's recommended.

pjmlp|1 year ago

I had to chuckle when I read the "Bad Tooling" section, because anyone that has had to deal with COM and DCOM, is painfully aware how much better the development experience with gRPC happens to be, and is incredible how bad the COM/DCOM tooling still is after 30 years, given its key role as Windows API, specially since Vista.

Not even basic syntax highlighting for IDL files in Visual Studio, but nice goodies for doing gRPC are available in Visual Studio.

pjc50|1 year ago

> nice goodies for doing gRPC are available in Visual Studio.

Could you elaborate on this? (Heavy grpc/C# usage here and we just edit the protos)

devmunchies|1 year ago

My biggest issue with GRPC is direct mapping of ip addresses in the config or at runtime. From the docs: "When sending a gRPC request, the client must determine the IP address of the service name." https://grpc.io/docs/guides/custom-name-resolution/

My preferred approach would be to map my client to a "topic" and then any number of servers can subscribe to the topic. Completely decoupled, scaling up is much easier.

My second biggest issue is proto file versioning.

I'm using NATS for cross-service comms and its great. just wish it had a low-level serialization mechanism for more efficient transfer like grpc.

hot_gril|1 year ago

I don't understand why there isn't an HTTP/1 mode for gRPC. Would cover the super common use case of client-to-server calls. Give people who already have your typical JSON-over-HTTP API something that's the same except more efficient and with a nicer API spec.

You know what's ironic, Google AppEngine doesn't support HTTP/2. Actually a lot of platforms don't.

bunderbunder|1 year ago

The streaming message transfer modes are the main thing that make it difficult.

pcj-github|1 year ago

FWIW I never worked at Google and I used protobuf / gRPC extensively at work and in nearly all of my side projects. Personally, I think overall it's great. I do wish trailers were an optional feature though.

epgui|1 year ago

A lot of this kind of criticism rubs me the wrong way, especially complaining about having to use words or maths concepts, or having to learn new things. That's often not really a statement on the inherent virtue of a tool, and more of a statement on the familiarity of the author.

I don't want to sound flippant, but if you don't want to learn new things, don't use new tools :D

usrnm|1 year ago

Sending a request and getting a response back is not a new concept, it's about as old as computer networks in general, and gRPC is the only framework that refers to this concept as "unary". This is the original argument from the article and I tend to agree with it

throwaway894345|1 year ago

> I don't want to sound flippant, but if you don't want to learn new things, don't use new tools :D

That's precisely the problem. The author wants to convince people (e.g., his colleagues) to use a new tool, but he has to convince them to learn a bunch of new things including a bunch of new things that aren't even necessary.

camgunz|1 year ago

IME gRPC is almost never the right balance of tradeoffs. There are (much) better tools for defining web APIs that web apps can actually use without a proxy, JSON encoding/decoding is easy to get to be real fast, and language support varies from great (Go, C++) to hmm (Java, Python). Debugging is painful, extra build steps and toolchains are annoying and flaky, dependencies are annoying, etc etc. 99% of people should probably just be using OpenAPI, and the other 1% should probably just use MessagePack.

neonsunset|1 year ago

A lot of tooling badness comes out of the fact that gRPC integration in its lingua franca, Go, requires manual wiring of protoc.

I don't know why or how there isn't a one-liner option there, because my experience with using gRPC in C# has been vastly better:

    dotnet add package Grpc.Tools // note below
    <Protobuf Include="my_contracs.proto" />
and you have the client and server boilerplate (client - give it url and it's ready for use, server - inherit from base class and implement call handlers as appropriate) - it is all handled behind the scenes by protoc integration that plugs into msbuild, and the end user rarely has to deal with its internals directly unless someone abused definitions in .proto to work as a weird DSL for end to end testing environment and got carried away with namespacing too much (which makes protoc plugins die for most languages so it's not that common of occurrence). The package readme is easy to follow too: https://github.com/grpc/grpc/blob/master/src/csharp/BUILD-IN...

Note: usually you need Grpc.Client and Google.Protobuf too but that's two `dotnet add package`s away.

atombender|1 year ago

The Go tooling for gRPC is inexplicably bad, both in terms of ergonomics and in terms of performance.

The GoGoProtobuf [1] project was started to improve both. It would generate nice Go types that followed Go's conventions. And it uses fast binary serialization without needing to resort to reflection.

Unfortunately, the gRPC/Protobuf team(s) at Google is famously resistant to changes, and was unwilling to work with the GoGo. As a result, the GoGo project is now dead. [2]

I've never used Buf, but it looks like it might fix most of the issues with the Go support.

[1] https://github.com/gogo/protobuf

[2] https://x.com/awalterschulze/status/1584553056100057088

tracker1|1 year ago

Similar experiences with web services via WCF. It was in dealing with anything published that wasn't .Net where it got difficult. PHP services were not complaint with their own WSDL, similar for internal types in Java from some systems. It was often a mess compared to the C# experience, hence everyone moving towards REST or simpler documentation that was easy to one-off as needed, or use an API client.

arccy|1 year ago

One of Go's goals is no arbitrary code execution during during compiles, so it will ~never pull in any code generation tools and run them for you.

kookamamie|1 year ago

Insisting a particularly exotic flavor of HTTP(2) is its most severe design flaw, I think. Especially, as it could have worked in an agnostic manner, e.g. on top WebSockets.

sudorandom|1 year ago

Author here: it's nerdy web trivia but HTTP trailers are actually in the HTTP/1.1 spec, although very few browsers, load balancers, programming languages, etc. implemented it at the time since it wasn't super useful for the web. You are definitely correct that it is an exotic feature that often gets forgotten about.

stairlane|1 year ago

Something I didn’t see listed was the lack of a package manager for protos.

For example if I want to import some common set of structs into my protos, there isn’t a standardized or wide spread way to do this. Historically I have had to resort to either copying the structs over or importing multiple protoc generated modules in my code (not in my protos).

If there was a ‘go get’ or ‘pip install’ equivalent for protos, that would be immensely useful; for me and my colleagues at least.

ergl|1 year ago

It is mentioned under the "Bad tooling" section

tempest_|1 year ago

One of my favourite bits is having to pass a json string to the python library to configure a service. To this day I am not entirely sure it is adhering to the config

slavomirvojacek|1 year ago

I am surprised no-one is mentioning Buf for all the great work they've done with the CLI and Connect for much better devex, tooling, and interoperability.

skywhopper|1 year ago

The worst part of all is that most people don’t need gRPC, but use it anyway. It’s a net addition of complexity and you’re very likely not getting the actual benefits. I’ve seen countless simple REST APIs built with language-native tooling burned to the ground to be replaced with layers of gRPC trash that requires learning multiple new tools and DSLs, is harder to troubleshoot and debug, and ultimately tends to force API rigidity far sooner than is healthy.

One project I worked on was basically just a system for sharing a JSON document to multiple other systems. This was at a golang shop on AWS. We could have used an S3 bucket. But sure, an API might be nice so you can add a custom auth layer or add server side filters and queries down the road. So we built a REST API in a couple of weeks.

But then the tech lead felt bad that we hadn’t used gRPC like the cool kids on other teams. What if we needed a Python client so we could build a Ansible plugin to call the API?? (I mean, Ansible plugins can be in any language; it’s a rest API, Ansible already supports calling that (or you could just use curl); or you could write the necessary Python to call the REST API in like three lines of code.) so we spent months converting to gRPC, except we needed to use the Connect library because it’s cooler, except it turns out it doesn’t support GET calls, and no one else at the company was using it.

By the time we built the entire service, we had spent months, it was impossible to troubleshoot, just calling the API for testing required all sorts of harnesses and mocks, no good CLI tooling, and we were generating a huge Python library to support the Ansible use case, but it turned out that wasn’t going to work for other reasons.

Eventually everyone on that team left the company or moved to other projects. I don’t think anything came of it all but we probably cost the company a million dollars. Go gRPC!

thinkharderdev|1 year ago

> The worst part of all is that most people don’t need gRPC, but use it anyway. It’s a net addition of complexity and you’re very likely not getting the actual benefits. I’ve seen countless simple REST APIs built with language-native tooling burned to the ground to be replaced with layers of gRPC trash that requires learning multiple new tools and DSLs, is harder to troubleshoot and debug, and ultimately tends to force API rigidity far sooner than is healthy.

This sounds odd to me because I don't really see how gRPC would cause any of those issues?

> layers of gRPC trash

What layers? Switching from REST (presumably JSON over http) to gRPC shouldn't introduce any new "layers". It's replacing one style of API call with a different one.

> learning multiple new tools and DSLs

New tools sure, you need protoc or buf to build the bindings from the IDL, but what is the new DSL you need to learn?

> ultimately tends to force API rigidity far sooner than is healthy

How does gRPC force API rigidity? It is specifically designed to be evolvable (sometimes to its usability detriment IMO)

There are some definite footguns with gRPC and I am becoming increasingly annoyed with Protobuf in particular as the years go on, but going back to REST APIs still seems like a huge step backwards to me. With gRPC you get a workflow that starts with a well-defined interface and all the language bindings client/server stubs are generated from that with almost zero effort. You can kind of/sort of do that with REST APIs using openapi specs but in my experience it just doesn't work that well and language support is sorely lacking.

DandyDev|1 year ago

People use it - like I do - because they like the improved type safety compared to REST. We use gRPC at $dayjob and I would hate going back to the stringly typed mess that is JSON over REST or the _really_ absurdly over engineered complexity trap that is GraphQL. gRPC lets us build type safe, self-documented internal APIs easily and with tooling like Buf, most of the pain is hidden.

The DSL I consider a plus. If you build REST APIs you will usually also resort to using a DSL to define your APIs, at least if you want to easily generate clients. But in this case the DSL is OpenAPI, which is an error prone mess of YAML or JSON specifications.

PaulWaldman|1 year ago

This anecdote highlights scope creep and mismanagement, not a fault of gRPC.

cletus|1 year ago

Story time: the whole development of protobuf was... a mess. It was developed and used internally at Google long before it was ever open sourced.

Protobuf was designed first and foremost for C++. This makes sense. All of Google's core services are in C++. Yes there's Java (and now Go and to some extent Python). I know. But protobuf was and is a C++-first framework. It's why you have features like arena allocation [1].

Internally there was protobuf v1. I don't know a lot about this because it was mostly gone by the time I started at Google. protobuf v2 was (and, I imagine, still is) the dominant form of.

Now, this isn't to be confused with the API version, which is a completely different thing. You would specify this in BUILD files and it was a complete nightmare because it largely wasn't interchangeable. The big difference is with java_api_version = 1 or 2. Java API v1 was built like the java.util.Date class. Mutable objects with setters and getters. v2 changed this to the builder pattern.

At the time (this may have changed) you couldn't build the artifacts for both API versions and you'd often want to reuse key protobuf definitions that other people owned so you ended up having to use v1 API because some deep protobuf hadn't been migrated (and probably never would be). It got worse because sometimes you'd have one dependency on v1 and another on v2 so you ended up just using bytes fields because that's all you could do. This part was a total mess.

What you know as gRPC was really protobuf v3 and it was designed largely for Cloud (IIRC). It's been some years so again, this may have changed, but there was never any intent to migrate protobuf v2 to v3. There was no clear path to do that. So any protobuf v3 usage in Google was really just for external use.

I explain this because gRPC fails the dogfood test. It's lacking things because Google internally doesn't use it.

So why was this done? I don't know the specifics but I believe it came down to licensing. While protobuf v2 was open sourced the RPC component (internally called "Stubby") never was. I believe it was a licensing issue with some dependency but it's been awhile and honestly I never looked into the specifics. I just remember hearing that it couldn't be done.

So when you read about things like poor JSON support (per this article), it starts to make sense. Google doesn't internally use JSON as a transport format. Protobuf is, first and foremost, a wire format for C++-cetnric APIs (in Stubby). Yes, it was used in storage too (eg Bigtable).

Protobuf in Javascriipt was a particularly horrendous Frankenstein. Obviously Javascript doesn't support binary formats like protobuf. You have to use JSON. And the JSON bridges to protobuf were all uniquely awful for different reasons. My "favorite" was pblite, which used a JSON array indexed by the protobuf tag number. With large protobufs with a lot of optional fields you ended up with messages like:

    [null,null,null,null,...(700 more nulls)...,null,{/*my message*/}]
GWT (for Java) couldn't compile Java API protobufs for various reasons so had to use a variant as well. It was just a mess. All for "consistency" of using the same message format everywhere.

[1]: https://protobuf.dev/reference/cpp/arenas/

mike_hearn|1 year ago

There was never any licensing issue, do you think Google would depend on third party software for anything as core as the RPC system? The issue was simply that at the time, there was a culture in which "open sourcing" things was being used as an excuse to rewrite them. The official excuse was that everything depended on everything else, but that wasn't really the case. Open sourcing Stubby could certainly have been done. You just open source the dependencies too, refactor to make some optional if you really need to. But rewriting things is fun, yes? Nobody in management cared enough to push back on this, and at some point it became just the way things were done.

So, protobuf1 which was perfectly serviceable wasn't open sourced, it was rewritten into proto2. In that case migration did happen, and some fundamental improvements were made (e.g. proto1 didn't differentiate between byte arrays and strings), but as you say, migration was extremely tough and many aspects were arguably not improvements at all. Java codebases drastically over-use the builder/immutable object pattern IMO.

And then Stubby wasn't open sourced, it was rewritten as gRPC which is "Stubby inspired" but without the really good parts that made Stubby awesome, IMO. gRPC is a shadow of its parent so no surprise no migration ever happened.

And then Borg wasn't open sourced, it was rewritten as Kubernetes which is "Borg inspired" but without the really good part that make Borg awesome, IMO. Etc.

There's definitely a theme there. I think only Blaze/Bazel is core infrastructure in which the open source version is actually genuinely the same codebase. I guess there must be others, just not coming to mind right now.

Using the same format everywhere was definitely a good idea though. Maybe the JS implementations weren't great, but the consistency of the infrastructure and feature set of Stubby was a huge help to me back in the days when I was an SRE being on-call for a wide range of services. Stubby servers/clients are still the most insanely debuggable and runnable system I ever came across, by far, and my experience is now a decade out of date so goodness knows what it must be like these days. At one point I was able to end a multi-day logs service outage, just using the built-in diagnostics and introspection tools that every Google service came with by default.

mdhb|1 year ago

I think there is a really nice opportunity to take some emerging open source standards such as CBOR for the wire format, CDDL for the schema definition and code generation inputs and WebTransport for the actual transport layer.

tgma|1 year ago

gRPC is deliberately designed not to be dependent on protobuf for its message format. It can be used to transfer other serialization formats. However, the canonical stub generator, which is not hard to replace at all, assumes proto so when people hear gRPC they really think of Protobuf over gRPC. Most of the complaints should be directed at protobuf, with or without gRPC.

The primary misfeature of gRPC itself, irrespective of protobuf, is relying on trailers for status code, which hindered its adoption in the context of web browser without an edge proxy that could translate gRPC and gRPC-web wire formats. That alone IMO hindered the universal applicability and adoption quite a bit.

bootloop|1 year ago

Do you know of an example where this is done? I didn't know that and we are currently using a customized wire format (based on a patched Thrift), so I thought gRPC wouldn't be an option for us.

jakjak123|1 year ago

This is the true design issue with gRPC as I see it. It would be way bigger without this. I love protobuf though, gRPC is just alright. At least gRPC makes it so much simpler to build powerful automation and tooling around it than the wild west of randomly created 'json'-ish REST-ish APIs.

FridgeSeal|1 year ago

> Why does gRPC have to use such a non-standard term for this that only mathematicians have an intuitive understanding of? I have to explain the term every time I use it.

Who are you working with lol? Nobody I’ve worked with has struggled with this concept, and I’ve worked with a range of devs, including very junior and non-native-English speakers.

> Also, it doesn’t pass my “send a friend a cURL example” test for any web API.

Well yeah. It’s not really intended for that use-case?

> The reliance on HTTP/2 initially limited gRPC’s reach, as not all platforms and browsers fully supported it

Again, not the intended use-case. Where does this web-browsers-are-the-be-all-and-of-tech attitude come from? Not everything needs to be based around browser support. I do agree on http/3 support lacking though.

> lack of a standardized JSON mapping

Because JSON has an extremely anaemic set of types that either fail to encode the same semantics, or require all sorts of extra verbosity to encode. I have the opposite experience with protobuf: I know the schema, so I know what I expect to get valid data, I don’t need to rely on “look at the json to see if I got the field capitalisation right”.

> It has made gRPC less accessible for developers accustomed to JSON-based APIs

Because god forbid they ever had to learn anything new right? Nope, better for the rest of us to just constantly bend over backwards to support the darlings who “only know json” and apparently can’t learn anything else, ever.

> Only google would think not solving dependency management is the solution to dependency management

Extremely good point. Will definitely be looking at Buf the next time I touch GRPC things.

GRPC is a lower-overhead, binary rpc for server-to-server or client-server use cases that want better performance and faster integration that a shared schema/IDL permits. Being able to drop in some proto files and automatically have a package with the methods available and not having to spend time wiring up url’s and writing types and parsing logic is amazing. Sorry it’s not a good fit for serving your webpage, criticising it for not being good at web stuff is like blaming a tank for not winning street races.

GRPC isn’t without its issues and shortcomings- I’d like to see better enums and a stronger type system, and defs http/3 or raw quic transport.

lanstin|1 year ago

I use protobuf to specify my protocol and then generate a swagger/openAPI spec then use some swagger codegen to generate rest client libraries. For a proxy server I have to fill in some stub methods to parse the json and turn it into a gRPC call but for the gRPC server there is some library that generates a rest service listener that just calls into the gRPC server code. It works fine. I had to annotate the proto file to say what REST path to use.

SrslyJosh|1 year ago

>> Also, it doesn’t pass my “send a friend a cURL example” test for any web API.

> Well yeah. It’s not really intended for that use-case?

Until $WORKPLACE is invaded by Xooglers who want to gRPC all the things, regardless of whether or not there's any benefit over just using HTTPS. Internal service with dozens of users in a good week? Better use gRPC!

sudorandom|1 year ago

Hey, author here:

> Why does gRPC have to use such a non-standard term for this that only mathematicians have an intuitive understanding of? I have to explain the term every time I use it.

>> Who are you working with lol? Nobody I’ve worked with has struggled with this concept, and I’ve worked with a range of devs, including very junior and non-native-English speakers.

This is just a small complaint. It's super easy to explain what unary means but it's often infinitely easier to use a standard industry term and not explain anything.

>> Also, it doesn’t pass my “send a friend a cURL example” test for any web API.

> Well yeah. It’s not really intended for that use-case?

Yeah, I agree. Being easy to use isn't the indented use-case for gRPC.

>> The reliance on HTTP/2 initially limited gRPC’s reach, as not all platforms and browsers fully supported it

> Again, not the intended use-case. Where does this web-browsers-are-the-be-all-and-of-tech attitude come from? Not everything needs to be based around browser support. I do agree on http/3 support lacking though.

I did say browsers here but the "platform" I am thinking of right now is actually Unity, since I do work in the game industry. Unity doesn't have support for HTTP/2. It seems that I have different experiences than you, but I still think this point is valid. gRPC didn't need to be completely broken on HTTP/1.1.

>> lack of a standardized JSON mapping

> Because JSON has an extremely anaemic set of types that either fail to encode the same semantics, or require all sorts of extra verbosity to encode. I have the opposite experience with protobuf: I know the schema, so I know what I expect to get valid data, I don’t need to rely on “look at the json to see if I got the field capitalisation right”.

I agree that it's much easier to stick to protobuf once you're completely bought-in but not every project is greenfield. Before a well-defined JSON mapping and tooling that adhered to it is is very hard to transition from JSON to protobuf. Now it's a lot easier.

>> It has made gRPC less accessible for developers accustomed to JSON-based APIs

> Because god forbid they ever had to learn anything new right? Nope, better for the rest of us to just constantly bend over backwards to support the darlings who “only know json” and apparently can’t learn anything else, ever.

No comment. I think we just have different approaches to teaching.

>> Only google would think not solving dependency management is the solution to dependency management

> Extremely good point. Will definitely be looking at Buf the next time I touch GRPC things.

I'm glad to hear it! I've had nothing but execellent experiences with buf tooling and their employees.

> GRPC is a lower-overhead, binary rpc for server-to-server or client-server use cases that want better performance and faster integration that a shared schema/IDL permits. Being able to drop in some proto files and automatically have a package with the methods available and not having to spend time wiring up url’s and writing types and parsing logic is amazing. Sorry it’s not a good fit for serving your webpage, criticising it for not being good at web stuff is like blaming a tank for not winning street races.

Without looping in the frontend (aka web) it makes the contract-based philosophy of gRPC much less compelling. Because without that, you would have to have a completely different language for contracts between service-to-service (protobuf) than frontend to service (maybe OpenAPI). For the record: I very much prefer protobufs for the "contract source of truth" to OpenAPI. gRPC-Web exists because people wanted to make this work but they built their street racer with some tank parts.

> GRPC isn’t without its issues and shortcomings- I’d like to see better enums and a stronger type system, and defs http/3 or raw quic transport.

Totally agree!

cherryteastain|1 year ago

For me, the breaking point was when I saw the C++ bindings unironically recommend [1] that you use terrible anti-patterns such as "delete this". I find it unlikely that all these incredibly well paid Google engineers are unaware how people avoid these anti-patterns in idiomatic C++ (by e.g. std::shared_ptr). The only remaining sensible explanation is that Google internal gRPC C++ tooling must have utilities that abstract away this ugly underbelly, which us mere mortals are not privy to.

[1] https://grpc.io/docs/languages/cpp/callback/

athorax|1 year ago

I do generally agree the tooling sucks, but as mentioned, buf and the connectrpc ecosystem have made it much easier to get things going.

cryptonector|1 year ago

> Bad tooling

Lolwut. This is what was always said about ASN.1 and the reason that this wheel has to be reinvented periodically.

throwaway894345|1 year ago

It can be true for both ASN.1 and gRPC? Moreover, definitions of "bad" can vary.

_zoltan_|1 year ago

in my latest project I actually needed an rpc library that was hardware accelerated and I was surprised gRPC doesn't do RDMA for example. why is that?