Introduction & Context

Microservices originally started as a fine-grained architectural approach—strongly influenced by pioneering companies which led to a mix of success stories and significant criticisms.

Many teams have jumped on the microservices bandwagon, only to encounter serious complexity, spiraling operational overhead, and design failures.

The Fundamental Theorem of Software Engineering

Classic ideas in modular software design go all the way back to the late 1960s and 1970s:

Core Premise: It is easier and cheaper to manage smaller, separate pieces of software than to entangle many concerns in one large piece of software.

Modules vs. Components:

  • A module is described as a contiguous, named collection of code—traditionally a single file, a small library, or something similar—that handles one well-defined section of logic.
  • A component is a module that can be independently upgraded and replaced without forcing changes on the rest of the system.
  • Process Boundaries: Moving from in-process modules (like classes or libraries) to separate processes (i.e., “services” talking over a network) is a strong boundary. This yields both benefits (clear isolation, separate deployability) and a new layer of operational challenges (network latency, distributed systems complexity, etc.).

In essence, microservices should be viewed as a way to further strengthen these module boundaries: each service is an independently replaceable module, isolated in its own process, and communicating with other services through well-defined interfaces or messages.

What Exactly Are Microservices?

Much of the industry’s confusion arises from misunderstanding or oversimplifying the early “microservices” definition. He cites Fowler and Lewis’s seminal points:

  • Componentization via Services: Each large-scale subsystem or “bounded context” runs as its own service, invoked via interprocess communication—HTTP-based REST, RPC, or messaging.
  • Independent Deployability: One of the largest benefits is the possibility of updating or replacing one microservice without impacting others, as long as the defined service contracts remain intact.
  • Smart Endpoints, Dumb Pipes: The key logic and domain model should live inside each service, not be orchestrated by external pipelines or complex integrations.
  • Decentralized Governance: Instead of a single, top-down approach to frameworks, databases, or data schemas, teams have the autonomy to choose what best fits each service (within reason).
  • Design for Failure: Microservices are distributed. Any network call can fail, so the architecture must anticipate partial failures and maintain overall resilience.

Collectively, these points form the basis of the “microservices style,” in contrast to simply breaking a system into many tiny parts without a clear domain or operational strategy.

The Rise of Misconceptions

  1. The “Micro” in Microservices

    A primary source of trouble comes from the term “micro.” Many teams interpret “microservices” to mean an extreme push to extremely small services, each containing as little as a single function or just a few lines of code. This has led to so-called Nano Services, in which every trivial concern is split into its own container or serverless function. The result, ironically, is a hyper-fragmented “Death Star diagram,” where the number of network calls explodes, introducing:

    • High latency (dozens of calls to complete a single user-facing flow),
    • Exponential integration points (each microservice depends on many others),
    • Low cohesion, high coupling (functions that used to live together in a module now live in separate services, but are still tightly dependent),
    • Complex release cycles (because everything is so interwoven that “independent deployability” becomes a myth).
  2. “Service” Equals “Container” Syndrome

    Another common misunderstanding is the assumption that each microservice must be:

    • Its own Docker container (or some containerized equivalent),
    • Deployed separately on Kubernetes or a serverless platform,
    • Developed in a wholly independent tech stack—even if that means massive overhead for the entire system.

This may lead to situations like “serverless gone wild” or “lambda sprawl” stories, where companies end up rewriting dozens of small functions into one more cohesive service. Despite the rhetoric, this re-centralization does not spell the end of microservices. Instead, it showcases that “less distribution” can sometimes improve performance and reduce complexity, especially if you inadvertently broke your system down into slices that are too small.

When Microservices or Monoliths Are Better

