---
title: "06 — Architectural Styles — From Client-Server to Microservices"
uid: architectural-styles
tags: ["client-server", "layered", "distributed-systems", "soa", "roadmap:software-architect", "architecture", "serverless", "actors", "microservices"]
excerpt: "Architectural styles are points on a spectrum from one process doing everything to many independent services — each step trades simplicity for independent scaling and deployment."
date: 2026-08-13T03:27:41+0000
source: https://www.aveshina.my.id/en/blog/architectural-styles
---

A menu of interchangeable options was how the architectures list read to me, which made every choice feel like preference. The model that straightened it out: **these are points on a spectrum, from "one process does everything" to "many independently deployable services," and each step along the spectrum trades simplicity for independent scaling and deployment** [1]. The architect's question isn't "which is best" — it's "how much independent scaling and deployment does this system actually need, and is the added complexity worth it?"

Reading the styles as a spectrum instead of a menu is what made the trade-offs legible. Every step right on the spectrum buys finer-grained scaling and independent deployment, and every step costs more operational complexity — network calls where there used to be function calls, partial-failure handling, data-consistency headaches.

## The left end: client-server and layered

**Client-server architecture** separates tasks between service providers (servers) and service requesters (clients) [2]. It's the foundation of every networked application on the web — a browser asks, a server answers. This isn't really a "style" so much as the basic shape underneath everything else in this post.

**Layered architecture** organizes a system into horizontal layers — presentation, business logic, data access — where each layer only talks to the ones directly above or below it [3]. The win is that you can swap one layer (say, the database) without touching the others. It's one of the oldest and most widely understood styles, and most monoliths are layered internally even if no one calls them that.

## The middle: SOA and the actor model

**Service-oriented architecture (SOA)** structures a system as a set of loosely coupled services communicating through well-defined interfaces, often using standards like SOAP, typically with heavier middleware like an **enterprise service bus** [4]. It predates microservices and shares the goals of modularity and reuse, but with more integration weight. Many large enterprises still run SOA systems built before microservices became common.

The **actor model** takes a different cut: actors are the basic unit of a system, each with private state, communicating only through messages, able to manage other actors [5]. Because state is private and communication is message-only, the model is inherently encapsulated and fault-tolerant. Erlang/OTP and Akka are the canonical implementations. The actor model is the right answer when you have massive concurrency and want failures isolated per actor rather than crashing a whole process.

## The right end: microservices and serverless

**Microservice architecture** is a pattern in which highly cohesive, loosely coupled services are separately developed, maintained, and deployed — each component handles an individual function, and combined they deliver the overall business capability [6]. The defining trait is _independent deployability_: you can ship a change to one service without redeploying the others. That independence is what teams actually buy with the complexity, and it's the thing to verify before adopting the style — if your services can't deploy independently, you've paid the distributed-systems tax without collecting the benefit.

```figure
<svg viewBox="0 0 680 290" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="Monolith versus microservices. Left: a single box with all modules inside sharing one database and one deployment. Right: several small service boxes, each with its own data store, communicating over a network. A label notes that the trade-off is independent deployability for operational complexity.">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">
    <!-- Monolith -->
    <text x="150" y="28" font-size="13" font-weight="700" fill="#134e4a" text-anchor="middle">Monolith</text>
    <rect x="40" y="44" width="220" height="180" rx="10" fill="#ccfbf1" stroke="#0d9488" stroke-width="1.5"/>
    <g font-size="11" fill="#134e4a" text-anchor="middle">
      <rect x="56" y="60" width="188" height="26" rx="5" fill="white" stroke="#0d9488"/>
      <text x="150" y="77">UI layer</text>
      <rect x="56" y="92" width="188" height="26" rx="5" fill="white" stroke="#0d9488"/>
      <text x="150" y="109">Business logic</text>
      <rect x="56" y="124" width="188" height="26" rx="5" fill="white" stroke="#0d9488"/>
      <text x="150" y="141">Data access</text>
      <rect x="56" y="156" width="188" height="26" rx="5" fill="white" stroke="#0d9488"/>
      <text x="150" y="173">One database, one deployment</text>
    </g>

    <!-- arrow -->
    <path d="M280,134 L380,134" fill="none" stroke="#64748b" stroke-width="1.5" marker-end="url(#iarrow)"/>
    <text x="330" y="126" font-size="10.5" fill="#475569" text-anchor="middle">split along</text>
    <text x="330" y="140" font-size="10.5" fill="#475569" text-anchor="middle">business capability</text>

    <!-- Microservices -->
    <text x="510" y="28" font-size="13" font-weight="700" fill="#1e1b4b" text-anchor="middle">Microservices</text>
    <g>
      <rect x="400" y="50" width="80" height="50" rx="8" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
      <text x="440" y="70" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="middle">orders</text>
      <text x="440" y="84" font-size="9" fill="#475569" text-anchor="middle">own DB</text>

      <rect x="500" y="50" width="80" height="50" rx="8" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
      <text x="540" y="70" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="middle">billing</text>
      <text x="540" y="84" font-size="9" fill="#475569" text-anchor="middle">own DB</text>

      <rect x="450" y="130" width="80" height="50" rx="8" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
      <text x="490" y="150" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="middle">shipping</text>
      <text x="490" y="164" font-size="9" fill="#475569" text-anchor="middle">own DB</text>

      <rect x="550" y="130" width="80" height="50" rx="8" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
      <text x="590" y="150" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="middle">users</text>
      <text x="590" y="164" font-size="9" fill="#475569" text-anchor="middle">own DB</text>
    </g>
    <text x="510" y="210" font-size="10.5" fill="#475569" text-anchor="middle" font-style="italic">each independently deployable, network calls between them</text>
  </g>
</svg>
```

