JC - Rust Production Coding: 2 Cool Pull Requests for Rust Web App Blueprint
As production applications mature, monolithic structures and early-stage blueprints must evolve to support multi-service architectures. This chapter reviews two major architectural pull requests merged into the Rust Web App Blueprint (created by community contributor Vamzi). These changes refactor the codebase to decouple core domain utilities from application-specific logic, paving the way for multi-service scaling (such as adding internal IT servers and secondary web services).
1. Why Do We Need Architectural Refactoring?
In early-stage web development, keeping code in a single service or monolithic library speeds up initial prototyping. However, as production demands grow, maintaining tightly coupled components introduces severe operational and security friction.
- The Monolithic Bottleneck: Initially, the
lib-rpclibrary handled everything: low-level helpers, error definitions, macros, and all web-server-specific RPC handlers. - The Multi-Service Horizon: Mature SaaS applications inevitably require multiple internal and external services (e.g., a primary customer-facing web/mobile backend, and a restricted internal IT server for administrative tasks and agent conversations).
- Security & Isolation Concerns: Even with proper role-based authorization, having unused or bleeding code paths sitting inside an active web server increases the attack surface.
- Divergent Lifecycles: Different services update at different frequencies. Core business logic might remain flat for months while user-facing web endpoints iterate rapidly.
2. Core Mental Model: The Proximity Principle vs. Dogmatic Truths
Real-Life Analogy / Philosophy: There is no single "universal hammer" or absolute architectural truth in software engineering. Architecture is a proximity game—grouping code that changes together close to each other, while cleanly separating components that belong to different operational domains or security zones.
As demonstrated in the blueprint's evolution, code organization should mirror your team's current operational scale and maturity. Avoid premature abstraction, but refactor decisively once production feedback highlights natural boundaries.
3. The Blueprint Architecture Stack
The Rust Web App Blueprint is structured into two primary tiers: foundational libraries at the bottom, and deployment-ready services at the top.
4. Pull Request #1: Splitting lib-rpc into Core and App
To support multi-service architectures without duplicating or entangling RPC handlers, lib-rpc was split into two distinct libraries: lib-rpc-core and lib-rpc-app.
Breakdown of the RPC Split
5. Leveraging the Prelude Pattern in RPC Handlers
In Rust RPC handlers, writing repetitive boilerplate imports (ModelManager, contexts, error types, model structs) across dozens of endpoint files becomes tedious and error-prone.
The lib-rpc-core uses a targeted Prelude module to streamline handler authoring:
// Example pattern inside an application RPC handler (e.g., agent-rpc.rs)
use lib_rpc_core::prelude::*;
use crate::model::AgentBmc; // Business model controller
// Handlers cleanly import common types via prelude and wire up custom logic
pub async fn create_agent(
ctx: Ctx,
mm: ModelManager,
params: RpcParam<AgentForCreate>,
) -> Result<Agent> {
// CRUD execution via Model Controller
AgentBmc::create(&ctx, &mm, params.data).await
}
- Why this works: Developers can cherry-pick business objects (like
AgentorConv) while automatically pulling in standard framework context and macro macros via the prelude. - Custom Handlers: Beyond standard JSON-RPC CRUD operations, developers can seamlessly inject custom Axum-style handlers alongside auto-generated routers.
6. Pull Request #2: Introducing lib-web for Server Commonality
Just as lib-rpc was separated, the original web server implementation contained significant boilerplate and common web primitives (login handlers, session management, core RPC wiring) that would be duplicated if a second web service (like an IT management dashboard) was introduced.
The Solution: Extracting lib-web
- Before: A single monolithic
webfolder inside the primary web server source tree. - After: A dedicated
lib-weblibrary crate that encapsulates shared server mechanics, configuration hooks, authentication middlewares, and standard routing endpoints.
7. Scaling Toward Multi-Service Topologies
With lib-rpc-app and lib-web established, the blueprint now natively supports scaling to multiple services:
- Separation of Concerns: The IT server operates under stricter IP-based firewall restrictions and has a different update lifecycle.
- Event-Driven Backends: Background job services consume tasks from message queues rather than handling HTTP ping-pong, but they still share foundational data models from
lib-core.
Summary and Key Takeaways
- Evolve Architecture Iteratively: Do not over-engineer prematurely; start with a unified blueprint, then refactor into modular libraries (
lib-rpc-core,lib-rpc-app,lib-web) as production usage dictates. - Proximity Over Dogma: There are no universal architectural truths—organize code based on proximity of change, team experience, and domain boundaries.
- Decouple RPC Core from Application Logic: Separate low-level RPC framing, error handling, and macros (
lib-rpc-core) from business-specific domain handlers (lib-rpc-app). - Leverage the Prelude Wisely: Use targeted preludes in RPC handlers to eliminate repetitive boilerplate imports and reduce compile-time friction.
- Extract Shared Web Primitives: Isolate common web server logic (login, auth, middleware) into a reusable
lib-webcrate to support future front-facing or administrative web services. - Multi-Service Readiness: Clean library boundaries enable you to spin up secondary services (such as secure internal IT servers) without code bleeding or security risks.
- Community-Driven Blueprints: Real-world production feedback from contributors (like Vamzi) helps validate and harden open-source application blueprints.