This is the written version of my gRPConf 2026 presentation. Thanks to Kevin Nilson and the organizing team for including me!
Hi, welcome and thanks for coming to our session.
For context, these are the presentations that are happening now. We’re in the purple one, and before I start I’d like to make a few comments about two of the others.
First the one below us, the codelab on xDS, is about how gRPC is used in service meshes. As you probably know, service meshes are built by having applications do all of their communication through proxies, and for the last several years the gRPC project has been working to eliminate those proxies by moving their features into the gRPC libraries. A proxyless service mesh sounds like it would cost less to operate. But as we’ll see, that might depend on how we measure cost. Remember that the gRPC project supports many different programming languages, and each of these language implementations needs to be extended to support the proxy features that gRPC needs. This also means that every gRPC application that we write will link in this code, whether we use it or not, and will need to be updated whenever any of this code or its dependencies change.
The session above us on post-quantum cryptography describes one of the reasons that we’ll be regularly updating our gRPC dependencies. The cryptographic algorithms that they use are vulnerable to attacks from quantum computers, so we need to replace them. We think that we have good alternatives, but these new algorithms haven’t had as much scrutiny as the ones that we currently use and they might need some updates over time. That’s creating a lot of work for the gRPC project because the gRPC team has to hook up and maintain these implementations for all of the gRPC libraries, and we gRPC users need to keep updating our applications to use the latest versions of the gRPC libraries. The biggest beneficiary of this is probably GitHub, because we will all be using a lot more minutes of GitHub Actions!
This session is about another way to approach all this. It’s about how we might achieve many of the same goals of gRPC xDS in a way that makes our applications more affordable, maintainable, and secure. When I proposed it, I gave it this title: A lightweight gRPC-compatible implementation for sidecars.
How I learned to stop worrying and love the sidecar.
Another good title is How I learned to stop worrying and love the sidecar.
What if, instead of trying to eliminate sidecars from our service meshes, we embraced them and made them important parts of our application architectures?
What if we leaned into our sidecars and gave them capabilities that we’re tired of building over and over again in our apps and libraries?
What if, instead of using sidecars to build The Matrix, where we normalize our applications so that we can control them, we instead used our sidecars to build Iron Man suits that gave them superpowers?
An Iron Man suit for application superpowers.
For the past year or so, I’ve been building IO. IO is a network proxy that controls and extends Envoy to give my applications superpowers.
IO is a local controller for Envoy. IO runs Envoy as a child process and uses Envoy’s xDS APIs to control its child, and my applications use that child Envoy for all of their networking. They call upstream services through it, their inbound traffic is authenticated and authorized with it, they terminate TLS and manage certificates with it, and sometimes they even proxy raw TCP connections through it. If I run my applications with a container manager like Podman, I can lock them down so that the only traffic in and out of my applications goes through IO’s Envoy, and I can configure my IO to record all of that traffic for debugging and auditing.
I like to say that IO is an Iron Man suit for my applications. It takes the power of Envoy that we’ve used to build service meshes and reframes it around the needs of individual applications to give them superpowers.
You don't put Thor in an Iron Man suit.
IO lets me write simpler applications - I don’t need to put Thor in my Iron Man suit, and in fact, he’s not a good fit for it.
Having all this capability in my proxy means that my applications can be a lot simpler. Just thinking about gRPC, almost everything in the gRPC SDK is unnecessary for my applications. I don’t need Connect either, because if I want to transcode binary protos to JSON, I can just do that in my proxy. Instead I want applications that use the gRPC wire protocol as simply as possible.
So Sidecar, the topic of this session, is a little Go library that I wrote to support the gRPC wire protocol. It builds directly on the Go standard library, which has great HTTP/2 support.
I first used Sidecar to write the gRPC xDS API server that IO uses to control Envoy. But I’ve also found it to be a great way to write other gRPC clients and servers, especially ones that use IO.
Sidecar is a tiny Go library that will make you like your gRPC code better.
Here is some sample code that shows how Sidecar is used.
You can see that it just uses the Go standard library to build servers, so you can easily mix gRPC services with other HTTP endpoints. You might also notice that apart from protobuf serialization, there’s no generated code. Instead Sidecar apps use Go generics to write client and server handlers that are simple and clear.
But rather than going into a lot of detail about it here…
Explore these Sidecar examples.
I’ll instead point you to posts that I’ve written presenting Sidecar and a Sidecar implementation of the Route Guide API.
What is the cost that matters?
Operating cost?
Now let’s talk more about why I’m doing this. There’s a lot of activity in our industry, and we can think of much of it being focused on cost. As we’ve seen, the gRPC project cares a lot about operating cost.
Code generation cost?
Another cost that people are focusing on is the cost of code generation. Coding agents are mainly addressing this.
Complexity is the cost that makes everything harder.
But I think that the cost that we should care most about is complexity. Here John Ousterhout defines complexity as anything related to the structure of our software that makes it hard to understand and modify.
Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system. - John Ousterhout
In A Philosophy of Software Design, Ousterhout describes three ways we experience complexity as software developers:
- Change amplification. A seemingly small change requires code modifications in many different places.
- Cognitive load. How much a developer needs to know to complete a task.
- Unknown unknowns. We don’t know how much work it will takee to do something until we try it.
Complexity will protect you until it kills you.
We can get more perspective on complexity from Mahesh Balakrishnan, who wrote about "three laws" of software complexity and built on things that Fred Brooks and others have written.
First, a well-designed system will degrade into a badly designed system over time. Note that Mahesh says "will" and not "may". It’s not an option, and Fred Brooks agreed. In the Mythical Man Month, Brooks wrote "Program maintenance is an entropy-increasing process, and even its most skillful execution only delays the subsidence of the system into unfixable obsolescence."
Next, complexity is a moat. Complex systems and products are hard to replicate, and this is an advantage for an incumbent. But a moat has two sides. It keeps some people out and some people in. There’s a song that Anais Mitchell wrote and put in the Hadestown musical titled "Why We Build the Wall". In it Hades asks "Why do we build the wall?" and the workers trapped behind it say "we build the wall to keep us free"... "how does the wall keep us free?" "the wall keeps out the enemy"... and "what do we have that the enemy wants?" "We have a wall to work upon. We have work and they have none and our work is never done!" Our walls of complexity might be keeping us employed, but this might not be on things that we should actually be doing.
Finally, Mahesh claims that there’s no fundamental upper limit on software complexity. You might disagree and say "until it kills you" and you might be right. But until then, complex systems can be made more and more complicated as more features and nuances are added.
Count the total cost of gRPC xDS.
So when we think about the effects of xDS on cost, we should think about the total cost and include the effects of the complexity that it adds.
Can you build your software in the programming languages that you want to use?
How many engineers are you employing to make that possible?
How many dependabot alerts are you getting?
How many lines of code are you auditing for vulnerabilities?
How do you know that all of your apps and services are staying up-to-date and configuring their gRPC libraries correctly?
There’s a suggestion in John Ousterhout’s book: "Pull Complexity Downwards". He says that a good way to manage complexity is to put it where as few people as possible need to look at it as infrequently as possible. If we move all this into our proxy, then that’s the only place where we’ll need to write, verify, test, and configure it.
When we move capabilities from the application to the proxy, we only write and test them once.
How many times do you want to write and test all of this?
- Metrics+Logging+Tracing
- Retry
- Service Discovery
- Load Balancers
- Name Resolution
- Deadlines
- Circuit Breakers
- Interceptors
- Compression
How can we make our software safer?
So with IBM, Google, and others building quantum computers to break our crypto and dozens of AI companies building tools to find our vulnerabilities, what can we do to make our software safer?
We can govern our applications' dependencies.
We should be mindful of the dependencies we take.
Consider Rob Pike’s Go Proverb: "a little copying is better than a little dependency."
Then John Ousterhout’s "Pull complexity downwards."
And then after we’ve concentrated all of our networking complexity n our proxy, we might want to simplify that further! Instead of writing the same features in four, five, or eight different languages, maybe our energy is better spent simplifying or replacing Envoy.
We can govern our applications' communication.
We should control what goes in and out of our applications at runtime.
We should be able to see everything, audit everything, and block anything.
If we need secrets to call upstream services, they should never be in our applications and application code should never even have access to them.
Be wary of people talking about "agent identity" – they’re really just talking about this and trying to make it sound like something we should be paying extra to get.
It’s zero trust.
We can prioritize interfaces over implementations.
Vendors sell implementations, but we should keep this in mind: Interfaces should always be more important than implementations, protocols more important than programs.
Instead of looking for the perfect library to include in our applications or the perfect proxy to secure them, we should focus on what these things do and how we control them so that we can easily improve, upgrade, and replace them.
We can work together.
The easiest way to work with me is to build something with the Sidecar library, see how you like it, and let me know.
I think it would also be great to have more minimal gRPC implementations like Sidecar. When someone writes a gRPC library, there’s a natural temptation to put features in it. I like to call this the "masterpiece syndrome" because it tempts us to prove our skill by adding lots of features. The Sidecar approach is to resist "masterpiece syndrome" and make the most minimal, dependency-free, and legible gRPC implementation that you can make.
And if you’re adventurous, you can try the IO preview.
You can read more about IO and other things that I’m doing at agent.io. See you there!