Go architectures · 3 MIN READ
SOA and RPC: stable service contracts
Compare service-oriented integration with smaller independently owned services.
Compare service-oriented integration with smaller independently owned services. Service-oriented architecture organizes reusable business capabilities behind contracts, often across existing enterprise systems. Trace the worked Go example, then compare the benefit with the cost before applying this design to your own project.
Architecture · A MAP OF THE IDEA
- Consumer sends a defined request
- Service enforces its contract
- Consumer interprets a defined result
Useful when
- Existing systems need explicit integration boundaries
- Capabilities are reused across several applications
Watch out
- Shared contracts need compatibility management
- Centralized orchestration can become a bottleneck
Implementation & operation cost: High
Fit depends on the task
Editorial suitability, not benchmarks or a universal ranking. Styles describe different axes and can be combined.
The design decision
Service-oriented architecture organizes reusable business capabilities behind contracts, often across existing enterprise systems. Neither SOA nor RPC requires a particular protocol. A contract needs explicit units, failure semantics and version rules regardless of JSON or generated stubs.
A complete Go example
Read this program from the entry point and follow the calls shown in the diagram. The output is included at the end so you can check the behavior without a compiler.
package main
import (
"errors"
"fmt"
)
type QuoteRequest struct{ WeightGrams int }
type QuoteResponse struct{ PriceCents int }
func Quote(req QuoteRequest) (QuoteResponse, error) {
if req.WeightGrams <= 0 {
return QuoteResponse{}, errors.New("weight required")
}
return QuoteResponse{PriceCents: 500 + req.WeightGrams/10}, nil
}
func main() {
result, err := Quote(QuoteRequest{WeightGrams: 200})
fmt.Println(result.PriceCents, err)
}
// Output:
// 520 <nil>
The request and response encode units in field names. The example uses a local function so the contract is visible without transport code. An RPC adapter would still need to distinguish validation errors, deadline expiry and unavailable dependencies.
Tradeoffs and the simpler alternative
Broad shared services can reduce integration duplication but become release bottlenecks. Avoid a universal service that owns every domain. Microservices emphasize independent capability ownership; SOA is a broader service integration approach, so real systems can share ideas from both.
Design an API contract for independent clients
An RPC method should express a stable business operation rather than expose a database row shape. Define identifiers, validation, cancellation and error categories, along with message evolution rules. Adding an optional field may be compatible while changing its meaning is not. Keep generated transport types at the adapter boundary if their evolution should not dictate the domain model. An interface in Go is a local language contract; it does not automatically provide a versioned remote protocol.
Make timeout ambiguity explicit
If a client times out on Reserve, it may not know whether a reservation exists. A stable operation ID allows retry or status lookup without repeating the effect. Set one deadline and distinguish validation failure, denied access, missing resource and transient service failure. Avoid returning unbounded result lists; pagination and resource budgets belong in the contract. Streaming APIs also need backpressure and a shutdown policy.
Verify mixed-version deployment
Run contract fixtures against old and new request shapes. Test that a server accepting a new field still handles older callers, and that clients tolerate allowed unknown fields according to the protocol. Record latency and error rate per operation without logging credentials or whole sensitive payloads. RPC or service-oriented integration can centralize a genuine shared capability, but a synchronous dependency on many services can become a distributed call chain with poor availability.
TAKE THIS WITH YOU
Defines units, outcomes and compatibility at a boundary. Broad shared services can reduce integration duplication but become release bottlenecks. Avoid a universal service that owns every domain. Microservices emphasize independent capability ownership; SOA is a broader service integration approach, so real systems can share ideas from both.
Check your understanding
Which statement best describes SOA and RPC: stable service contracts?
Go to the source
Progress stays in this browser. No account needed.