**Serverless** (Function-as-a-Service) pushes the spectrum further — applications are broken into individual functions invoked and scaled individually by a third-party provider, eliminating server management from the developer's view [7]. The trade-off is even more granular scaling against cold-start latency, vendor lock-in, and harder local testing.

## Distributed systems: the underlying reality

Everything on the right half of the spectrum is a **distributed system** — multiple independent components on different machines communicating over a network to work as one system [8]. The roadmap is direct about the consequences: distributed systems introduce network latency, partial failures, and data-consistency problems that don't exist in single-machine applications, and architects designing them must _plan for failure as a normal condition rather than an exception_ [8]. This is the tax every step rightward on the spectrum collects. The actor model and microservices don't make failures go away; they make them local to one actor or one service so the rest can keep running.

## How I use this

The decision is a single question: do parts of this system need to scale, deploy, or fail independently? If yes — different teams, different release cadences, different scaling characteristics — the complexity of microservices or serverless is justified. If no, a layered monolith is simpler, cheaper to operate, and I'd rather have it. I start at the left end and only move right when a concrete need forces it, because each step is very hard to walk back.

## References

[1] "Architectures," roadmap.sh — Software Architect. [Online]. Available: [https://roadmap.sh/software-architect/architecture](https://roadmap.sh/software-architect/architecture)

[2] Simplilearn, "What is Client-Server Architecture," [Online]. Available: [https://www.simplilearn.com/what-is-client-server-architecture-article](https://www.simplilearn.com/what-is-client-server-architecture-article)

[3] "Layered architecture," Wikipedia. [Online]. Available: [https://en.wikipedia.org/wiki/Layered_architecture](https://en.wikipedia.org/wiki/Layered_architecture)

[4] Amazon Web Services, "What is Service-Oriented Architecture?," [Online]. Available: [https://aws.amazon.com/what-is/service-oriented-architecture/](https://aws.amazon.com/what-is/service-oriented-architecture/)

[5] B. Storti, "The actor model in 10 minutes," [Online]. Available: [https://www.brianstorti.com/the-actor-model/](https://www.brianstorti.com/the-actor-model/)

[6] microservices.io, "Pattern: Microservice Architecture," [Online]. Available: [https://microservices.io/patterns/microservices.html](https://microservices.io/patterns/microservices.html)

[7] M. Fowler, "Serverless Architectures," martinfowler.com. [Online]. Available: [https://martinfowler.com/articles/serverless.html](https://martinfowler.com/articles/serverless.html)

[8] "Distributed Systems," roadmap.sh — Software Architect. [Online]. Available: [https://roadmap.sh/software-architect/distributed-systems](https://roadmap.sh/software-architect/distributed-systems)

```quiz
Q: What is the defining trait that distinguishes microservices from a monolith?
- Microservices use a relational database
- Microservices are independently developed, maintained, and deployed
correct: 1
explain: The whole point of microservices is independent deployability — you can ship a change to one service without redeploying the others. That independence is the benefit teams buy with the added complexity.

Q: In a layered architecture, how do layers communicate?
- Any layer can talk to any other layer freely
- Each layer only communicates with the layers directly above or below it
correct: 1
explain: Layered architecture restricts communication to adjacent layers, which is what lets you swap one layer (e.g. the database) without disturbing the others.

Q: What problem does the actor model primarily address?
- Rendering large user interfaces
- Massive concurrency with isolated, per-actor state and fault tolerance via message passing
correct: 1
explain: Actors have private state and communicate only via messages, so concurrency is isolated and failures are local to one actor rather than crashing the whole process.

Q: The roadmap says architects designing distributed systems must…
- treat failure as a normal condition, not an exception
- assume the network is reliable
correct: 0
explain: Distributed systems introduce latency, partial failures, and consistency problems. Planning for failure as normal is the discipline; assuming a reliable network is the classic mistake.

Q: Serverless pushes the spectrum further than microservices by…
- breaking applications into individual functions invoked and scaled by a third-party provider
- combining all services back into a single monolith
correct: 0
explain: Serverless (FaaS) breaks apps into individual functions the provider invokes and scales, eliminating server management — at the cost of cold-start latency and vendor lock-in.
```
