Process-Based Architecture: Sweet Spot Between Monoliths and Microservices
Ever found yourself drowning in a sea of tightly coupled code? You're not alone. Many SaaS applications, especially those built with Java, have fallen into the trap of the "single process, multiple thread" model. It seems convenient at first – just launch one JVM and you're good to go! But as your application grows, this approach can lead to a tangled mess of dependencies, shared memory issues, and painful garbage collection cycles.
Let's explore a more balanced approach: process-based architecture. This design pattern sits comfortably between heavyweight microservices and bloated monoliths, offering a practical solution for today's multi-core computing environments.
The Problem with Monolithic JVMs
When you pack everything into a single Java Virtual Machine, you're essentially putting all your eggs in one basket:
All functions share the same memory space
Everyone suffers through the same garbage collection pauses
Source code becomes tightly coupled over time
Changes to one component risk breaking others
Scaling means scaling the entire application, not just busy parts
As the codebase grows, development slows down. New features become harder to implement, and the risk of introducing bugs increases. Your once-nimble application has transformed into dreaded "bloatware."
PostgreSQL: A Masterclass in Process-Based Architecture
To understand the power of process-based architecture, let's study PostgreSQL – one of the most robust and reliable database systems available today. PostgreSQL's architecture is a prime example of how multiple specialized processes can work together to create a system that's both powerful and maintainable.
The Journey of a SQL Query Through PostgreSQL
When you send a SQL query to PostgreSQL, it travels through a carefully orchestrated dance of specialized processes:
Connection Management Layer
The Postmaster Process (the system's guardian) listens for incoming connections
When a client connects, Postmaster forks a new Backend Process dedicated to this connection
This Backend Process maintains the client's session state and handles authentication
Query Processing Layer
The Backend Process parses the SQL query into a syntax tree
The query planner analyzes the tree and generates an execution plan
The executor then implements this plan, coordinating with other processes as needed
Storage Layer
The executor requests data pages from the buffer cache
If pages aren't in memory, the Background Writer and Checkpointer processes manage reading from and writing to disk
For write operations, the WAL Writer ensures changes are logged for durability
All the while, supporting processes handle critical background tasks:
The Autovacuum Launcher initiates cleanup operations
The Stats Collector gathers performance metrics
The Archiver manages write-ahead logs for disaster recovery
This process-oriented design allows PostgreSQL to:
Handle thousands of concurrent connections efficiently
Maintain data integrity even during system crashes
Utilize multiple CPU cores effectively
Isolate failures to minimize system impact
The Orchestration Magic
What makes PostgreSQL's architecture particularly elegant is how these processes communicate and coordinate:
Shared Memory Segments allow fast data exchange between processes
Lightweight Locks coordinate access to shared resources
Semaphores synchronize operations across process boundaries
Signal Handlers enable processes to respond to events from others
This sophisticated orchestration allows PostgreSQL to maintain both high performance and rock-solid reliability. When a query traverses the system, each specialized process handles its part of the workload, passing results to the next process in the chain until the final response is delivered to the client.
Source Code Modularity: Learning from PostgreSQL
PostgreSQL's source code organization reflects its process architecture, with clear boundaries between components. This modularity provides valuable lessons for application developers:
Connection management code is separate from query processing
Parser code is distinct from execution logic
Storage engine components are isolated from higher-level functions
This separation ensures that changes to one area don't unexpectedly impact others, making the system more maintainable despite its complexity.
Polyglot Programming: Language Freedom Through Process Boundaries
One of the most powerful yet underappreciated advantages of process-based architecture is the freedom to use different programming languages for different components of your system. This polyglot approach enables you to match the right language to each specific domain problem:
Computation-intensive functions: Rewrite from Java to Rust or C++ for significant performance gains
Data processing pipelines: Use Python for its rich data science ecosystem
Web interfaces: Employ JavaScript/TypeScript with modern frameworks
Administrative tools: Build with scripting languages for rapid iteration
While PostgreSQL itself is primarily written in C, its architecture demonstrates how separate processes with well-defined interfaces could theoretically be implemented in different languages. For example, you could imagine a specialized analytical engine written in Rust that communicates with the core PostgreSQL processes through established protocols.
Domain-Driven Design: The Perfect Companion
Process-based architecture pairs beautifully with Domain-Driven Design (DDD) principles:
Bounded Contexts: PostgreSQL demonstrates this with its clear separation between connection handling, query processing, and storage management – each with its own conceptual model.
Ubiquitous Language: Each component in PostgreSQL has its own terminology appropriate to its domain, from "query plans" in the processing layer to "page slots" in the buffer manager.
Context Mapping: The interfaces between PostgreSQL's components define clear translations between domain models.
Aggregates: PostgreSQL's concept of a "relation" (table) and its associated objects form natural aggregates within the system.
These DDD principles can be applied to any process-based architecture, helping to define clean boundaries between components that map to your business domain.
The Natural Path to Microservices
One of the most compelling advantages of a process-based architecture is its natural evolution path toward microservices:
Start with process separation: Begin by splitting functionality into separate processes
Enforce clean interfaces: Define clear communication boundaries
Separate repositories: Move each process to its own codebase
Containerize: Package each process as a container
Distribute: When needed, deploy processes across multiple machines
This incremental approach allows you to gain the benefits of microservices without the "big bang" rewrite that often dooms microservice migrations.
Implementation Strategies for Your Applications
When implementing a process-based architecture inspired by PostgreSQL, consider these approaches:
Function boundaries: Identify natural layers in your application (presentation, business logic, data access) that could become separate processes
IPC mechanisms: Choose appropriate inter-process communication methods based on performance needs
Process management: Use supervisors to ensure processes start in the correct order and restart if they fail
Repository strategy: Create separate repositories with clear ownership boundaries
Language selection: Choose the optimal programming language for each process based on its specific requirements
Real-World Example
Imagine a typical e-commerce application with these processes:
API Gateway: Routes external requests to appropriate internal processes
Product Catalog: Manages product information and search
Order Processing: Handles order creation and payment processing
Recommendation Engine: Computes personalized product recommendations
Inventory Management: Tracks available inventory
Notification Service: Sends emails and other notifications
Each process has its own repository and can be written in the language best suited to its domain. As you evolve the system, you might rewrite the recommendation engine in Rust for better performance without disrupting any other component – just as PostgreSQL's specialized processes focus on their specific responsibilities.
Perfect for Modern Cloud Computing
With cloud providers offering multi-core instances at reasonable prices, process-based architecture shines. Instead of paying for multiple machines to run microservices, you can efficiently utilize a single multi-core instance by distributing processes across cores.
This approach gives you:
The isolation benefits of microservices
Lower infrastructure costs than a distributed system
Simpler operations than managing a cluster
Better resource utilization than a single-process application
Language flexibility without technological fragmentation
A smooth path to full microservices when needed
Conclusion
Process-based architecture offers a pragmatic middle ground between monolithic applications and distributed microservices. PostgreSQL provides a masterclass in how to design such a system effectively, with specialized processes working in concert through well-defined interfaces to handle complex workloads reliably.
By studying how PostgreSQL orchestrates the journey of a SQL query through connection management, query processing, and storage layers, we can apply these same principles to application development. The result is systems that are modular, extensible, and primed for whatever scaling challenges the future holds.
The ability to rewrite individual processes in different programming languages provides unprecedented flexibility to optimize for performance, developer productivity, or specific domain requirements. Combined with Domain-Driven Design principles, this approach creates a powerful framework for building complex systems that remain maintainable and adaptable over time.
Remember: True modularity starts with process boundaries and clear interfaces. This foundation gives you the freedom to choose the right tool for each job while maintaining system integrity and coherence – just as PostgreSQL has done for decades.

