With the rise of cloud-native development, organizations have been faced with a difficult decision: attempt to scale applications as monoliths (and cope with centralized, finicky, rollback-prone deploys) or break applications into microservices (and suffer from data/ownership siloes that make it difficult to transactionally manage state). We have been forced to make uncomfortable tradeoffs. This is a false choice, we're missing the right abstractions. It should be possible to write code with the simplicity of a monolith (straightforward function calls composed via transactions), but with the scalability of microservices (encapsulation of data and ownership, support for polyglot components, independent deploys, etc). In this talk, we’ll discuss how using microservices in anger led to the need for transactionality between calls. We’ll also discuss how gRPC and protobuf were obvious choices for implementing the network layer and schema language.