Go architectures · 3 MIN READ
Microservices: pay for independent ownership
Extract a remote boundary only when its independence is valuable.
Extract a remote boundary only when its independence is valuable. A microservice owns a business capability, its data and its deployment. 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
- Caller sets a deadline
- Remote service owns its contract and data
- Caller handles a partial failure
Useful when
- Teams need independent deployment and isolation
- A capability has distinct scaling requirements
Watch out
- Network and data consistency costs are ongoing
- Shared releases can create a distributed monolith
Implementation & operation cost: Very 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
A microservice owns a business capability, its data and its deployment. A Go package boundary is cheap; a service boundary adds timeouts, partial failures and contract evolution. Splitting one synchronous call chain into many processes can create a distributed monolith.
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 (
"context"
"errors"
"fmt"
)
type Inventory interface {
Available(context.Context, string) (bool, error)
}
type OfflineInventory struct{}
func (OfflineInventory) Available(ctx context.Context, id string) (bool, error) {
return false, errors.New("inventory unavailable")
}
func CanShip(ctx context.Context, inventory Inventory, id string) error {
ok, err := inventory.Available(ctx, id)
if err != nil {
return fmt.Errorf("check inventory: %w", err)
}
if !ok {
return errors.New("out of stock")
}
return nil
}
func main() {
fmt.Println(CanShip(context.Background(), OfflineInventory{}, "book"))
}
// Output:
// check inventory: inventory unavailable
The dependency contract distinguishes a business answer from a failed lookup. The fake models a remote failure deterministically without opening a socket. A real adapter must add deadlines, authentication and response validation rather than treating failure as zero stock.
Tradeoffs and the simpler alternative
Independent ownership helps teams with different release and scaling needs. It also requires tracing, deployment automation and data consistency design. Start with a modular monolith when one team can operate it; high request volume alone is not a service-count target.
Draw ownership and data boundaries first
A service owns a capability, its durable data and an operational responsibility. Sharing one database schema across independently deployed services often preserves tight coupling while adding network failures. Define the public API or event contract and the team that can evolve it. Prefer coarse business boundaries over a service per table. A modular monolith is a useful starting point when the same small team owns all capabilities and coordinated releases are acceptable.
Budget for partial failure
A request may time out after the remote effect succeeds. Bound the total deadline, propagate cancellation, make retryable mutations idempotent and avoid retries at every layer. Keep cross-service transactions out of local transaction assumptions: model pending work, reconciliation or compensations explicitly. A circuit breaker can protect a struggling dependency but does not correct invalid data or guarantee delivery. Separate authentication from service authorization and protect both transport and business operations.
Plan extraction and rollback
Choose one capability whose independent scaling, release cadence or fault isolation is measured to matter. Put an adapter behind its current contract, move ownership deliberately and define the migration source of truth. Shadow read traffic can compare results without duplicating mutations. Test backward-compatible API changes before rolling out producers and consumers separately. Observability, deploy automation, secrets, on-call and recovery are part of the design cost, not optional work after the code has been split.
TAKE THIS WITH YOU
Adds independent ownership and partial remote failures. Independent ownership helps teams with different release and scaling needs. It also requires tracing, deployment automation and data consistency design. Start with a modular monolith when one team can operate it; high request volume alone is not a service-count target.
Check your understanding
Which statement best describes Microservices: pay for independent ownership?
Go to the source
Progress stays in this browser. No account needed.