Microservices are often adopted as an identity: “we are a microservices shop.” I prefer a meaner question: what hurts when it is coupled? Commerce platforms I have led or built, gateway + auth + domain services + Shopify apps + Terraform, only stay sane when splits follow pain.
The wrong reason to split
Splitting because “that is what scalable companies do” creates a distributed monolith: many repos, one conceptual blob, slower delivery. Network calls replace function calls without reducing cognitive load.
The right reasons show up in the calendar
Good split signals:
- Different deploy cadences (POS app weekly, billing rules rarely)
- Different scale profiles (order bursts vs user profile reads)
- Different compliance/sensitivity (auth tokens vs public catalog reads)
- Different teams owning outcomes
- Failure isolation needs (catalog sync outage must not take checkout admin down)
I have seen suites with users, locations, orders, business rules, API gateway, and POS as separate services. That works when each service has a clear noun and a clear owner. It fails when every feature needs four coordinated deploys and a shared spreadsheet of env vars.
Gateways do not remove coupling
An API gateway microservice can centralize authn/z and routing. It can also become a second monolith if all business logic leaks upward. Keep gateways thin. Push domain rules down. Otherwise you have reinvented a BFF that nobody can change safely.
Data is the real distributed system
The hardest microservice problem is not HTTP. It is data ownership:
- Whose database holds the source of truth for a location?
- How do order services learn user identity without chatty auth calls?
- What is replicated vs queried synchronously?
- How do you migrate a shared database when services were split in name only?
Shared RDS across many Shopify apps can be pragmatic. Shared tables casually written by five services is a trap. Be explicit about ownership even when the physical database is shared.
Infrastructure must match the topology
Terraform maps for ECS services, or Lightsail containers per service, make independent deploys possible. Without that, “microservices” are folders in a mono-deploy. Pipelines, image repos, and health checks per service are part of the architecture, not DevOps leftovers.
Event-driven edges soften the graph
Lambdas for webhooks, inventory sync, fulfillments, and reports let the core services avoid absorbing every spike. But events add their own complexity: ordering, idempotency, poison messages, schema evolution. You are trading one kind of coupling for another. Do it deliberately.
A practical heuristic I use
Before splitting a service, write one paragraph:
If this stays in the monolith, what becomes slow, risky, or politically blocked? If we split it, what new failure mode do we accept?
If nobody can answer, do not split yet. Modular boundaries inside one deployable often buy 80% of the benefit at 20% of the cost, until pain proves otherwise.
Microservices are a response to organizational and operational complexity. They should not be the source of it.
