Few architectural concepts have captured the technology world as much as microservices, and the excitement is somewhat deserved, particularly judging by the years they have been promoted as a silver bullet solution to modern software development issues. While the benefits of microservices are genuine, our attempt to develop AtroCore as an open-source master data management and integration platform led us to the conclusion that microservices are not always the answer.
Like any other architectural style, microservices have been getting years of excitement and appreciation from the industry, but their relevance purely comes down to the use case. For AtroCore, we have stripped down the advantages and disadvantages of the features and settled on a Modern Modular Monolith as the architecture foundation for our platform for today. Let us explain.
The Excitement Of Microservice Architecture
Microservices, by their own definition, structure an application as a collection of smaller independent services. As a result, we are able to achieve the following benefits:
- Scalability: Services can be scaled independently based on load.
- Fault Isolation: The failure of one service doesn't bring down the entire application.
- Agility & Technological Freedom: Teams can develop and deploy services independently, choosing the best technology stack for each task.
- Better Maintainability: Smaller codebases are easier to understand and manage.
- Reusable Code: Logic can be packaged and consumed by multiple services.
This offers positive results for certain types of projects:
- Heterogeneous complex business systems with functional modules or (?) microservices, and can be independently located, owned, developed, maintained or evolved.
- Cloud-native SaaS Products that is multi-tenant and sustains large varied workloads.
- Services, streaming Real-time Data Processing that is isolated to individual services.
- High-traffic systems that need to flexibly scale certain critical bottlenecks.
The Microservices Trap
The Microservices are considerably simpler is in fact, a falsehood. The promise of microservices does come at a high price, a price that is difficult for a lot of organizations and applications to afford.
Within a tightly integrated platform like AtroCore, it was quickly understood that for AtroCore’s case, the compliance would be more trouble than it was worth.
- Infrastructure Overhead: The management of many services, deployment pipelines, containers and service meshes comes at a large cost, due to the massive infrastructure needed.
- Distributed Transactions: Maintaining separate services and their data, and ensuring that data is consistent for all services, is extremely difficult and often results in complex compensating transactions (Sagas).
- Cross-Service Communication: Within the same data center, network calls are slower and far less reliable than simple in-memory function calls.
- Increased Infrastructure Cost: More servers and components to monitor, in addition to an increased cloud bill, will all result from more moving parts.
- Difficult Monitoring and Debugging: Monitoring a single user request that spans many services is, by default, far more complicated than monitoring a single application.
The Modular Monolith as an Optimal Architecture for Standard Business Software
Standard business applications like ERP, MDM, PIM, and CRM systems revolve around integrated workflows, interlinked data models, and closely connected dependencies within components/modules. These systems generally necessitate concurrent operations across multiple domains.
Bounded context clarity
The Modular Monolith implements bounded contexts through its logical separation into more manageable modules, achieving meaningful separation without separation of undeployed modules which introduces unnecessary complexities in inter-domain transactions. This works nicely for business software where domains (i.e. PIM, CRM) are separate but require deep intertwined interdependency.
Release and version interdependence
Monolith software can be simultaneously and consistently deployed while considerably simplifying release management compared to an orchestrated release of numerous independent microservices. This is especially crucial in an enterprise context where core components are required to be versioned and released simultaneously (e.g. an Order Module upgrade must interoperate seamlessly with an Inventory Module).
Centralized business logic
For security and compliance needs (ex. GDPR) and regulations, a single application boundary simplifies governance immensely, providing a single, controlled point to enforce critical and cross-cutting business concerns (ex data masking, logging, and audit trails).
Cross-domain development
Developing features that span two related domains (e.g. managing accounts and related orders) is far more straightforward. The developer can perform a full functional change required for an enterprise workflow in a single codebase, thus enhancing velocity considerably, and to be certain, they can be debugged and tested in deployed in a single transaction.
Resource Efficiency
The Monolith offers better resource efficiency and lower memory overhead in comparison to multiple processes with Operating Systems and containers. This also makes it a more economically viable and environmentally friendly option for the predictable workload profiles encountered in most business software.
Skill Set Fit
This architecture works more aligned with the skill set of in-house IT teams or systems integrators. It requires strong design skill, but not the expensive, specialized DevOps talent to untangle the complex web of distributed tracing, service meshes, and Kubernetes clusters necessary for independent Microservices.
Data Consistency
Latency and consistency are critical, and the failure or delay in communications across business-critical modules can be costly. With a modular monolith, interactions occur within the same process and under a unified transaction scope, which can mitigate the risk of partial failures and optimize rollback complexity.
Internal / External Maintenance
Centralized teams with domain expertise typically develop and maintain all standard business software. The modular monolith architecture accommodates this structure because it allows teams to operate within a single unified codebase while retaining distinct, interdependent modules. This helps to boost collaboration while also improving governance and onboarding time.
Customizability
Business software often needs considerable adjustments to fit particular workflows, regulations, or clients. More customization is possible with a modular monolith since every module is built on a shared structure, and alterations can be made without the complexities of service and deployment projections across disparate systems.
AtroCore's Reasoning
We had certain requirements that eliminated the Microservices approach. We specifically did NOT WANT to choose a multi-tenant architecture, where all customers use the same database, as this is extremely prone to data breaches. AtroCore is purpose-built for high-integrity deployed, single tenant environments.
Our different domains (like PIM, Sales, Projects etc) share a lot of similar core logic, like configurable layout profiles, the data model configuration layer, permission logic, and REST API logic. Code duplication or unnecessary service-to-service dependency hell would result from separation.
The Modular Monolith architecture is definitely smarter and more pragmatic than the first architecture proposed.
It still possesses the advantages of a single, unified deployment unit while still respecting the decoupled internal structure coupled with Microservices.
Our Modularity Approach
There is a modular approach where the traditional microservices decoupled approach is communication.
All communication is done “in-process” which is rather fast and reliable.
The AtroCore Framework/Core: This is the central part of the platform dealing with all the shared concerns (security, user roles, logs, access to the database, settings, etc.). This reduces complexity for each module developer, because they no longer have to build these services from scratch.
Independent Modules: The Projects module is logically and structurally separate from the Sales module. While modules are clearly defined, they are designed to extend and/or modify the core logic and the logic provided by other modules.
The Benefits for AtroCore Data Platform
Within the "Modular Monolith" architecture, AtroCore is able to enjoy critical benefits without operational complexity.
- Deployment: With AtroCore, we no longer need to manually track dependencies and use complex deployment scripts. AtroCore modules are distributed via Packagist with strict versioning. Updates are part of the system and under one administrator action, ensures the system consistency and reliability.
- Testing/Debugging: It is exponentially easier to trace and debug a request from the start to the end across a single application.
- Speed: Direct function calls and shared memory access are way faster than network calls.
- ACID Transactions: It is easy to maintain strong ACID transactional consistency (Atomicity, Consistency, Isolation, Durability) across related data, which is crucial for accurate data – for example, order data, or inventory data.
Future-Proofing and Data Flexibility
The Modular Monolith comes with a set of base features designed especially for evolution instead of just scaling. This allows AtroCore to remain enterprise-grade, open-source Software and provider of software solutions, while still being scalable and flexible, even as company data becomes more complex or increases in volume.
Dealing with Data Volume: The architecture does not limit us to a singular type of database. If a customer’s analytics or historical data reaches a Big Data scale, AtroCore is able to implement specialized, tier-one databases, for example, ClickHouse for analytics queries, without requiring a complete system overhaul to microservices. The modules interface with the right tool for the job.
Performance Goal Accuracy: There is no need to rewrite a module as a microservice to improve performance. The modular approach works to redesign performance issues in a more targeted manner on a micro level. We only need to isolate high-load core business processes that need tight coupling to modular, serverless functions without needing to extract the entire set of services.
Prolonged Surplus of Simplicity: The obsolescence of service decomposition in AtroCore increases the simpler the system is, and the more maintenance is needed over a decade. This directly converts into a decreased TCO for our clients, guaranteeing that complexity does not build up unnecessarily.
More modular extensions to the core are simpler to build and maintain, and thus the overall system is more sustainable and affordable than supporting a web of individual microservices.
Final Thoughts
For some large scale, loosely-coupled use cases, microservices as a distinct architecture are more than useful – they are essential. For something as integrated and feature rich business apps as AtroCore, however, they represent over-optimization and an unjustifiable increase in operational and development efforts.
The Modern Modular Monolith is definitely the best way for similar cases. It provided powerful, tightly integrated, and efficient platform without overwhelming complexity, enabling us to concentrate on the business functionality and not on backend infrastructure issues.
Before assuming the hottest trend will work for you, assess your project’s real requirements – its size, the level of integration, and your team. Often, the best system design is the one that keeps things simple and maximizes functionality in important areas.
Top comments (0)