Go architectures · 3 MIN READ
Simple monolith: start with one executable
Keep a small application understandable without premature service boundaries.
Keep a small application understandable without premature service boundaries. A command-line invoice tool can parse input, compute a result and print it in one process. 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
- Input at main
- Local calculation
- Result in the same process
Useful when
- A small team ships one useful workflow
- Local calls and one deployment keep debugging direct
Watch out
- A growing main package can mix unrelated responsibilities
- One release coordinates every component
Implementation & operation cost: Low
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 command-line invoice tool can parse input, compute a result and print it in one process. Functions can separate these responsibilities before packages or network services become useful. One deployment is an operational choice; it does not require one giant function or prevent later modules.
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 (
"fmt"
"strconv"
)
func total(raw string) (int, error) {
n, err := strconv.Atoi(raw)
if err != nil {
return 0, err
}
return n * 12, nil
}
func main() {
n, err := total("3")
if err != nil {
fmt.Println("invalid quantity")
return
}
fmt.Println(n)
}
// Output:
// 36
The entry point decides how to report failure; total only parses and computes. The result is 36. There is no remote call, queue or dependency container because this variation has not appeared in the problem.
Tradeoffs and the simpler alternative
Start splitting when different responsibilities change independently or teams need ownership boundaries. A simple monolith can scale through replicas; shared mutable state and database contention still need measurement. Avoid hiding every function behind an interface.
Build one process with explicit composition
Keep main responsible for configuration, dependency construction, startup and graceful shutdown. Pass dependencies into handlers rather than hiding them in package globals. Place use cases behind package APIs even if there is only one executable. This retains fast local calls and a single operational unit while allowing multiple entry points later. A monolith describes deployment; it does not require a single package or prevent good isolation inside the process.
Use local transactions as a strength
Order creation and inventory reservation can commit in one database transaction when they share a consistency boundary. Validate cheap input before opening that transaction, avoid network calls while holding locks and roll back on every failure path. A successful HTTP response should follow the required durable commit, not precede it. If an email must eventually follow the commit, record an outbox item atomically and process it later; sending email first cannot be rolled back with the database.
Scale only the measured bottleneck
Measure request latency, database time, queue depth and memory before extracting services. A process can have multiple replicas and background workers while remaining a monolith, provided shared state is durable and concurrency-safe. Start by improving indexes or isolating a slow worker. If one capability later needs independent deployment, keep its existing API and extract behind that seam. Expect remote timeouts and partial failure to become new work after extraction.
TAKE THIS WITH YOU
One process with explicit local responsibilities. Start splitting when different responsibilities change independently or teams need ownership boundaries. A simple monolith can scale through replicas; shared mutable state and database contention still need measurement. Avoid hiding every function behind an interface.
Check your understanding
Which statement best describes Simple monolith: start with one executable?
Go to the source
Progress stays in this browser. No account needed.