“The best architectures, requirements, and designs emerge from self-organizing teams.”
-Agile Manifesto Principle
Any practitioner, who got burnt with the Big Design Up Front (BDUF) approach will attest to how important and useful this principle is. However, sometimes this leads to a naïve understanding that the iterative approach is somehow at odds with the “architecture”.
An agile team has to make architectural decisions. They need to consider areas like scalability, security, performance, and agility. Additionally, they need to have a concrete understanding of what components need to be built and how they will collaborate. Agile does not mean that these considerations can be wished away.
Choosing the right service architecture pattern is essential for success. Once the decisions are made, they stay with the product for a very long time, so they need due consideration.
Types of service architecture patterns
To make the right choice, we have a few options:
Monolith
The dictionary defines monolith as “a large impersonal structure regarded as indivisible and slow to change”. In the realm of software architecture, the concept of monolithic means different components of an application being combined into a single program on a single platform. A typical monolithic application consists of a database, server-side application, and a client-side user interface.
Components in a monolithic architecture are interdependent and interconnected. This is a traditional solution for building applications. It’s a comfortable architecture for small teams and many start-ups choose this approach when building their products. Sometimes considered outdated and derided unfairly, it is a perfect solution in some circumstances.
Why Monolith? | Why not Monolith? |
Offers simpler development and deployment options easier to hook up components to cross-cutting concerns (e.g., rate limiting, audit trails, etc.) when everything runs in the same app. If built correctly, monolithic apps are more performant. An app using microservices architecture may make dozens of API calls to load each screen. Monolithic apps allow faster communication due to shared process space and memory. | Over time, successful products keep on gathering new functionality incrementally. The underlying structure starts breaking down as the codebase starts to look massive. Side effects and dependencies start kicking in as new developers get added to the team. Every update means a full redeployment. All developers must wait before the deployment is done. If multiple teams are working on the product, it impacts agility where every team must synchronize with a master release schedule. Hard to introduce new technology. |
Service-Oriented Architecture (SOA)
SOA focuses on application service reusability. It separates functions into distinct units, or services, that developers make accessible over a network to allow users to combine and reuse them in the production of applications. These services and their corresponding consumers communicate with each other by passing data in a well-defined, shared format, or by coordinating an activity between two or more services.
The concept of SOA is as follows: an application can be designed and built in a way that its modules are integrated seamlessly and can easily be reused.
Why SOA? | Why not SOA? |
Well-suited for large, complex, enterprise-wide systems that require integration with many applications and services as compared to microservices that are better suited for smaller, well-partitioned web-based systems.Valuable in integrating with multiple heterogeneous systems and services. Contract decoupling – the primary capability of SOA – enables services and consumers to evolve separately while maintaining the contract. Microservices architecture doesn’t support it. | Requires a greater upfront investment of development time and cost. Managing a service-oriented architecture is complex. Reusability comes with a higher cost to maintain which lowers agility. |
Microservices
Microservices is a service-oriented architectural pattern wherein applications are built as a collection of the smallest independent service units. The microservices approach focuses on decomposing an application into single-function modules with well-defined interfaces.
With a focus on decoupling, microservices can be independently deployed and operated by independent teams that own the entire lifecycle of the service.
“Micro” refers to the sizing of the service which must be manageable by a single development team.
Why Microservices? | Why not Microservices? |
A single service can be built, tested, and deployed independently so that development teams don’t step on each other’s toes. This reduces the ensuing risks in deployment. Developers can update system components without any application downtime so the team can attain higher velocity. Can achieve horizontal scaling very easily through automation, which is a huge advantage of cloud-native development. | Architecture can bloat quickly if not kept in check. Good implementation on a microservices architecture requires careful planning, considerable effort, and a skilled team. There is increased demand for automation as each service has to be tested and monitored. Transaction management and data consistency become a challenge with separate databases for each service. |
Serverless
Serverless is a model in which application code is executed on-demand in response to triggers that application developers configure ahead of time.
Code execution is managed by a server, allowing developers to deploy code without worrying about server maintenance and provision.
Serverless doesn’t mean “no server.” The application is still running on servers, but a third-party cloud service takes full responsibility for these servers.
Why Serverless? | Why not Serverless? |
Developers don’t need to worry about infrastructure. A new application can be spun up quickly. Serverless mode is generally cheaper to run, especially if there is a large peak-to-mean load ratio. Gives the easiest scalability, allowing high loads to be managed without affecting the performance. | Serverless threads are not well-suited for long-running processes. Serverless functions are stateless, which makes them hard to debug in production. Heavy reliance on the vendor ecosystem for execution can lead to vendor lock-in. |
Conclusion
As always, there is no “best” architectural choice. However, there certainly are “wrong” choices and that depends on the situation and problem at hand. Understand the choice you are making and its trade-offs. Make considered decisions and never jump headlong into ‘buzzword du jour’. Live long and code!