QIAOPANG.COM · SELECTED ESSAYS (2013–2026) · 260 ESSAYSBrowse Chronologically (2013 → 2026) ↗
QiaoPang · Programmers LifeSelected Essays · Systems, Craft & Agentic Era
Timeline ↗

Why Should We Read Source Code?

Why Should We Read Source Code?

Programmers work with code every day. After years of basic education and professional training, most programmers can “write” code—or at least copy and modify it. Yet few can read code, and even fewer can read it while genuinely understanding the source of some large project. If we trace this oddity to its roots, the blame does not really lie with programmers as a group; it comes from two causes:

  • All our education and training emphasizes how to write code; no one teaches us how to read it.
  • Most workplaces operate on the “one radish, one hole” principle: we only need to understand a small part of a system to do our jobs, so reading unrelated code seems useless.

I often compare writing code to writing prose—the two have much in common. But when we look at how the abilities are cultivated, there are many differences. Our writing ability is built on a foundation of extensive reading. Beyond learning grammar and rhetoric, from elementary school onward we spend years reading works by masters at different levels, accumulating experience through all kinds of writing exercises. Our coding ability, by contrast, after we understand and master syntax and grammar (learning and copying example code counts as part of that), skips the stage of reading widely from masters and is acquired automatically with a “biu”: once we learn basic syntax and try a few examples, we rocket straight to writing code, grinding monsters, and gaining XP. Skipping extensive code reading has three harms:

  1. The foundation for writing code is unstable, and the leveling-up process is slowest. The reason is simple: the pits previous generations fell into, and the lessons they summarized, are things you have to try out for yourself, one by one, using the slowest method.
  2. It easily fosters a Stack Overflow–driven coding habit. When you do not know how to write something, you find a ready-made answer online, pick a highly voted one, copy, paste, tweak it, and muddle through the feature. When problems arise while coding, you enter debug mode: either set countless breakpoints and trace step by step, or print information everywhere and try to patch hole-ridden code, turning the whole coding process into a history of blood and tears from debugging. (See my article: )
  3. The upper bound of your coding ability is the upper bound of the strongest engineer around you.

Let us return to reading books.

From elementary school through high school, twelve years of Chinese language study means twelve textbooks and hundreds of essays. If each essay averages a thousand characters, we read hundreds of thousands of characters. We read these texts closely—some we were even required to memorize in full. For each essay, we summarized the central idea and the gist of each paragraph; we identified arguments, reasoning, and evidence, or time, task, place, cause, process, and result; we analyzed long and difficult sentences; we learned the qi-cheng-zhuan-he structure of introduction, development, turn, and conclusion; we repeatedly trained our basic diction and sentence construction; and ultimately we imitated those essays and wrote our own. In this process, we learned the classical rhetorical modes of fu, bi, and xing; we mastered the syllogism; we learned how to express our thoughts more elegantly. More importantly, these reading exercises let us independently finish reading a book after leaving basic education. We no longer rely on a teacher or reference book to hand us paragraph gists and central ideas. We know how to skim, how to read closely, and even how to read one book against another. We can distill the essence of a book into a mind map, and excerpt excellent sentences, paragraphs, or chapters at length.

Over those dozen years, counting extracurricular reading, world classics, classical literature, Jin Yong and Gu Long, cultivation fantasy and xianxia, a twenty-something college graduate should have read no fewer than several million characters. A somewhat broader reader will often have accumulated tens of millions. With that accumulation, when a young beauty walks toward you, what comes to mind are phrases like skin fairer than snow, bright eyes and charming glances, peach-blossom cheeks, teeth like shells, breath like a hidden orchid, a beauty beyond description—one smile topples a city, a second topples a nation; fish sink and geese fall, the moon hides and flowers blush—rather than not knowing how to express it, swallowing your saliva, and muttering to yourself: “Damn, what a beauty.”

This is the first great function of reading: accumulating material (information). Have you ever racked your brains while writing an article, unable to describe something? Likewise, when coding, have you ever had no clue where to begin? Or had some ideas, yet your hands froze over the keyboard, at a loss? These phenomena mostly come from a lack of accumulation.

