Understanding Service-Oriented Architecture
There’s a reason SOA became a punchline in the 2010s. The ESB projects that were supposed to unify the enterprise instead became black holes: expensive, slow, and perpetually almost working. When microservices arrived, they were positioned as the antidote — and for many teams, they were. But dismissing SOA as simply “old microservices” misses what the pattern was actually trying to solve, and more importantly, what it still solves well today.
SOA and microservices aren’t two points on the same spectrum. They’re different tools designed for different problems. Mark Richards puts it best: the difference between SOA and microservices isn’t apples and oranges. It’s apples and kittens.
Enterprise Scope, Not Application Scope
The first thing that separates SOA from almost every other architecture pattern is its scope. Microservices, layered architecture, pipeline, space-based — these are all built around applications. SOA is built around the enterprise.
That’s not a small distinction. SOA was designed to integrate heterogeneous systems and applications across an entire organization, or across a significant domain within it. When you have six insurance divisions, each running their own legacy systems, each storing customer records in inconsistent formats — that’s the problem SOA was invented to solve.
Think of an insurance company where a customer holds policies across auto, commercial, life, disability, and travel divisions. When that customer moves and calls to update their address, the representative can only update one record. The customer has to call five different numbers to reach the other divisions. Every system stores the address differently. Some have “East Street,” some have “E. Street,” some have “East null Street.” This is the shared resource problem, and SOA’s answer to it was to centralize that customer information into a unified enterprise service that all divisions could access consistently.
That’s a fundamentally different problem than “how do we deploy faster” or “how do we scale checkout independently from inventory.” Those are application-level problems. SOA plays at a higher altitude.
The Service Taxonomy
One of SOA’s defining characteristics is its formal taxonomy of service types — something microservices deliberately avoids. Where microservices has no prescribed service classification, SOA organizes everything into four tiers.
Business services sit at the top. These are coarse-grained, abstract definitions of what the organization does. They’re typically defined by business users and describe inputs, outputs, and high-level processing steps. A useful litmus test: ask whether the organization is in the business of doing this thing. “Creating an auto quote” — yes. “Creating a customer” — no, that’s plumbing for creating a quote. Business services answer the “are we in the business of X” question affirmatively.
Enterprise services live below the integration hub. These are concrete, coarse-grained services owned by shared services teams or architects. A single business service can invoke one or many enterprise services. There’s no specified granularity here — an enterprise service might be a handful of classes, or it might be an entire claims processing subsystem. What matters is that it’s available across the enterprise and owned by a team responsible for it at that level.
Application services are fine-grained and bound to a specific application context. Where enterprise services represent broad organizational capabilities, application services are the discrete operations that implement them: Add Driver, Add Vehicle, Validate Policy. They’re owned by application teams and typically invoked by enterprise services.
Infrastructure services round out the taxonomy — auditing, logging, security, and other cross-cutting concerns that both enterprise and application services consume.
What’s striking about this taxonomy is that each tier has a different owner. Business users own business services. Shared services teams own enterprise services. Application teams own application services. Infrastructure teams own infrastructure services. This creates significant coordination overhead — making any change involves multiple teams across multiple layers — which is why SOA’s agility scores are low. But it’s also why SOA can integrate systems that would otherwise never communicate.
The Enterprise Service Bus: Power and Pathology
The integration hub — also called an ESB, messaging middleware, or enterprise service bus — is the central nervous system of SOA. Everything flows through it. This is what makes SOA’s capabilities possible and what makes it operationally painful.
The ESB enables three things that nothing else in this series does quite as well.
Protocol-agnostic heterogeneous interoperability. Microservices require all services to agree on a protocol. Everyone speaks REST, or everyone uses the same message queue format. SOA removes that constraint. The ESB handles protocol transformation, so a Java service calling via AMQP can reach a C++ service using ATMI without either side knowing or caring about the other’s protocol. This is protocol-agnostic interoperability — genuinely different from microservices’ protocol-aware model — and it’s essential when you’re integrating systems that were built decades apart.
Contract decoupling. This one is underrated. SOA was designed around the principle that the business should define how it does business, and IT should adapt — not the other way around. The integration hub handles the transformation between what the business defines (a SKU number, a date in MM/DD/YY format) and what the underlying enterprise service expects (an internal product ID, a date in Oracle YYYY.MM.DD format). The business doesn’t change how it operates to satisfy an IT constraint. The ESB adapts. This is contract decoupling, and it lets business services, enterprise services, and application services all evolve independently without breaking each other.
Abstraction layers. SOA introduces multiple levels of abstraction between consumers and implementations. Business services call an integration hub, which routes to enterprise service APIs, which call another integration hub, which reaches application service APIs, which sit on top of the actual legacy systems. This is verbose — “usually with SOA, we’re SOL” is a genuine joke in the source material — but it’s also what enables incremental modernization. When you swap out that C++ legacy system for a new microservice and update only the integration hub fronting its API, nothing else in the enterprise changes. The rest of the ecosystem is completely unaware the migration happened.
The Trade-off Profile
SOA’s characteristics ratings read like a cautionary tale if you apply an application-scope lens to them — which is part of why the pattern has a bad reputation. But they make more sense in context.
Agility is low. Making a change requires coordinating business users, shared services teams, application teams, and infrastructure teams. That’s not a design flaw so much as the inherent cost of operating at enterprise scope. The complexity of what you’re trying to integrate is real; SOA just makes that complexity explicit.
Deployment risk is mixed. The abstraction layers actually help here — you can test your piece in isolation, validate your contract decoupling, and deploy without touching the rest of the ecosystem. But the coverage problem is genuine. A service shared across the enterprise has an enormous surface area of possible callers, and testing all those scenarios comprehensively is very difficult.
Performance suffers because of the abstraction layers. Every additional hop through an integration hub adds latency. If you’re building something with tight performance requirements, you’re fighting the pattern.
Testability is challenging for similar reasons — the incompleteness of coverage, not necessarily the difficulty of testing any individual component.
And cost is very high. SOA and space-based architecture sit at the top of the cost scale. The ESB products, the team coordination, the governance overhead — it adds up. This is enterprise infrastructure, priced accordingly.
When to Use It — And How to Use It to Move Away from It
SOA is for enterprises managing heterogeneous, legacy-laden landscapes. If you have systems built in COBOL, C++, Java, and .NET that all need to exchange data and participate in shared business processes, SOA gives you the integration layer to make that happen without a rip-and-replace project that would take a decade and cost a fortune.
The more interesting use case is SOA as a migration vehicle. Because the abstraction layers hide implementation details from consumers, you can use SOA to incrementally modernize legacy systems. The C++ application gets a REST-based microservice replacement. The integration hub fronting it gets updated to route to the new service. Nothing else changes. The business service that calls through the ESB never knew the underlying implementation changed.
This is genuine value — using layers of abstraction not as permanent complexity but as seams that let you evolve one piece at a time without breaking everything else.
The Conway’s Law Problem
There’s a structural risk in mediator-heavy architectures that applies directly to SOA: Conway’s Law.
Conway’s Law states that the communication structure of an organization will be reflected in the technical artifacts it produces. As soon as you centralize business process orchestration in an ESB, you also create a team of integration architects who own that ESB. Every business process flows through both the technical hub and the human team around it. That team becomes a bottleneck — not through incompetence, but through inevitability. The architecture demanded their existence, and their existence constrains the architecture.
This is what people experienced in the 2000s and early 2010s with ESB-heavy SOA implementations. The integration team couldn’t scale to match the demand from every application team that needed something integrated. Tickets piled up. Timelines slipped. The ESB that was supposed to free teams from integration complexity instead became the single most expensive queue in the organization.
Understanding this dynamic doesn’t mean avoiding SOA. It means planning for it deliberately — keeping the ESB’s scope bounded, resisting the temptation to route every business workflow through it, and treating the integration team’s capacity as an architectural constraint.
SOA Is Not SOA Lite Microservices
The most persistent misconception about these two patterns is that microservices replaced SOA, or that microservices are just a lighter version of the same idea. They’re not.
Microservices solve an application-scope problem: how do you build a system that’s independently deployable, independently scalable, and organized around bounded business contexts? The answer involves fine-grained services, separate databases per service, no shared middleware, and protocol-aware communication.
SOA solves an enterprise-scope problem: how do you get twenty heterogeneous systems, built across four decades, to participate in unified business processes? The answer involves a formal service taxonomy, a protocol-agnostic integration hub, contract decoupling, and abstraction layers that isolate evolution from disruption.
These are different problems. The fact that both use the word “service” is where the confusion starts and ends.
If you’re building a new product and want agility and independent deployability, microservices is the right conversation. If you’re managing a heterogeneous enterprise landscape and need to integrate legacy systems without rewriting everything, SOA’s capabilities are genuinely hard to replicate with anything else.
Part of a series based on the O’Reilly Software Architecture Fundamentals course by Mark Richards and Neil Ford. Not sponsored or affiliated — just a resource I genuinely find useful. If you want to go deeper, O’Reilly Learning offers a 10-day free trial with access to courses, books, and hands-on labs.





