Overview
SafetyCulture describes how they streamlined gRPC development for their offline-first mobile apps by automating code generation for their C++ middleware layer called Crux. The article explains how a Python-based code generation script replaced hundreds of lines of manual C++ and Djinni IDL boilerplate with concise Python definitions, lowering the barrier to entry for mobile engineers who lack deep C++ expertise.
What You'll Learn
How to design a middleware layer for offline-first gRPC communication in mobile apps
Why automating boilerplate code generation reduces developer friction in cross-platform mobile development
How to categorize gRPC calls into distinct patterns for caching and response reduction
When to use code generation scripts instead of rewriting legacy C++ systems in modern languages
Prerequisites & Requirements
- Understanding of gRPC protocol and client-server communication patterns
- Familiarity with offline-first mobile app architecture and data caching strategies
- Experience with mobile development (iOS/Android) and cross-platform libraries
- Basic understanding of C++ and code generation concepts(optional)
Key Questions Answered
How does SafetyCulture handle gRPC communication in offline-first mobile apps?
What is the Crux middleware and what role does it play in mobile offline support?
What are the four gRPC call patterns used for offline mobile app support?
How can code generation reduce boilerplate in cross-platform mobile middleware?
Why is C++ problematic for mobile developer productivity in gRPC middleware?
Why didn't SafetyCulture rewrite their C++ middleware in Go or Rust?
What is response reduction in offline-first mobile apps?
Key Statistics & Figures
Technologies & Tools
Some links below are affiliate links. We may earn a commission if you make a purchase.
Key Actionable Insights
1Introduce a middleware abstraction layer between feature modules and network clients to enable offline support. By preventing direct gRPC calls from feature code and routing all communication through a middleware like Crux, you can transparently add caching, response reduction, and other offline capabilities without requiring changes to business logic.This pattern is especially valuable for apps used in environments with unreliable connectivity, such as remote worksites, cruise ships, or mining locations where network access is intermittent or unavailable.
2Categorize your network calls into distinct patterns (e.g., single fetch, batch fetch, mutations) and build specialized handling for each. This classification allows you to apply appropriate caching strategies and response reduction logic per pattern rather than handling each call individually, which reduces complexity and ensures consistency.SafetyCulture uses four distinct gRPC call patterns in Crux, each with specialized caching and data reduction handling. This pattern-based approach makes it easier to add new calls since developers only need to specify which pattern applies.
3When legacy code creates productivity bottlenecks, consider automating code generation before attempting a full rewrite. A Python script that generates C++ boilerplate and IDL definitions can dramatically reduce the barrier to entry, allowing engineers without deep C++ expertise to contribute effectively.SafetyCulture's experience shows that rewriting from C++ to Go or Rust was unsuccessful, but code generation achieved similar developer productivity improvements while preserving the performance benefits of the existing C++ system.
4Start with automating a single, limited use case and iteratively expand coverage. SafetyCulture's initial script only supported Single Object Fetch with no response caching, but its immediate productivity gains justified continued investment, eventually growing to support all four gRPC call patterns.The iterative approach over six months allowed the team to validate the approach early and expand based on real developer needs rather than trying to build a comprehensive solution upfront.
5Use declarative Python definitions as the interface for code generation rather than requiring developers to write the target language directly. This approach lets mobile engineers specify behavior (caching keys, item types, mutation tags) in a familiar, concise syntax while the generator handles language-specific complexities.The code example in the article shows how domain, service, and call definitions in Python replace hundreds of lines of C++ and Djinni IDL, making the system accessible to developers who are not C++ experts.