AskVellalaAskVellala
Technology

Application Architectures — A Practitioner's Map

Over the years, I've come to believe that architecture is less about choosing the 'right' pattern and more about understanding what each pattern was designed to solve. Here is my attempt at a practitioner's map — not a textbook, but a working guide.

·8 min read

By Santosh Vellala

Over the years, I've come to believe that architecture is less about choosing the "right" pattern and more about understanding what each pattern was designed to solve. Every architecture in this list was born out of a real problem that the previous generation of systems couldn't handle well.

Here is my attempt at a practitioner's map — not a textbook, but a working guide to the architectures you'll encounter, use, or debate in your career.


1. Monolithic Architecture

Everything — UI, business logic, data access — lives in a single deployable unit.

This gets a bad reputation today, but it's often the right starting point. A monolith is simple to develop, test, and deploy. The problems come when the team grows, the codebase balloons, and a change in one corner breaks something in another.

Best for: Early-stage products, small teams, MVPs.


2. Layered (N-Tier) Architecture

The application is divided into horizontal layers — typically Presentation, Business Logic, and Data. Each layer only communicates with the one directly below it.

This is the architecture most of us learned first. It brings order to a monolith. The downside: changes tend to ripple vertically through all layers even for small modifications.

Best for: Enterprise applications, internal tools, teams new to structured design.


3. Client-Server Architecture

A clear separation between the client (which requests) and the server (which responds). The internet itself is built on this model.

What I find underappreciated here is how much of "modern architecture" is really just a sophisticated evolution of this two-decade-old pattern.

Best for: Web apps, mobile apps, any networked system.


4. Microservices Architecture

The application is broken into small, independently deployable services, each owning a specific business capability and its own data.

Microservices solve the scaling and team-autonomy problems of monoliths — but they introduce distributed systems complexity in return. I've seen teams adopt microservices too early and spend more time managing infrastructure than building features.

The rule I follow: Don't start with microservices. Migrate to them when the monolith's pain is real, not theoretical.

Best for: Large teams, high-scale systems, products with clearly separated domains.


5. Serverless Architecture

You write functions; someone else manages the servers. The cloud provider handles provisioning, scaling, and availability.

Serverless is a genuine productivity multiplier for the right use cases. This very blog uses a serverless Azure Function to power the AI widget — no server to maintain, scales to zero when idle.

Best for: Event-triggered workloads, APIs with variable traffic, small teams wanting to move fast.


6. Event-Driven Architecture

Services communicate by producing and consuming events rather than calling each other directly. An event says something happened — other services decide what to do about it.

This is one of the most powerful patterns for building loosely coupled systems. The producer doesn't know or care who's listening. The trade-off is that the flow of data becomes harder to trace — debugging requires good tooling.

Best for: Real-time systems, notification pipelines, systems with many independent consumers.


7. Service-Oriented Architecture (SOA)

Similar in spirit to microservices, but services tend to be coarser-grained and communicate over an Enterprise Service Bus (ESB). SOA was the enterprise answer to integration problems in the 2000s.

Microservices are in many ways SOA's lighter, cloud-native successor. SOA still appears in large organisations with legacy systems that can't be easily replaced.

Best for: Large enterprise integration, legacy system interoperability.


8. Hexagonal Architecture (Ports and Adapters)

The core business logic sits at the centre, completely isolated from the outside world — databases, APIs, UIs. It communicates with the outside only through well-defined ports and adapters.

I find this architecture produces the most testable code I've ever written. When your business logic has no idea what database you're using, it's easy to swap databases, easy to test without infrastructure, and easy to reason about.

Best for: Complex domain logic, systems that need to be highly testable, long-lived codebases.


9. Microkernel Architecture

A small, stable core system (the kernel) with plug-in modules that extend its functionality. The core works without any plug-in; plug-ins add features without changing the core.

You interact with this every day — VS Code, Eclipse, and most IDEs are built this way. The core is lean; extensions add everything else.

Best for: Extensible platforms, developer tools, applications that need third-party customisation.


