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

The Seven Habits of Highly Effective Programmers

The Seven Habits of Highly Effective Programmers

Embrace the Unix Philosophy

A programmer’s first and second lessons should both be about the Unix philosophy — put simply: do one thing, and do it well. More concretely:

  • Small is beautiful.
  • Make each program do one thing well.
  • Build prototypes as early as possible.
  • Portability is more important than efficiency.
  • Store data in text files.
  • Squeeze every last drop of value out of your software.
  • Use shell scripts to improve efficiency and portability.
  • Avoid user interfaces that offer poor customizability.
  • Every program is a filter on data.

Even more concretely (TL;DR):

In [1]: import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Pick a Role Model and Chase Them

Every NBA rookie has a model to emulate, and we are forever calling some rising football star “Little Ronaldinho” or “Ronaldo Jr.” A role model gives you someone to imitate and pursue, and at the same time forces you to consider what kind of programmer you actually want to be. Mine are Greg Pass and Werner Vogels. I may never reach their heights in this lifetime, but that doesn’t stop me from drawing a little closer, step by step, to the stars I’ve set my sights on.

Write Code, Don’t Tweak It as You Go

The worst experience in building software is probably writing and debugging at the same time — write a little, run it, write a little more. Plenty of programmers work this way, for two reasons: (1) they aren’t familiar with the code (or the libraries) at hand, so they need to run as they write to keep things correct; (2) the REPL (Read-Evaluate-Print-Loop — the language’s shell) in modern languages actively encourages the habit.

People who write systems software seldom do this. Their lousy tooling makes write-and-run a productivity killer — if a small change cost you several minutes of compilation, or longer, would you still do it? So they typically finish an entire module before compiling and debugging. (Which suggests that highly efficient tools are sometimes a double-edged sword.)

To me, writing code is like writing an essay: once you’ve worked out the idea and have an outline, you should let it flow and finish it in one continuous sweep, then go back to adjust sentences and fix typos. If you turn around to re-check what you wrote after every paragraph, you’re slow, and your train of thought scatters.

Code produced by write-and-run also tends to be low in quality. Individual parts may be polished, but the whole is out of proportion and always looks awkward. It’s like sculpting: holding a block of stone, you first refine the nose, then work your way across the face. By the time you reach the ears, the nose may be too large or too small — however exquisite, it earns no praise.

Debug Smartly

Software always breaks. When it does, many programmers set breakpoints in their IDE at every conceivable location; without an IDE, they hurl every print/log statement they can think of at the problem — take a swing and hope to hit a date.

Good programmers consider debugging while they are writing the code: they inject log output at various levels into the key nodes of the system, then switch on the appropriate debug level when needed and follow the trail, avoiding unreliable guesswork. This is the way of debugging.

Many problems reveal themselves the moment you turn on debug logging. But sometimes you find the initial cause through debug output and still need specific tools to pin the problem down — the technique of debugging — such as the breakpoint debugging described above. And sometimes, when a problem can’t be solved with gdb-like tools (pdb for Python) — a performance problem, say — you need more tooling for runtime profiling, such as systemtap.

Use Markup for Documentation, Not Word or PowerPoint

Don’t write documents with tools that can only be opened by one specific piece of software, such as Word/Pages or PowerPoint/Keynote. Use tools that work “anywhere under heaven.”

Java’s marketing slogan was “write once, run anywhere.” You want the same for your documents. Markdown (md) / reStructuredText (rst) — indeed any markup language, even Jade — are exactly such tools. By writing in a specific text format, your document can be compiled into almost any other format (html, rtf, latex, pdf, epub, …), truly achieving “write once, run anywhere.” Most importantly, because the logical layer (the text itself) is separated from the presentation layer (formats, fonts, line spacing, and so on), the same document can take on a completely different look with a different template.

Unless I absolutely must, all my documents are now in md or rst.

Everything Is a Project

Everything a programmer produces should be organized project-style. Software, obviously — but documents and scattered thoughts should also be grouped into projects according to their relevance. A few examples of my own:

  • My blog is a GitHub project called jobs.
  • All my WeChat articles live in the project craftsman.
  • My learning process for any given subject (Go, say) goes into one or several projects.
  • Every work project’s various outputs (including meeting notes) get a corresponding git repo.

The virtue of the project approach is traceability. I can manage each project with git, so from nearly any device I can see the work I did before. Think about a document you wrote three years ago — can you still find it? Can you still recover its revision history?

Another great benefit is that you can build tooling on top of it. For example, these WeChat articles you’re reading — at any moment I can run

make publish YEAR=2014

to generate a PDF containing everything I wrote in 2014.

Stay Open-Minded, Dare to Try

In programmer communities, wars over languages, systems, and software philosophies are practically the norm: python vs ruby, go vs java vs erlang vs rust, scala vs clojure, OOP vs FP, iOS vs Android. But no matter the color of the cat, the one that catches the mouse is a good cat — Facebook still runs on PHP. Programmers should meet new technologies and new ideas with an open mind, dare to try them, rather than dismissing them out of hand. The saddest thing in this world is holding a hammer and seeing everything as a nail (or rather, being able to see nothing but nails).

I’ve only been using a Mac for three years. Yet in those three years I went from sneering at Macs to loving them deeply, and ended up a heavy user. Many things you only understand once you’ve used them; without trying them, without touching them, I might have lived out my life on the other side of an invisible wall my own subconscious had built.

Over the past two years I’ve learned Erlang, Go, and Scala, and read a little Clojure and Rust. Right now I’m enthusiastic about Go development, but that doesn’t stop me from continuing to embrace Python and Node.js. Every programmer should have a primary language at each level. Mine:

  • System level (realtime): C (perhaps Rust someday)
  • System application level (realtime): Erlang (in training)
  • System application level (non-realtime): Go (in training)
  • Application level: Python
  • Web backend: Python, Node.js, Go
  • Web frontend: JavaScript
  • Device side: Android Java (no plans yet)

You needn’t take this list as a reference — I only want to use it to show that the more open your mind, the larger the world you see.

MORE IN Leadership & Career

Further Reading in This Column

View all essays in “Leadership & Career” →

The Programmer's Meltdown

After enduring the 'unsafe shitstorm,' actix-web's maintainer pulled the top-ranked Rust framework and walked away from open source—a story of maintainer burnout and the hidden cost of demanding that volunteers reshape their work for everyone else.

Book Next Chronicles (2013–2020)2,451 chars · 5 min read

Nana the Intern

When it comes to interns, beyond learning ability, I ask for one thing: a long enough runway. By "long enough" I mean at least two or three months — anything shorter and they leave before contributing anything of value, clutching a glowing evaluation form. Nana's story is an exception worth studying.

程序人生 (2015–2019)4,528 chars · 10 min read

ArcBlock at One Year

One year since trading the Bay Area for Washington State: a reflection on the winding road that built ArcBlock — its Forge framework, its bet on application chains, and the choices that led here.

Book Next Chronicles (2013–2020)6,593 chars · 15 min read