← All posts
Tech 18 Dec 2025 8 min read

The real cost of a microservice

The standard pitch for microservices is organizational agility: independent deployability, autonomous team ownership, and isolated fault domains.

What architectural conference talks rarely mention is that introducing a network boundary between two pieces of logic replaces simple in-memory function calls with the full taxonomy of distributed systems failures: network timeouts, serialization overhead, eventual consistency races, and cascading retry storms.

The latency tax of the network hop

An in-process method call takes under 10 nanoseconds. An inter-service RPC over gRPC/HTTP within the same AWS availability zone takes 1.5 to 3.5 milliseconds—a \(300,000\times\) latency penalty.

When a single user request fans out into a call graph with a depth of 6 services, your latency budget is consumed entirely by TCP handshakes, TLS termination, and JSON/Protobuf marshaling.

// Transactional Outbox Pattern in Go: Atomic state + event persistence
func (s *OrderService) CreateOrder(ctx context.Context, order Order) error {
    tx, err := s.db.BeginTx(ctx, nil)
    if err != nil {
        return err
    }
    defer tx.Rollback()

    // 1. Insert domain state
    if err := s.insertOrder(tx, order); err != nil {
        return err
    }

    // 2. Insert outbox event in identical local ACID transaction
    outboxPayload, _ := json.Marshal(order)
    if err := s.insertOutbox(tx, "OrderCreated", outboxPayload); err != nil {
        return err
    }

    return tx.Commit()
}
Every microservice boundary you draw is a distributed transaction problem you have chosen to solve with asynchronous message queues.

The death of ACID: Sagas and Outbox patterns

In a monolith, transferring money or updating an inventory balance is an atomic SQL transaction: BEGIN; ... COMMIT;. If the server crashes mid-flight, the database engine guarantees zero data corruption.

Once inventory and billing are split into separate services with separate databases, atomic transactions are impossible without slow two-phase commit (2PC) locks. You are forced to implement:

When decomposition actually pays off

Microservices are not an engineering optimization; they are an organizational mechanism for companies with 150+ engineers where merge conflicts and release coordination on a single codebase become unbearable.

If your engineering team has fewer than 25 developers, a well-factored modular monolith running on a single Postgres cluster will ship features 5× faster with 90% fewer late-night on-call incidents.


Refactoring microservice boundaries or designing outbox pipelines? Reach out.