Background paper texture
microservicearchitecturesoftware engineering

Microservice: From Monolith to Distributed System

Casual notes on monolith vs microservice, inter-service communication, and the repository pattern.

Author avatar

Peter Shaan

November 18, 2025


53 Views

In my current career as a software engineer at a company, I've entered an ecosystem called microservices. When I first started, I was a bit confused: what are microservices? Why are people talking about them so much? How are they different from the infrastructure I've been using before? And why do I need to use microservices?

These are casual notes explaining the journey from a monolith to a microservice, why people bother moving architectures, and what concepts are important to understand if you want to play in the distributed system world.


Monolith Architecture

Let's start with the basics:

The code that what your college teacher taught you back then is usually in the form of a monolith. The freelance projects you've done, the web apps you've built using frameworks like Next js, Laravel, Django, or Rails, are typically monolithic applications.

Monolith = a large codebase that manages many domains/features within a single application.

  • One repository (repo)
  • One build artifact (e.g., one Docker image)
  • One deployment unit (usually one server / one pod)

So all features — payment, user login, dashboard, etc. — are mixed within a single application.

The consequences:

  • If the login feature crashes, then:
    • Payment might also fail
    • Dashboard becomes inaccessible
    • In short: one part breaks, the whole system catches fire

In the end, it's just one big service:

  • Packaged as one Docker image
  • Usually runs on one server
  • Single unit of deployment – all functions are deployed together
  • If you want to release a small change (e.g., fix one small bug), you still have to redeploy everything

In short: simple at the beginning, but becomes increasingly painful as it grows.


Microservice

Dive in to microservice.

The basic mindset: built to scale, both in terms of:

  • Load (increasing traffic)
  • Team (many teams working in parallel)
  • Business domain (increasingly complex business)

Usually, microservices are not created from scratch, but:

“Microservice is part of a gradual migration from monolith.”

Gradually, certain domains are split into their own services.

In the real world, all of this usually lives inside:

  • Kubernetes cluster (k8s)
  • One cluster, containing many small services
  • Services communicate with each other

Kubernetes is a whole topic on its own, we will not discuss it here.

Some common characteristics of microservices:

  • Robustness
    The system remains resilient and stable even if one service fails. For example, if the notification service goes down, the core booking service still operates.

  • SOC (Separation of Concerns)
    Each service has a clear responsibility. For example:

    • user-service: only handles users
    • payment-service: only handles payments
  • Team Autonomy
    One team owns one microservice and can operate independently:

    • Tech stack can be different
    • Release cycle can be different
    • Not too dependent on other teams for shipping

You dont win by haing Microservice. The two best reason to choose Ms is because :

  1. Your organization is growing and needs to allow for more teams to work independently.
  2. Improved Scalability and Resilience.

Service?

The definition of microservice can vary, but generally:

Microservice = small, autonomous, loosely coupled, context bound service.

The details:

  • Micro
    As the name suggests, a service should be small and focused on one specific domain or task, and do it very well.

  • Autonomous
    Every service:

    • Independent deployable
    • Able to operate independently
    • Has its own lifecycle (build, deploy, scale)
  • Loosely Coupled
    Always keep interdependency between services as low as possible.
    In practice:

    • A service only knows the contract (API, event) of other services
    • Not the implementation details

    If you come from the frontend world, it's similar to the concept of a “dumb component” that is easy to reuse and compose.

  • Context Bound
    Ideally, one service is handled by one small team.
    This helps maintain productivity and avoid excessive communication overhead within the team.

Cohesion and Coupling

Microservice = we aim for high cohesion and low coupling 👍.

The whole point of microservices is being able to make change one service without having to change other services.

We want:

  • Service that loosely coupled
  • Only know what is really necessary about other services

In short: minimize coupling if you want to play with microservices.

## Example

Imagine we have a `payment-service` that needs to send a notification when a payment is 
successful.