10. Component-Based Architecture

The UI and application are assembled from reusable, self-contained components. React, Vue, Angular — all embrace this model.

This is the architecture of the modern frontend. The mental shift it requires is thinking in components (small, composable, isolated) rather than pages or screens.

Best for: Modern web frontends, design systems, UI-heavy applications.


11. Domain-Driven Design (DDD)

Strictly speaking, DDD is a design philosophy more than an architecture — but it shapes architecture deeply. The idea is that software structure should mirror the business domain, with bounded contexts separating different areas of the problem space.

DDD pairs naturally with microservices — each service often maps to a bounded context. It requires deep collaboration between developers and domain experts, which is both its strength and its challenge.

Best for: Complex business domains, large systems where "what does this term mean?" is a recurring question.


12. Cloud-Native Architecture

An approach — not a single pattern — where applications are designed from the ground up to run on cloud infrastructure: containerised, dynamically orchestrated, built for resilience and elastic scale.

Kubernetes, containers, managed services, and infrastructure-as-code are the tools. The mindset shift is designing for failure — assume any instance can die at any time, and design accordingly.

Best for: Products built for public cloud, teams operating at scale, modern SaaS platforms.


13. Peer-to-Peer (P2P) Architecture

There is no central server. Every node is both client and server, sharing resources directly with other nodes.

BitTorrent, blockchain, and decentralised file systems are built on this model. It is resilient by design — there is no single point of failure. The trade-off is consistency and coordination are much harder.

Best for: Decentralised systems, file sharing, blockchain applications.


14. Space-Based Architecture

Designed to handle extreme scale and high concurrency by distributing both processing and data storage across a grid of nodes — eliminating the database as the central bottleneck.

This is a pattern for when you've exhausted every other scaling option and need to handle millions of concurrent transactions. Financial trading platforms and large-scale gaming backends sometimes reach for this.

Best for: Ultra-high-concurrency systems, real-time trading, massive multiplayer games.


15. Progressive Web App (PWA) Architecture

Web apps that behave like native mobile apps — installable, offline-capable, and push-notification-aware — through the use of service workers and web APIs.

PWA is a powerful choice for reaching mobile users without building a separate native app. The gap between PWA and native app experience has narrowed significantly.

Best for: Mobile-first web experiences, markets with low bandwidth, reducing app store dependency.


Patterns Worth Knowing Beyond the Standard List

A few more that practitioners encounter regularly:

Modular Monolith — A monolith with clear internal module boundaries. A smart middle ground before committing to microservices. Often underrated.

CQRS (Command Query Responsibility Segregation) — Separate the model for reads from the model for writes. Unlocks significant performance and scalability for read-heavy systems.

Event Sourcing — Instead of storing current state, store the full log of events that led to it. You can reconstruct any past state and audit everything. Complex to implement, but powerful.

Jamstack — Pre-build everything at deploy time; serve static assets from a CDN; use APIs for dynamic behaviour. Fast, secure, cheap to run. This blog is built on Jamstack.

Micro-Frontend — Apply microservices thinking to the frontend. Independent teams own and deploy their UI slices. Useful at scale; overkill for most teams.

Islands Architecture — A mostly static page with isolated interactive "islands" of JavaScript. The newest pattern on this list — frameworks like Astro are built around it.


The Question I Always Ask

When I evaluate an architecture decision, the question I always ask is: what problem does this solve, and what new problem does it introduce?

Every architecture is a trade-off. Microservices solve team autonomy and scaling but introduce distributed systems complexity. Serverless solves infrastructure burden but introduces cold starts and debugging challenges. Hexagonal architecture produces testable code but requires discipline to maintain.

There is no universally correct architecture. There is only the architecture that fits your team's size, your system's scale, your domain's complexity, and the stage your product is at.

Start simple. Migrate to complexity only when the pain of staying simple becomes real.

That, in my experience, is the only architectural principle that never goes out of fashion.

software architecturesystem designmicroservicescloudengineering