The correlation when building anything; Go
The correlation when building anything
Every server you ever build has exactly three layers:
LAYER 1 DATA
"what do I store and how?"
-> your Log, your Database, your Cache
-> pure Go structs, no HTTP, no network
LAYER 2 BUSINESS LOGIC
"what can I do with the data?"
-> Append, Read, Delete. Run logic to get/derive result
-> still no HTTP, just functions on your data
LAYER 3 TRANSPORT
"how does the outside world talk to my logic?"
-> HTTP, gRPC, CLI
-> unmarshal -> call layer 2 -> marshal backThe correlation is each layer only knows about the layer below it, never above. Layer 3 calls Layer 2. Layer 2 calls Layer 1. Layer 1 knows nothing about HTTP.
- HTTP knows nothing about your Log
- Your Log knows nothing about HTTP
- Business logic sits in the middle, clean
The code is clean. And tomorrow when we swap HTTP for gRPC. Log doesn't change at all. Only Layer 3 changes. That's the payoff of the design. Interesting isn't it.
In http.go + log.go:
Layer 1 -> Log struct (log.go)
Layer 2 -> Append(), Read() methods
Layer 3 -> http.go the bridge between net/http and your logicEvery decision in chapter 1 is a question answered. once you see the questions, the code writes itself.
1. what am I building? -> a log, append-only, ordered by time
2. what does it need? -> store records, give them back by offset
-> define Record, define Log
3. what type for offset? -> never negative -> uint64
-> "make illegal states unrepresentable"
4. concurrent access? -> multiple goroutines -> RWMutex
-> reads share, writes exclusive
5. how does outside -> HTTP server
world reach it? -> two routes: produce, consume
6. how do routes reach -> httpServer struct carries the Log
the Log? -> handlers are methods on that struct
7. public or private? -> NewHTTPServer public (world uses it)
-> newHTTPServer private (internal setup)
8. pointer or value? -> big structs, shared state -> pointers