<br /> <br />
Instead of directly calling the `notification-service`'s internal functions (which would 
create tight coupling), the `payment-service` can simply send a message to a message broker 
or call a public API exposed by the `notification-service`.

<br /> <br />
If change occur in the notification logic, the `payment-service` remains unaffected as long
 as the contract (API/message format) stays the same.

The Point

High cohesion = the things that logically related are grouped together in one place.

Example:

in a microservice this type of interaction is unavoidable. it relies on well defined api contracts and message formats to ensure that changes in one service do not break others.

We still want to keep it to a minimum. (avoid chatty communication between services).

The Database Problem

The problem really arrise when multiple services read/write to the data.

It also defeat the purpose of microservice if multiple services read/write to the same database.

Changes to DB schema need to be reflected in multiple services. This creates tight coupling at the data layer.

THe solution is to have each service own its own database. This way, services are decoupled at the data layer, and changes in one service's database schema do not impact others.


Communication Styles

When services need to talk to each other, there are two main styles of communication:

"Now, if we have many services how to communicate each of the service?”

Synchronous Communication

  1. HTTP / REST API
  • The most common way services talk to each other
  • One service (client) makes an HTTP request to another service (server)
  • Typical methods: GET, POST, PUT, DELETE
  • No loose contrast, loosly defined via API documentation (OpenAPI/Swagger)
  • Text based (usually JSON)

Note: use it when excellent for public facing APIs and scenarios where interoperability and ease of debugging are priorities.

  1. RPC / gRPC
  • High performance Remote Procedure Call framework that uses a Protocol Buffers (binary format)
  • Define service and method contracts using .proto files, and a code generated client/server stubs
  • Support simple request-response, streaming, and bi-directional streaming

All of that Rest Api or gRPC call it is still synchronous communication.

  • The client waits for the server to respond before continuing
  • If the server is slow or down, the client will also experience delays or errors

Note: use it when well suited for high-performance internal services to service communcation where strong contracts and low latency are required.


Asynchronous Communication

"if synchronous communcation make system dependent on the health of other service, how to reduce the risk?”"

the answer is asynchronous communication.

  • Message broker
  • Event bus
  • Queue (Kafka, RabbitMQ, SQS, dsb.)

The benefit of asynchronous communication:

  • Loose coupled: service a and service b dont need to be up at the same time
  • Scalability: because messages queue up, services can process them at their own pace
  • Realiability & Fault tolerance: message brokers often have built-in mechanisms for retrying failed messages, ensuring that important data is not lost
  • Durability: messages can be persisted in the broker, ensuring they are not lost even if the consumer service is down temporarily

Hybrid Approach

Gateway can handle synchronous requests from clients, and then internally communicate with other services using either synchronous or asynchronous methods depending on the use case.


Layered Architecture

Now for the last topic before we end this post: layered architecture in microservices.

Even though microservice, work in many service, we still can used layered architecture the main idea is to make the code organized and every service manageable.

There are many typed of layering architecture, but the most common one is:

  • Separation of Concerns (SoC): each layer has a specific responsibility
  • Independence: layers should be independent of each other as much as possible
  • Maintainability: easier to maintain and update each layer without affecting others

Example layering that i used in my workplace:

  • Routes Layer: handles HTTP requests and responses
  • Controllers Layer: contains the business logic for handling requests
  • Services Layer: contains the core business logic and interacts with repositories
  • Repositories Layer: handles data access and persistence

It is called Clean Architecture or Onion Architecture. im using at echo framework in golang. here is the repo if you want to check it out it also already connect with swagger: github.com/petershaan/echo-clean-architecture


Final Thoughts

When you move to microservices, you’ll face a one problem that you are really have to consider that is

The Cost of Distributed System

Microservice bring many benefit that monolith cant provide, but it also spend more cost, time, team to maintain the system. so before you move to microservice make sure you really need it. peace out guys.