Microservices are not for every team or project:

  • Team Size

    When you have only a handful of developers, the operational overhead of separate build pipelines, containers, deployment scripts, and monitoring for many small services outweighs the benefit. A well-structured monolith (or modest modular architecture) can be simpler and faster.

  • Multiple Subdomains & Rapidly Changing Business Requirements

    Large teams (30, 40, or more developers), spread across diverse business capabilities, often benefit from having separate services. Each product-based team can own a domain area (or a small set of them) end-to-end.

  • Deployment Independence

    If certain subdomains truly move at different speeds, or require distinct technology or environment changes, microservices can reduce collisions. Large single deployments (where many domains live in the same codebase) often cause big-bang release chaos.

  • Organizational Culture

    Microservices are a good match if an organization is already comfortable with decentralized governance, DevOps practices, and cross-functional teams. If everything must go through a single control board, microservices quickly devolve into painful coordination overhead.

  • Team Availability Fracture

    Splitting out a “new service” just because the existing domain owners are busy, rather than because it logically belongs in a separate bounded context. This leads to services that do almost nothing new or that replicate features in an isolated silo.

  • Excessive Synchronous Calls

    Microservices that all call each other in a chain (HTTP or RPC) can balloon latency and coupling. If possible, asynchronous communication via messaging can reduce failures from chain reactions and allow truly independent scaling.

  • Inadequate Module Boundaries

    Some microservices are essentially single classes or single functions with no real domain logic. When everything is spread out too thinly, comprehending system behavior or performing changes can become harder than it was in a monolith.

  • No Centralized Observability

    Microservices require robust logging, metrics, and distributed tracing to debug. Without it, tracking down a bug across tens or hundreds of services can be nightmarish.

Practical Recommendations

  • Right-Size Your Services

    We must emphasizes the “micro” does not have to mean microscopic. Let domain-driven design guide the boundaries: each service should revolve around a coherent subdomain or business capability

  • Embrace Modularity Before Distribution

    Teams that jump straight to dozens of network-separated processes sometimes do not even have a clean modular architecture within their code. A “modular monolith,” with well-defined internal boundaries, can reveal where splits into independent services truly make sense.

  • Adopt Asynchronous Messaging Where Possible

    Whether you use a queue-based system, events, or a broker, asynchronous designs often ensure that one service can fail or go offline temporarily without taking everything else down. It also lowers the frequency of direct, synchronous calls.

  • Invest Heavily in DevOps & Observability

    Automated builds, deployments, container orchestration, and robust telemetry (logs, metrics, traces) become critical. If these are missing, managing large numbers of microservices quickly overwhelms engineering capacity.

  • Revisit the Organizational Context

    Consider team structure, domain ownership, and communication overhead. Microservices can amplify or reduce organizational friction depending on whether your teams are prepared for autonomy and capable of supporting many production systems.

Conclusion & Takeaways

It is important to underscore that microservices, in their intended form, can still deliver on their promise of smaller, independently deployable components with clear domain boundaries. However, they bring distribution costs and amplify the need for solid architecture, meaningful domain partitioning, and strong operational tooling. Many projects that have declared “microservices are useless” likely over-split their system (leading to “nano services”), conflated containers with services, or introduced more complexity than necessary for their team size and product scope.

Rather than viewing microservices as a universal cure-all, we need to reminds us that the fundamental insights from the 1970s—about properly sized, well-encapsulated modules—remain the key to success. If your system’s “microservices” cannot be upgraded or replaced in isolation, or if every code change triggers multiple dependent deployments, you do not actually have microservices. Far from being discredited, true microservices are best leveraged when your codebase and your teams are big enough to need them, your architecture is mature enough to handle distribution, and your organization is equipped with the DevOps and domain-driven approach to support them.

Ultimately the message is not to discard microservices outright, but to use them wisely. Start with clearer domain boundaries, ensure you have the operational capacity to handle many services, and resist the temptation to break every function into its own container. When in doubt, a well-designed monolith with explicit modules can be simpler, more cohesive, and perfectly adequate—especially for smaller teams or less dynamic business contexts. Only when you genuinely need separate deployment lifecycles, specialized technologies, or truly independent domains do microservices provide their real competitive advantage.

- Comments

- Leave a Comment