Go architectures · 3 MIN READ

Choose a style; keep the code easy to change

Compare a modular monolith, layered design and microservices using concrete operational tradeoffs.

Architecture is a choice about boundaries, change and failure. A modular monolith can keep strong internal boundaries with one deployment. Microservices can separate ownership and release schedules, but add remote calls, distributed failures, versioning and operational work.

Architecture decision guide · A MAP OF THE IDEA

  1. State the quality goal and constraints
  2. Compare ownership, consistency and deployment costs
  3. Record a decision and a measurable revisit trigger

Useful when

  • A team needs to explain why a style fits
  • Architecture should evolve with evidence

Watch out

  • Ratings are editorial starting points, not benchmarks
  • DDD, CQRS and deployment styles describe different axes

Implementation & operation cost: Depends on the chosen style

01

Choose the smallest useful distribution boundary

A small team sharing one transaction model may benefit from one deployable process with cohesive packages. Separate services become useful when independent scaling, ownership or delivery outweighs coordination costs. A folder named services does not make a monolith distributed, and a network hop does not make a boundary clean.

02

Make the normal path visible

Early returns keep a short function focused on its successful operation. Names should explain domain meaning; return errors at the layer able to add useful context. Avoid a generic helper that hides the important policy decision from its caller.

go
func Ship(order Order) error {
    if order.Cancelled {
        return ErrCancelled
    }
    if !order.Paid {
        return ErrUnpaid
    }
    return reserveShipment(order)
}
Read the code

This fragment makes the ordering of policy checks explicit. The real operation still needs an atomicity and idempotency contract if reservation changes external state. Shorter code is not cleaner when it conceals those obligations.

03

Use a change-oriented checklist

Ask whether one business change requires edits across unrelated packages; whether error ownership is clear; whether interfaces have real consumers; and whether tests describe observable behavior instead of private function calls. Keep formatting with gofmt, document surprising contracts, and remove abstractions that do not pay for their indirection. No architecture style eliminates concurrency, capacity or consistency tradeoffs.

04

Compare decisions on the same axis

Monolith and microservices describe deployment and ownership boundaries. Layered, hexagonal, Clean and Onion describe responsibility and source dependencies. Vertical slices organize change around features; MVC organizes presentation. DDD is a modeling approach, CQRS separates write and read models, and event sourcing chooses a state history as authority. A modular monolith can use hexagonal ports, vertical slices and CQRS together. Record the quality goal before comparing scores.

05

Separate three architecture questions

First choose code organization: packages by capability, layers or vertical slices. Next choose state coordination: local transactions, asynchronous events or event history. Finally choose deployment topology: one executable, functions or independent services. These are different axes. A modular monolith can use hexagonal boundaries and CQRS; a microservice can still have tangled internal code. Describe the constraint a choice solves before comparing editorial ratings. Scores are scenario-specific recommendations, not performance measurements.

06

Write an architecture decision with an exit condition

A useful decision record contains the workload, team ownership, correctness requirements, candidate approaches, chosen tradeoff and what evidence would reopen the decision. For a small team, one deployable with local transactions may beat independently deployable services despite an ambitious diagram. Revisit when measured scaling, fault isolation or team release independence becomes a constraint. Do not migrate because a style receives a higher score in a different scenario.

07

Make quality visible at the seams

Review one request from input validation to durable effect and response. Who owns the transaction? Who retries? Where is authorization enforced? Which boundary receives a deadline, and which log identifies the operation without exposing credentials? Then inspect tests at these seams. Small functions alone cannot repair contradictory ownership or undefined failure recovery. Prefer the simplest architecture that makes the required guarantees testable and operationally understandable.

TAKE THIS WITH YOU

Choose boundaries for real change and ownership needs. Clear names, explicit errors, narrow contracts and behavioral tests matter in every architecture style.

Check your understanding

Which statement is correct about a modular monolith?

Go to the source

Progress stays in this browser. No account needed.