From a tiny blog to a billion-user fintech platform — every major software architecture pattern used in the Go industry explained with code, diagrams, bottlenecks, real-world use cases, and decision frameworks.
Everything lives in one codebase, one binary, one process. A Go monolith might have packages like
/handlers, /services, /repository, /models — all
compiled into a single go build output. No network calls between components; they call each
other as regular Go function calls.
A well-structured monolith uses internal package boundaries to enforce modularity — the "modular monolith" variant is the best starting point for most production Go systems.
go build, one Docker imageGin/Echo/Chi router in main.go receives the request.
/handlers/order.go parses, validates request, calls service.
/services/order.go applies business rules — direct function call, zero overhead.
/repository/order.go queries PostgreSQL. Returns to handler. HTTP response.
go run commandInstead of one big Go binary, you have 10-50+ small Go binaries: order-service,
menu-service, payment-service, notification-service, each in its
own repo. They communicate via gRPC (internal) or REST (external). Each owns its own PostgreSQL
schema/database. Each can be deployed, scaled, and failed independently.
Order service places order → publishes OrderPlaced event to Kafka topic
orders.placed.
Kafka durably stores the event in ordered partition. Consumers can replay from any offset.
Kitchen, inventory, analytics, notification services each consume in parallel — at their own pace.
Kitchen service consumes OrderPlaced, produces CookingStarted.
Notification consumes that, pushes to customer.
PaymentInitiated →
fraud-detection-service consumes → FraudCheckPassed → payment-processor-service charges card
→ PaymentCompleted → ledger-service records → notification-service alerts → analytics-service
aggregates → compliance-service logs for regulators. All async, all parallel, all independently scalable.
Kafka retains 30 days of events for replay and audit.Source code dependencies must always point inward toward higher-level policy. Nothing in an inner circle can know about something in an outer circle. The domain never imports Gin. The use case never imports GORM. Outer layers implement interfaces defined by inner layers.
handler/): HTTP handlers, request parsing, response
formatting. Uses Gin/Echo.service/): Business rules, orchestration,
validation. Pure Go, no HTTP.repository/): Database access, queries, CRUD.
Hides SQL from services.domain/): Shared structs, interfaces, constants.
Used by all layers.Layered architecture allows any inner layer to depend on a lower one — including service knowing about database types. Clean Architecture enforces that domain never depends on anything. Layered is pragmatic and easier; Clean is stricter and more testable. Most Go teams start with Layered and migrate to Clean when needed.
GinHTTPAdapter,
PostgresOrderRepo, StripeAdapter
Hexagonal and Clean Architecture express the same dependency rule but with different metaphors. Hexagonal uses the hexagon shape to show that there are many equivalent sides (ports) — there's no "top" or "bottom", just inside and outside. Go's implicit interface satisfaction makes Hexagonal effortless to implement.
InMemoryAdapter — no DB, no HTTPRead and write workloads have fundamentally different needs. Writes need ACID transactions, foreign keys, strong consistency. Reads need fast aggregations, full-text search, denormalized joins, caching. CQRS lets you optimize each side independently — scale read replicas, use Elasticsearch for complex queries, Redis for hot data — without compromising write integrity.
GOARCH=amd64 GOOS=linux go build -o bootstrapGo compiles to a single native binary — no runtime, no JVM startup. Cold starts are 10x faster than Java,
2-3x faster than Python. The binary is tiny (~10MB). Go's goroutine model handles concurrent invocations
efficiently within a single container. AWS Lambda supports Go natively with the aws-lambda-go
SDK.
Modern Go teams rarely build classic SOA but may integrate with enterprise SOA systems. Go services often serve as lightweight, performant adapters to legacy SOA — exposing modern REST/gRPC endpoints while consuming legacy SOAP/XML services internally. A Go API gateway might sit in front of a Java ESB.
encoding/xml for SOAP parsing in GoOrder{ID string}. Same ID = same
entity.Money{Amount, Currency}. Equal by
value.Order containing
OrderItems.
OrderPlaced, PaymentFailed — things that
happened.Different parts of the system have different models of the same concept. In an e-commerce app, Order in the Shopping Context has cart items and discounts. Order in the Fulfillment Context has warehouse locations and picking status. Order in the Billing Context has invoice numbers and payment terms. DDD says: keep these models separate. Don't unify them.
Domain experts and developers use the same words in code. If the chef calls it a "Kitchen
Ticket" — your struct is KitchenTicket, not OrderNotification. If accountants
say "Invoice" — not "BillingDocument". This alignment reduces translation errors and makes code readable
to domain experts. In Go, package names and type names should reflect domain language exactly.
WardRound struct, not DailyVisit.
| Criteria | 🏛️ Monolithic | 🔬 Microservices | ⚡ Event-Driven | 🎯 Clean Arch | 🥞 Layered | ⬡ Hexagonal | ⚖️ CQRS | ☁️ Serverless | 🕸️ SOA | 🌐 DDD |
|---|---|---|---|---|---|---|---|---|---|---|
| Type | Structural | Deployment | Communication | Structural | Structural | Structural | Communication | Deployment | Deployment | Philosophy |
| Team Size | 1–15 | 15–500+ | Any (infra) | 5–50 | Any | 5–50 | 15–100+ | Any | 50–1000+ | 10–200+ |
| Project Size | Small Medium | Large Enterprise | Medium Large | Medium Large | Any | Medium Large | Large Enterprise | Small Medium | Enterprise | Medium Large |
| Setup Complexity | Very Low | Very High | High | Medium | Low | Medium-High | Very High | Low (FaaS managed) | Very High | Medium-High |
| Testability | ~ Integration tests | ~ Contract tests | ~ Event simulation | ✓✓ Unit + Integration | ✓ Good with interfaces | ✓✓ InMemory adapters | ~ Two sides to test | ✓ Local SAM/Invoke | ✗ ESB hard to mock | ✓✓ Domain unit tests |
| Horizontal Scaling | Limited (full copy) | ✓✓ Per service | ✓✓ Consumer groups | Depends on deploy | Depends on deploy | Depends on deploy | ✓✓ Read/write separately | ✓✓ Infinite auto | ~ Service-level | Depends on deploy |
| Fault Isolation | ✗ One crash = all down | ✓✓ Per service | ✓✓ Consumers independent | ~ Depends on deploy | ✗ Same as monolith | ~ Depends on deploy | ✓ Read/write isolated | ✓✓ Function isolation | ~ ESB = single point | ~ Context isolation |
| Data Consistency | Strong (ACID) | Eventual (Saga) | Eventual | Strong (ACID) | Strong (ACID) | Strong (ACID) | Eventual (projections) | Per-function strong | Eventually | Strong within agg. |
| Debugging Ease | Excellent | Hard (tracing needed) | Hard (event chain) | Good | Good | Good | Medium | Medium (CloudWatch) | Hard | Good (rich model) |
| Local Dev Ease | One command | Docker Compose needed | Broker needed | One command | One command | One command | Two DBs locally | SAM CLI needed | ESB locally hard | Good |
| DevOps Requirement | Minimal | Advanced (K8s, mesh) | Medium (broker ops) | Minimal-Medium | Minimal | Minimal-Medium | Medium-Advanced | Minimal (cloud-managed) | Advanced (ESB) | Minimal-Medium |
| Best For (Industry) | Startup · MVP · Blog · CMS | Uber · Netflix · Amazon | Fintech · IoT · Stock | Long-lived SaaS · Enterprise | REST APIs · ERP · CRM | Multi-protocol · DDD apps | Search · Reporting · Analytics | Webhooks · Scheduled jobs | Banks · Telcos · Gov | Complex domain · Healthcare |
| Go Frameworks/Tools | Gin, Echo, Chi, GORM | gRPC, Consul, K8s | Kafka-go, NATS, RabbitMQ | Any (framework-agnostic) | Gin, Echo, sqlx | Any (clean interfaces) | Elasticsearch, Redis | aws-lambda-go, GCF SDK | encoding/xml, SOAP libs | Any + domain packages |
| ERP Suitability | ~ Early stage | ✓ Large ERP | ~ Events addon | ✓✓ Ideal structure | ✓✓ Very common | ✓ Good | ✓ Reporting module | ✗ Not suitable | ✓ Integration layer | ✓✓ Ideal for complex |
| Fintech Suitability | ~ Only small scale | ✓✓ Per-domain services | ✓✓ Transaction events | ✓✓ Auditable clean code | ✓ Good baseline | ✓✓ Swap payment providers | ✓✓ Reporting + transactions | ~ Specific functions | ✓ Legacy integration | ✓✓ Rich financial domain |
| SaaS Suitability | ✓✓ Early SaaS | ✓ At scale | ~ Feature-specific | ✓✓ Best for longevity | ✓✓ Default choice | ✓ Good | ~ When needed | ✓ Background tasks | ✗ | ✓ Complex domains |
| Overall Complexity | ★☆☆☆☆ | ★★★★★ | ★★★★☆ | ★★★☆☆ | ★★☆☆☆ | ★★★☆☆ | ★★★★★ | ★★☆☆☆ | ★★★★★ | ★★★★☆ |