Why and How to Adopt Microservices: Lessons from a Node.js Migration

This article explains the goals, principles, and practical reasons for moving from a monolithic Node.js application to a microservice architecture, outlining design guidelines and a seven‑point strategy to avoid common pitfalls and improve performance, scalability, and team productivity.

Node Underground
Node Underground
Node Underground
Why and How to Adopt Microservices: Lessons from a Node.js Migration

Microservice architecture aims to help engineering teams deliver products faster, safer, and with higher quality. By decoupling services, teams can iterate quickly while minimizing impact on the rest of the system.

At Medium, the tech stack began in 2012 as a large Node.js monolith. After building several auxiliary services, no formal microservice strategy existed. As the system grew more complex and the team expanded, the company migrated to a microservice architecture in early 2018. This article shares the experience and how to avoid the "microservice syndrome".

What is microservice architecture?

In a microservice architecture, many loosely‑coupled services work together. Each service focuses on a single goal, and its behavior and data are highly cohesive.

The definition includes three design principles:

Single purpose – each service should concentrate on one purpose and do it well.

Loose coupling – services know little about each other; changes to one service should not require changes to others, and communication occurs only through well‑defined interfaces.

High cohesion – related behavior and data are encapsulated within the service, so new features affect only that service.

Microservice design principles
Microservice design principles

When designing microservices, adhering to these three principles is the only way to unlock the full potential of the architecture. Missing any principle leads to anti‑patterns.

If a service lacks a single purpose, it becomes an “integrated” service that does too much, increasing operational cost without delivering microservice benefits.

Without loose coupling, a change in one service can affect others, preventing fast and safe releases and risking data inconsistency or loss.

Without high cohesion, teams end up with a distributed monolith that requires coordinated changes across many services, often becoming more complex than a traditional monolith.

It is also important to understand what microservices are not:

They are not defined by a small amount of code or “tiny” tasks; a microservice can be complex and large as long as it follows the three principles.

They are not always built with new technology. While microservices make it easier to experiment, the primary goal is service isolation, not technology novelty.

They are not required to be built from scratch. Existing well‑structured applications can be split into services without rewriting everything.

Why Do It Now?

When making major product or engineering decisions, Medium asks “Why now?” to avoid assuming unlimited people, time, and resources. This question adds constraints such as impact on current work, opportunity cost, and distraction, helping prioritize effectively.

The monolithic Node.js application has become a bottleneck in several ways.

First, performance is the most urgent bottleneck. Heavy computation and I/O‑intensive tasks are ill‑suited for Node.js, and incremental improvements to the monolith proved ineffective, limiting product quality.

Second, the monolith slows product development. Because engineers work on a tightly‑coupled codebase, changes in one area affect many others, making large modifications risky and often blocking deployments when a single bad commit occurs. Microservices enable faster, safer iteration by decoupling new features from the rest of the system.

Third, scaling specific tasks or isolating resources is difficult with a single application; resources must be provisioned for the entire system, leading to over‑provisioning for simple tasks.

Finally, the monolith hinders experimentation with new technologies. Microservices allow each service to use the most appropriate tech stack, facilitating rapid and safe innovation.

Microservice Strategy

Adopting microservices is not trivial and can reduce engineering efficiency if done poorly. The following seven strategies helped us during the early transition:

Create new services with clear, valuable purpose.

Avoid monolithic persistent storage; treat it as a liability.

Decouple "building services" from "running services".

Ensure comprehensive and consistent observability.

Not every new service needs to be built from scratch.

Respect failures; they will happen.

Avoid "microservice syndrome" from day one.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Backend ArchitectureMicroservicesSoftware EngineeringSystem Design
Node Underground
Written by

Node Underground

No language is immortal—Node.js isn’t either—but thoughtful reflection is priceless. This underground community for Node.js enthusiasts was started by Taobao’s Front‑End Team (FED) to share our original insights and viewpoints from working with Node.js. Follow us. BTW, we’re hiring.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.