The second great function of reading is opening up your thinking. Sometimes a passage, even a single sentence, rushes at you unexpectedly and gives you a moment of sudden enlightenment. In Fortress Besieged, for example, when Zhao Xinmei and Fang Hongjian first meet, Qian Zhongshu describes Zhao’s arrogance and rudeness like this: “He looked him over arrogantly from head to toe, as if Hongjian were a large-print kindergarten reader that could be taken in at a glance.” When I first read Fortress Besieged, I focused on the story and let such sentences slip by. When I reread it a few years ago, I realized how exquisite it was: using an object to describe a person so simply, restoring the whole scene as vividly as if it were happening before my eyes. Afterward I imitated it in my own writing, sometimes deliberately using such metaphors to strengthen the visual sense. Not long ago I happened to read this sentence again. Because I now had experience reading kindergarten readers to my daughter, I smiled and immediately understood a truth: what is exquisite is not the metaphor itself, but the minute observation of life.

While learning Elixir and building a policy engine (see: ), apart from official documentation and scattered blog posts, there was pitifully little to read. For some problems I needed to solve, no one on the forums could give me good ideas. So I turned to reading part of iex’s source code and came to understand how Elixir code is compiled. Eventually I completed an auto compiler app—it can accept some API requests and compile preconfigured source code belonging to other apps on a node in the cluster; when compilation is done, it reloads throughout the cluster. While building the API, I read the main logic in plug, especially closely reading the code of Plug.Router, and understood why Phoenix’s router dares to claim that during the route match phase its performance beats peers by several orders of magnitude. So when I built the API, I had a clearer idea of how to perform actions before and after match/dispatch to implement middleware, and even how to hook into before send.

Accumulating material is the foundation; inspired ideas string that material into lines, and this forms knowledge. The more you read and the more diligently you think, the richer your knowledge. And the integration of knowledge ultimately forms the third great function of reading: through understanding, absorbing other people’s thoughts, discarding the dross, and ultimately forming your own thoughts—or wisdom.

information -> knowledge -> wisdom is a long accumulation, not something achieved overnight.

Apart from a few ads, all my articles are original, and 99% of the original articles are my own original work. But are these originals completely my own “original” work? In “How to Choose a Job,” I borrowed an idea from Hackers & Painters: measurability and leverage. I agree with that idea, and I integrated it into my own thinking. In “Programmers and Hand-Pulled Noodles,” I actually wrote a modern version of Cook Ding Butchers an Ox. In “The Way of Code Refactoring,” I borrowed ideas from Yukihiro Matsumoto, Martin Fowler, Xunzi, and others, and formed my own views. Of course, I have still read too few books, so truly valuable thoughts remain scarce.

Likewise, the ultimate destination of reading excellent code by masters is to form your own approach to writing code. Last year I wrote a node restify–based API framework (see: series). Although it has many imperfections, its core is quite stable; over the past year it has needed only minor patches. Writing it was an integration of the various projects I had read before. To decide whether I should base it on restify, I read through its code (not much), fused in some ideas from hapi and loopback, provided a Rails-like CLI, and added a bit of my early experience with parsers. I logically split the framework into compile time (strictly speaking, Node has no compile time, but configuration processing and the generation of internal data structures for routes, middleware, models, and tasks are counted as compile time), load time, and run time—using the “inefficiency” of the first two stages to buy efficiency in the last. This is analogous to my old line of work: control plane / data plane and first path / fast path design on routers and firewalls. Without the prior accumulation from reading all kinds of source code, I would have found such a design very hard to produce.

Likewise, reading Elixir’s Unicode implementation two years ago inspired me to create a brute-force method for Chinese-character slugification, or Chinese-character-to-pinyin conversion (solving the polyphone problem), using the same approach (see: chinese_translation). This idea was further developed early this year into the policy engine and content engine we now use at Tubi TV, safeguarding countless content requests every day. We use the code-as-cache method: transformations of database content that need not happen at runtime are all completed at compile time; then at runtime we combine them with the three elements of narrative writing to produce the final result. The slowest API in our system used to be abysmal—especially its 95th-percentile response time under low concurrency (under high concurrency, we could not even complete the test). Now, under high concurrency and with no failures, its 99th-percentile response time stays around 500ms.

So tell me: how important is reading excellent, inspiring source code?

When there is time, we can talk about how to read other people’s code.

MORE IN Languages & Craft

Further Reading in This Column

View all essays in “Languages & Craft” →

Time to Meet jj: Git's Next Evolutionary Step

Git has ruled version control for twenty years, but its staging area, brittle rebases, and blocking merge conflicts are becoming liabilities in the AI era. jj rebuilds the mental model from the ground up — while staying fully Git-compatible. Here's why it deserves your attention.

New Hope (2025–2026)5,588 chars · 12 min read