01 — Reading Production C¶
Reading production C is the single fastest way to level up in this phase. Textbook C teaches you syntax; production C teaches you taste — why one function is 400 lines and another is 12, why a macro exists, why a goto cleanup is the right answer, why a static inline in a header is worth the compilation cost. You are not reading to memorize; you are reading to develop the reflex that lets you predict what the next 20 lines will do before you scroll.
The four canonical codebases below are chosen because each teaches a distinct discipline and each is small enough to actually finish. Read them in this order. The order matters.
The reading order (non-negotiable)¶
# |
Repo |
LOC (approx) |
Discipline it teaches |
Why here |
|---|---|---|---|---|
1 |
SQLite |
~150k (amalgamation ~230k) |
Documentation, testing, invariants |
Best-documented C project alive; DO-178B-style rigor |
2 |
Valkey (Redis fork) |
~130k |
Event loops, data structures, ops |
Cleanest single-threaded server C you will ever read |
3 |
curl |
~180k |
Portability, protocol handling |
30+ years of “works on everything” pragmatism |
4 |
git |
~350k |
Complex object graphs, plumbing vs porcelain |
Advanced; leave for last |
Do not shortcut this order. People who start with git bounce off; people who start with SQLite absorb how to think about a C project and carry that to the rest.
1. SQLite — the reference standard¶
SQLite is the most-deployed database on Earth (in every phone, every browser, every plane) and is written by three people. The public-facing distribution is a single-file amalgamation sqlite3.c (~230k lines) but the source-of-truth lives in a Fossil repo with ~150 modules. Documentation-per-line ratio is unmatched. Start with the architecture doc, then the amalgamation.
What to read, in order:
doc/architecture.mdon sqlite.org — the four-layer picture: SQL Compiler → VDBE bytecode → B-tree → Pager → OS interface.src/vdbeaux.c— how the VDBE (virtual machine) is built. This is one of the most beautiful pieces of C ever written.src/btree.c— the B-tree that stores everything. Read the top-of-file comment first (~600 lines of prose).src/pager.c— journal, WAL, atomic commit. This is where SQLite earns its “you literally cannot corrupt this database” claim.src/os_unix.candsrc/os_win.c— how the same interface hides platform brutality.
Testing worship: SQLite ships ~150k LoC of source and ~100 million LoC of test code — roughly a 600:1 ratio. Read test/ for one hour to understand what “test coverage” actually means in safety-critical software.
One thing most people get wrong: they try to modify SQLite. Don’t. SQLite does not accept public patches for licensing reasons (public-domain / no-copyright policy) — the sqlite.org page was softened in Dec 2025 but the process still requires a signed copyright-dedication affidavit mailed to HWACI (Hipp, Wyrick, Aggarwal, Confluent Inc). Read SQLite; do not send it your PR.
2. Valkey — the event-loop archetype¶
Valkey is the Linux-Foundation fork of Redis (created March 2024 after Redis Inc. moved from BSD-3 to SSPL/RSALv2). By mid-2026 it is the default in Fedora, Ubuntu 26.04 LTS, AWS ElastiCache, GCP Memorystore. It is a single-threaded, event-loop-driven, memory-first C server — the cleanest example of that architecture available.
What to read, in order:
src/server.c—main(), config, initialization. ~7,000 lines.src/ae.c— the event loop (Antirez’s own reactor). Under 500 lines; read every one.src/networking.c— how a command comes in over a socket and how a reply goes out.src/t_string.c,src/t_hash.c,src/t_list.c— command implementations. Pick two.src/dict.c— the incremental-rehash hash table. This design is copied everywhere.src/aof.candsrc/rdb.c— persistence, forking, copy-on-write.
A concrete win: track a single command (SET foo bar) from readQueryFromClient() → processCommand() → setCommand() → addReply() → writeToClient(). Two hours. You will never look at a network server the same way again.
Antirez rule: if a function has more than about 100 lines, it is usually intentional (a state machine) not sloppy. Look for the state comment at the top.
3. curl — the portability sensei¶
curl is what happens when one person (Daniel Stenberg) maintains a codebase for ~27 years while it becomes the transport layer for the entire internet. It supports 25+ protocols, compiles on 100+ OS/architecture combos, and every configure switch you can imagine. It teaches you what portable C actually costs.
What to read, in order:
lib/urlapi.c— URL parsing. Looks simple; is not.lib/http.c— the HTTP state machine. Watch how one function handles HTTP/1.0, 1.1, and 2 without a rewrite.lib/multi.c— the multi-handle API. This is how you do concurrency without threads in C.lib/select.c— polling abstraction overselect/poll/epoll/kqueue/WSAPoll.CURLOPT_*handling inlib/setopt.c— 300+ options, all backward-compatible for decades. This is what API stability looks like.
Daniel-ism: the docs/INTERNALS.md file is required reading before you touch anything. It is short and it explains every convention.
4. git — the graph god¶
git is the advanced tier. It teaches you object graphs, content-addressable storage, plumbing vs. porcelain, and the discipline of keeping a 350k-LoC C codebase intelligible. Do not start here.
What to read, in order:
Documentation/technical/api-*.txt— read the API docs before the code. Junio Hamano’s rule.object.c,object.h— the four object types (blob, tree, commit, tag) and how they are addressed.read-cache.c— the index. Understand this and you understandgit add.builtin/commit.c— one full command from CLI parse to object write.revision.c— the commit walker. Everygit logvariant is a knob on this.
Warning: git’s C style is idiosyncratic (heavy macro use, strbuf everywhere). Read Documentation/CodingGuidelines first.
How to actually read (not “look at”)¶
Reading production code is a skill. Do these six things every session:
Clone locally. GitHub’s web view will lie to you about what actually compiles.
Build it first.
./configure && make -j$(nproc). If it doesn’t build, you don’t understand it yet.Use a real editor with ctags/LSP.
clangdin Neovim or VSCode. Jump-to-definition is the whole point.Keep a
notes/<repo>/folder. One markdown file per source file you read. Two paragraphs each. Future you will thank you.Explain one function per session to a rubber duck (or your
notes/file). If you can’t, you didn’t read it.Read the tests for the module you just read. Tests reveal invariants that the code assumes but never states.
Budget: about 1 hour of code reading = 3 hours of writing your own C in learning yield. This is not a shortcut; it is the highest-leverage activity in this phase.
What most people get wrong about this¶
They read for comprehension when they should read for pattern. You will not remember what pager.c:2847 does. What you will (and should) remember is: “SQLite uses a single-file journal for rollback and a shadow-page WAL for concurrent readers, and both funnel through sqlite3PagerAcquire().” Patterns transfer to your own code. Line-level details do not.
The second thing they get wrong: they treat these repos as museums. They are alive. Valkey shipped 8.1 in April 2026, curl ships every 8 weeks, llama.cpp ships weekly. Subscribe to the mailing lists or GitHub releases. Reading is passive; watching a live project is active.
Return to README.md · Next: 02_static_analysis_and_ci.md