Phase 1: Go Fundamentals (Days 1–30)
Phase Goal: Go from "I can read Go" to "I can write Go without looking things up." This is the foundation. Don't rush it.
Week 1: Go Syntax, Types & Functions (Days 1–7)
Why this week matters: Every Go service you'll build — microservice, proxy, security middleware — starts here. Writing and reviewing Go confidently requires fluency in these basics.
Day 1 — Go toolchain & your first program
- Why: Understanding
go build,go run,go test,go modis what you'll reference when engineers say "it works locally" - Topic: Install Go, workspace setup,
go mod init,package main,func main(),fmt.Println - Exercise: Write a program that prints a formatted system info report: current time, hostname (
os.Hostname), number of CPUs (runtime.NumCPU), Go version (runtime.Version) - Key packages:
fmt,os,runtime,time
Day 2 — Variables, types & zero values
- Why: Go's type system prevents a whole class of bugs you'd otherwise debug at runtime in dynamic languages
- Topic:
var,:=, basic types (string,int,bool,float64), zero values, type conversion,const,iota - Exercise: Build a unit converter: convert between MB/GB/TB, ms/s/min. Use typed constants with
iotafor units. No hardcoded magic numbers.
Day 3 — Functions & multiple return values
- Why: Go's
(value, error)return pattern is in every library call. Understanding it is essential for reading Go code - Topic: Function syntax, multiple return values, named returns, variadic functions, first-class functions
- Exercise: Build a
parseConfig(input string) (Config, error)function that parseskey=valuepairs. Return structured errors. Write 5 test cases withif err != nilhandling.
Day 4 — Slices & maps
- Why: These are the workhorse data structures in 90% of Go code. Misuse causes production memory leaks
- Topic: Slice internals (len/cap),
append, slice of slice, map operations, nil vs empty slice/map, iteration withrange - Exercise: Build an in-memory request log: store last 1000 requests (IP, path, status, latency) in a slice with a fixed-size ring buffer. Query by IP using a map index.
Day 5 — Structs & methods
- Why: Go uses structs + methods instead of classes. Every service, every config, every request object is a struct.
- Topic: Struct definition, field tags, methods with value vs pointer receivers, struct embedding, anonymous fields
- Exercise: Model a
Serverstruct with config fields. Add methods:Start(),Stop(),Status() string. Use pointer receivers. Embed aLoggerstruct.
Day 6 — Interfaces
- Why: Go interfaces enable the pluggable, testable architectures your best engineers design. Understanding them helps you spot good vs bad design in PRs
- Topic: Interface definition, implicit satisfaction,
interface{}(any), type assertions, type switches - Exercise: Define a
Storageinterface withSet(key, value string),Get(key string) (string, bool),Delete(key string). Implement it with an in-memory map. Write aCachedStoragethat wraps anyStorageand adds metrics.
Day 7 — Error handling
- Why: Go's explicit error handling is why Go services tend to be more reliable. Knowing the patterns helps you require them in code review
- Topic:
errorinterface,errors.New,fmt.Errorf,errors.Is,errors.As, wrapping with%w, sentinel errors - Exercise: Build a multi-layer error system for the storage from Day 6:
ErrNotFound,ErrStorageFull,ErrInvalidKey. Each wraps context. Write a handler that distinguishes each error type.
Week 1 Mini Project: Configuration Server
- Build an HTTP server (
net/http) that serves runtime config as JSON - Endpoints:
GET /config(return all config),PUT /config/{key}(update a value),GET /health(return status + uptime) - Use a struct for config, interface for storage, proper error responses
- Key packages:
net/http,encoding/json,os,time - Engineer Takeaway: This is the skeleton of every internal CLI and admin tool. You can now choose deliberately between
varand:=, and between pointer and value receivers.
Week 2: Control Flow, Packages & Testing (Days 8–14)
Why this week matters: Go's testing story is one of its strongest features. By end of week you'll write tests the way your senior engineers do.
Day 8 — Control flow
- Why: Understanding
deferexplains a lot of "why does this cleanup always run?" patterns in Go servers - Topic:
if/else,switch(no fallthrough by default),for(only loop in Go),break/continue,defer(LIFO, arguments evaluated immediately),goto(avoid) - Exercise: Write a request lifecycle simulator:
defercleanup functions in the right order (close body → release connection → log → decrement counter). Observe execution order.
Day 9 — Packages & modules
- Why:
go modand package structure drive how Go code is organized. Knowing this lets you lay out a repo that scales past one package - Topic: Package naming, exported vs unexported,
go.mod,go.sum, internal packages,init()function, circular imports (why Go forbids them) - Exercise: Refactor the Week 1 mini project into proper packages:
config/,storage/,server/,health/. Each package has one clear responsibility. No circular dependencies.
Day 10 — Testing in Go
- Why: Go has testing built in — no framework needed. Understanding
go testhelps you set coverage requirements - Topic:
testing.T, table-driven tests,t.Runsubtests,t.Helper, test file naming,-runflag,-vflag - Exercise: Write table-driven tests for the storage interface from Day 6. Cover: empty key, value too long, concurrent reads, delete non-existent key. Run with
-vand-count=3.
Day 11 — Benchmarks & examples
- Why: Benchmark-driven performance discussions beat intuition. Knowing how to read benchmarks changes how you evaluate "it's slow" reports
- Topic:
testing.B,b.N,b.ResetTimer,b.ReportAllocs,go test -bench,go test -benchmem, example functions - Exercise: Benchmark three implementations of the same lookup: linear scan slice, map lookup, sorted slice + binary search. Report ns/op and allocs/op. Which wins at 100 items? At 10,000?
Day 12 — Goroutines (introduction)
- Why: Go's concurrency model is why Go handles high traffic efficiently. This is the single most important Go concept for a networking/security stack
- Topic:
gokeyword, goroutine lifecycle, the fact that goroutines are not OS threads,runtime.NumGoroutine(), goroutine leaks - Exercise: Write a program that starts 1000 goroutines, each sleeping for a random duration. Count active goroutines with
runtime.NumGoroutine()every 100ms. Observe the ramp-up and drain. Ensure all goroutines exit cleanly.
Day 13 — Channels
- Why: Channels are how Go goroutines communicate safely. This pattern appears in every concurrent server you'll write
- Topic: Make channel, send/receive, buffered vs unbuffered,
close,rangeover channel,select,default - Exercise: Build a job queue: producer goroutine sends jobs into a buffered channel; 5 worker goroutines consume and process jobs; a results channel collects outcomes. Print summary when all done.
Day 14 — sync package
- Why:
sync.Mutexandsync.WaitGroupare in every Go service. Misuse causes deadlocks. Knowing them helps you spot issues in review - Topic:
sync.Mutex,sync.RWMutex,sync.WaitGroup,sync.Once,sync.Map - Exercise: Implement a thread-safe request counter: tracks requests per endpoint, reads are frequent (use
RWMutex), resets happen rarely. Write a concurrent test with 100 goroutines hammering it. Run with-race.
Week 2 Mini Project: Concurrent URL Checker
- Build a tool that takes a list of URLs (from a file) and checks each one concurrently (HTTP GET, 5s timeout)
- Worker pool: configurable concurrency (default: 10)
- Results: status code, latency, error (if any), written to output file
- Graceful: if any URL check takes > 30s total, cancel remaining
- Key packages:
net/http,sync,context,os,time - Engineer Takeaway: This pattern (worker pool + channel pipeline + context cancellation) is in every batch job, health checker, and data pipeline you'll write.
Week 3: Context, I/O & JSON (Days 15–21)
Why this week matters: context and encoding/json are in literally every production Go service. These are not optional topics.
Day 15 — context package
- Why: Context is how timeouts and cancellations propagate through your entire stack — from load balancer to database query. It's why Go services can be reliably cancelled
- Topic:
context.Background(),context.TODO(),WithCancel,WithTimeout,WithDeadline,WithValue,ctx.Done(),ctx.Err() - Exercise: Build a request simulator with 3 stages (auth → fetch data → format response). Each stage has its own timeout. Cancel everything if any stage fails or the parent context is cancelled. Use
selectonctx.Done().
Day 16 — io.Reader & io.Writer
- Why: Every file read, HTTP body, network socket, and log writer in Go is an
io.Readerorio.Writer. Composing them is fundamental - Topic:
io.Reader,io.Writer,io.Copy,io.TeeReader,io.LimitReader,io.MultiWriter,io.Pipe,bufio.Reader/Writer - Exercise: Build a request logger that: reads an HTTP request body, logs it (via
io.TeeReader), limits to 10KB (viaio.LimitReader), and passes it downstream. Don't read the body twice.
Day 17 — encoding/json
- Why: JSON is the wire format for APIs. Understanding Go's JSON encoder/decoder explains why engineers write struct tags the way they do
- Topic:
json.Marshal,json.Unmarshal, struct tags (json:"name,omitempty"),json.Decoder(streaming),json.Encoder, customMarshalJSON/UnmarshalJSON,json.RawMessage - Exercise: Build a JSON API request/response pipeline: decode incoming JSON request (streaming, don't buffer full body), validate required fields, transform, encode response. Test with malformed JSON.
Day 18 — File I/O & os package
- Why: Config files, log files, PID files — services interact with the filesystem constantly. Knowing the patterns prevents bugs
- Topic:
os.Open,os.Create,os.ReadFile,os.WriteFile,os.Stat,filepath,os.MkdirAll,os.TempDir, file permissions - Exercise: Build a rotating log writer: write to
app-YYYY-MM-DD.log, create new file daily, keep last 7 files (delete older ones), concurrent-safe withsync.Mutex.
Day 19 — Strings & bytes
- Why: Security-critical code manipulates strings constantly — URLs, headers, payloads. Knowing strings vs bytes prevents subtle bugs
- Topic:
stringspackage (Builder, Split, TrimSpace, Contains, HasPrefix),bytespackage, string immutability,[]byteconversions,strings.Builderfor efficient concatenation - Exercise: Build a URL normalizer: lowercase scheme and host, remove default ports (
:80,:443), normalize path (remove double slashes, resolve./and../), sort query params. No regex yet.
Day 20 — regexp
- Why: WAF rules and log parsers rely on regex. Understanding Go's
regexppackage performance (compiled vs interpreted) matters for high-throughput security middleware - Topic:
regexp.MustCompile,regexp.Compile,FindString,FindAllString,ReplaceAll,SubexpNames, pre-compiling patterns,regexp.MatchStringpitfall (re-compiles every call) - Exercise: Build a log line parser using named capture groups: parse nginx/Apache access log format (
$ip - - [$time] "$method $path $proto" $status $bytes). Compile all patterns at startup.
Day 21 — time package
- Why: Rate limiting, token expiry, metrics windows, log rotation — all time-dependent. Go's
timepackage is rich and often misused - Topic:
time.Now(),time.Duration,time.Since,time.Until,time.After,time.Tick(leak risk),time.NewTicker,time.NewTimer, time zones,time.Parse/Format - Exercise: Build a sliding-window rate limiter (purely time-based, no external state): each call checks if the count in the last N seconds exceeds a limit. Use
time.NewTickerfor cleanup. Thread-safe.
Week 3 Mini Project: Structured Request Logger
- Build an HTTP middleware that logs every request as structured JSON to a rotating file
- Log fields: timestamp, request ID (UUID-like, from
crypto/rand), method, path, status, latency, client IP, user-agent, request size, response size - Context: inject request ID into context at entry, retrieve at response write
- Rotation: new file daily, keep 14 days
- Key packages:
net/http,encoding/json,context,sync,time,os,crypto/rand - Engineer Takeaway: Audit logging is a compliance requirement. You now know what "structured logging" means in code, how to choose a log format, and why log rotation matters.
Week 4: Advanced Go Patterns (Days 22–30)
Why this week matters: These are the patterns that separate junior Go from senior Go. Knowing them helps you review architecture proposals.
Day 22 — Generics (Go 1.18+)
- Why: Generics reduce code duplication in shared libraries. You'll write a generic cache or pool yourself, and know when generics are worth it
- Topic: Type parameters, constraints,
comparable,any, generic functions, generic types - Exercise: Build a generic
RingBuffer[T](fixed-size circular buffer). Use it withstring(log entries) andint(metrics). Then build a genericResult[T]type wrapping(T, error).
Day 23 — sync.Pool & memory efficiency
- Why: In high-traffic services (security proxies, WAF), allocations cause GC pressure.
sync.Poolis how teams reduce that - Topic:
sync.Pool, GC interaction with Pool, when to use (reusable buffers), when not to use (long-lived objects),bytes.Bufferpooling pattern - Exercise: Build a byte buffer pool. Write a benchmark comparing: (1) allocate new buffer each request, (2) use
sync.Pool. Measure allocs/op and ns/op at 10k/req.
Day 24 — Functional patterns
- Why: Go middleware chains, option functions, and builder patterns are functional patterns. They appear everywhere in idiomatic Go
- Topic: Function types, middleware pattern (
func(Handler) Handler), options pattern (func(*Config)), method chaining builders - Exercise: Build a configurable HTTP server using the options pattern:
NewServer(WithPort(8080), WithTimeout(30*time.Second), WithTLS(certFile, keyFile)). No config struct in the constructor signature.
Day 25 — Embedding & composition
- Why: Go uses composition over inheritance. Understanding embedding explains how interfaces get "extended" in Go
- Topic: Struct embedding, interface embedding, method promotion, shadowing, embedding vs field
- Exercise: Build a
MeteredConnthat embedsnet.Connand counts bytes read/written. Build aTimedHandlerthat embedshttp.Handlerand records latency. Both are transparent wrappers.
Day 26 — expvar & runtime metrics
- Why:
expvaris built-in observability. Every production Go binary should expose/debug/vars. Expose it in every service you ship - Topic:
expvar.Int,expvar.Float,expvar.Map,expvar.String,/debug/varsHTTP endpoint,net/http/pprof - Exercise: Add
expvarmetrics to the Week 3 request logger: requests total, errors total, p50/p99 latency (ring buffer of last 1000 latencies), bytes served total. Expose at/debug/vars.
Day 27 — Graceful shutdown
- Why: Abrupt server shutdowns drop in-flight requests. Every production HTTP server needs graceful shutdown. This is a common incident cause
- Topic:
os/signal,signal.NotifyContext,http.Server.Shutdown,sync.WaitGroupfor in-flight tracking, shutdown timeout budget - Exercise: Build an HTTP server with 3-stage graceful shutdown: (1) stop accepting (10s), (2) wait for in-flight (30s), (3) force close. Test by sending requests mid-shutdown.
Day 28 — Profiling
- Why: When engineers say "the service is slow," you need to know what a flame graph means and how to generate one
- Topic:
go tool pprof, CPU profile (-cpuprofile), heap profile (-memprofile), goroutine profile,net/http/pprofendpoints, reading flame graphs - Exercise: Add pprof endpoints to your server. Write a load generator (100 goroutines, 10s). Collect a CPU profile. Open in pprof. Find the hottest function. Explain what the flame graph shows.
Day 29 — Testing: httptest & net.Pipe
- Why: Testing network code without real network calls is how you get fast, reliable CI
- Topic:
net/http/httptest.NewRecorder,httptest.NewServer,net.Pipe(), table-driven HTTP handler tests - Exercise: Write tests for the Week 3 middleware using
httptest. Test: request logging, rotation trigger, concurrent requests, context cancellation mid-request. No real HTTP server.
Day 30 — Review & code audit
- Review all Phase 1 code with fresh eyes
- Apply: consistent error handling, no goroutine leaks (
go test -race),defercleanup, proper context propagation - Engineer Takeaway: You can now read production Go code comfortably, write tests, benchmark performance, and profile CPU/memory. You're ready for networking.
Week 4 Mini Project: In-Memory Metrics Server
- Build a self-contained metrics collection + query server
- Ingest:
POST /metricsaccepts{name, value, tags}JSON - Query:
GET /metrics/{name}?window=60sreturns min/p50/p95/p99/max over the time window - Storage: ring buffer per metric name, concurrent-safe
- Observability: itself exposes
/debug/varsand/debug/pprof - Graceful shutdown with drain
- Key packages:
net/http,encoding/json,sync,time,expvar,net/http/pprof - Engineer Takeaway: This is a miniature Prometheus. You now know how metrics systems work inside, and why they use ring buffers, not unbounded slices.