Service-Oriented Architecture (SOA) exposes business capabilities through explicit network contracts. It became common in enterprise integration because SAP, mainframes, custom applications, and later SaaS products could cooperate without sharing an implementation stack.

The service contract is the durable idea. SOAP and WSDL were common, and an Enterprise Service Bus (ESB) often handled protocol translation or routing. Neither technology is required for an architecture to be service-oriented.

SOA can separate development and ownership, but it does not guarantee independent deployment, data ownership, or scaling. Those properties depend on the service boundaries and governance model.

SOA and Microservices

ConcernTypical enterprise SOATypical microservices system
Primary pressureIntegrate heterogeneous systemsGive bounded capabilities independent ownership
Service sizeOften coarse business servicesUsually smaller bounded services
CommunicationSOAP, messaging, or mediated integrationHTTP, gRPC, or lightweight messaging
Integration logicMay live in an ESB or orchestration layerUsually stays near service endpoints or a workflow engine
DataShared enterprise stores are commonService-owned data is strongly preferred
GovernanceCentral contracts and schemasTeam-owned contracts within platform guardrails
DeploymentMay share infrastructure and release coordinationIndependent deployment is a core goal

The useful distinction is where change is controlled. Traditional SOA often centralizes integration policy. Microservices push more responsibility into independently owned services and keep transport infrastructure comparatively simple.

The ESB’s responsibilities did not disappear. Edge routing and rate limits often moved to an Software Architecture/Distributed Systems/API Gateway, asynchronous transport to a message broker, and long-running coordination to services or workflow engines. Trouble starts when business decisions collect in the integration layer and every domain change needs its approval.

When SOA Still Fits

SOA remains practical when the main job is integrating systems that cannot be changed together. A coarse customer or order service can give several business units one stable contract without forcing each legacy application into a new deployment model.

Central governance also has a place when contracts require formal audit, schema review, or protocol mediation. The trade is slower local autonomy in exchange for controlled interoperability.

Service Contract

A classic service can publish a WSDL contract. Consumers depend on that contract rather than the implementation:

<!-- WSDL-style service contract (simplified) -->
<definitions name="OrderService">
  <portType name="OrderServicePort">
    <operation name="PlaceOrder">
      <input message="PlaceOrderRequest"/>
      <output message="PlaceOrderResponse"/>
    </operation>
  </portType>
</definitions>

A REST-based service can use OpenAPI for the same boundary. Generated clients reduce hand-written protocol code, although compatibility still depends on disciplined schema evolution.

// Consumer: generated client from OpenAPI spec
// dotnet openapi add url https://orders-service/swagger/v1/swagger.json
var client = new OrderServiceClient(httpClient);
var response = await client.PlaceOrderAsync(new PlaceOrderRequest
{
    CustomerId = customerId,
    Items = items
});

The consumer should not import the service’s internal assemblies or reach into its tables. Once it does, the published contract is no longer the real boundary.

How Central Integration Goes Wrong

Business Logic in the ESB

Routing and transformation are integration concerns. Pricing rules, eligibility decisions, and order state transitions belong to the service that owns the domain. Putting them in the bus creates a second application whose ownership is usually less clear.

Shared Data Without Ownership

A shared database can be unavoidable during legacy integration. The dangerous part is shared write authority. Give each service explicit ownership of its tables or stored procedures, then expose cross-boundary behavior through contracts. Direct writes from several services turn a schema change into a coordinated release.

Contract Version Sprawl

Rigid consumers can make a harmless additive field behave like a breaking change. Prefer tolerant readers and additive evolution, record deprecation dates, and measure remaining consumers before retiring a version. A permanent collection of /v1 through /v6 endpoints is not a versioning strategy.

Central Governance as a Queue

A central contract review can protect interoperability, but it can also serialize every team behind one group. Standardize the parts that must interoperate and leave service implementation decisions with the owning team.

Coexisting with Microservices

Many estates use both styles. Existing systems meet through governed integration services, while newer product capabilities use smaller independently deployed services. The dividing line is whether stable cross-system contracts or independent product-team delivery is the stronger constraint.

Questions

References