Really useful post, thanks. Lesson 3 hit home for me: the slow endpoint is usually a missing index, and adding the index is cheaper than adding a cache.
A small tip for lesson 5: staticcheck warns about a plain string as a context key, because another package can use the same string. An unexported key type avoids that:
And one I'd add to the list: set timeouts on http.Server itself, at least ReadHeaderTimeout. A slow client can hold a connection open while it sends headers, and that happens before the handler runs, so the context timeout from lesson 2 never starts.
Appreciate the careful read, Hamed. You're right on lesson 5. An unexported struct type as the context key is the right call over a plain string, and the staticcheck warning is a good reminder. I'll tighten that section. And the ReadHeaderTimeout suggestion is a genuinely good addition. Most handlers think about request timeouts but forget slowloris-style clients can tie up the listener before a request ever forms. I'll add a lesson on server timeouts.
Hamed Yousefi
Really useful post, thanks. Lesson 3 hit home for me: the slow endpoint is usually a missing index, and adding the index is cheaper than adding a cache.
A small tip for lesson 5: staticcheck warns about a plain string as a context key, because another package can use the same string. An unexported key type avoids that:
type requestIDKey struct{}
ctx := context.WithValue(r.Context(), requestIDKey{}, id)
And one I'd add to the list: set timeouts on http.Server itself, at least ReadHeaderTimeout. A slow client can hold a connection open while it sends headers, and that happens before the handler runs, so the context timeout from lesson 2 never starts.