Where to Go Next
Two choices in this book existed for grading reasons, not because they're what you'd reach for by default, and it's worth being direct about which:
SQLite, in-process. It let every exercise run offline, in milliseconds,
with no server to stand up. A production Go service backed by Postgres or
MySQL uses the same database/sql interface — Open, QueryRowContext,
ExecContext, transactions, everything in this book — against a different
driver string and DSN. Almost nothing you learned is SQLite-specific except
the SetMaxOpenConns(1) + :memory: gotcha from Chapter 1, which doesn't
exist against a real server: connections there really are independent, and
the pool is there to be used, tuned with the real values Chapter 5 only
gestured at.
modernc.org/sqlite, a pure-Go driver, existed because the sandbox runs
--network=none with no cgo toolchain. Postgres work typically reaches for
pgx instead of database/sql's lib/pq — faster, and with its own
connection pool (pgxpool) that supersedes database/sql's. The concepts
transfer directly; the package names don't.
sqlc versus an ORM
Chapter 8 generated Go from SQL you write. The other common answer is an
ORM — gorm is the usual Go one — which generates SQL from Go structs and
method calls instead. Both solve "stop hand-writing Scan calls," and they
trade off in opposite directions:
sqlc keeps you writing SQL, which means you can always see and reason
about the actual query — its indexes, its joins, its EXPLAIN plan — and
sqlc only ever generates code for queries you wrote yourself. gorm
generates the SQL for you from struct tags and chained method calls,
which is faster to start with and can quietly produce a query you wouldn't
have written — an N+1 loop from an innocent-looking association load is the
classic version of this. Neither is wrong; they're optimizing for different
things. A team that already thinks in SQL and wants type safety without
losing visibility into the query tends toward sqlc. A team that wants to
avoid writing SQL at all, and is willing to trust the generator, tends
toward an ORM.
This project's own backend — the auth and books stores your submissions
flow through — uses sqlc against Postgres via pgx/v5, for exactly the
reasons above. If you want to see the pattern from this book at production
scale, sqlc.yaml and internal/*/store/queries.sql in this repository are
real, running examples of it.
You now have every piece the Tasks API's original sync.Mutex map promised
to become: a real database behind the same interface, transactions where
they matter, tests that exercise it honestly, and generated queries where
hand-written ones stopped paying for themselves. That's the whole arc this
book set out to close.