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 userspayment-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 :
- Your organization is growing and needs to allow for more teams to work independently.
- 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
- 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.
- RPC / gRPC
- High performance Remote Procedure Call framework that uses a Protocol Buffers (binary format)
- Define service and method contracts using
.protofiles, 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.
