Home About Me

A Weekly Build Habit, Blogging as a Programmer, and a Few Things Worth Reading

This Week’s Package Project

Some time ago, I came across a small guide built around a very practical way to learn: start with the most basic possible implementation, then keep refining it step by step until you can reason your way toward the final source code. I’ve always liked that approach, so I decided to turn it into a habit of my own: from now on, I want to build and study one npm package every week.

At least in the beginning, the focus has to stay on simple, commonly used packages. There’s no point pretending I can thoroughly explain something too large or too complex before I’m ready.

This week’s package is only-allow, a tool used to enforce a single package manager across a team.

How should programmers write blogs?

I recently saw a discussion about this question and it got me thinking not just about blogging in general, but also about my own writing over the years.

My first post went online in 2018. Compared with people who have been running personal sites for more than a decade, that still feels relatively recent. But even within these few years, writing has involved plenty of hesitation, frustration, persistence, and gradual change.

Looking back, I think my blog writing has gone through several overlapping stages. They aren’t strictly linear, and in practice they often coexist.

1. Writing study notes

This is where many programmers begin. The output at this stage is usually basic learning notes, often with limited originality. Most of it can already be found with a quick search, so the practical value for others may be fairly small.

I still remember sharing one of those early posts in a tech community and being told, in no uncertain terms, that I was misleading people. Someone even mocked it as little more than copying a whole book. It was discouraging. At the same time, I also knew I really was inexperienced.

For a while, I questioned whether I should continue adding more low-level material to the Chinese tech community at all. In the end, I kept going.

A lot of programmers start from this kind of writing. Many never move beyond it, and some stop writing entirely. That’s the real pity. Even if these notes are rough, they can still be the beginning of a better writing practice.

2. Resource roundup posts

Deep technical writing is hard. Even ordinary technical writing can be hard. Because of that, there was a period when I particularly enjoyed writing resource-sharing posts: useful websites, practical tools, handy Chrome extensions, and so on.

These posts are easy to produce. You simply list things you already use regularly, add a few comments, and you can quickly get likes and bookmarks. That also helps explain why there are so many Markdown-style resource repositories on GitHub.

But after a while, I realized this kind of writing did very little to improve my own ability.

That doesn’t mean resource-sharing posts are meaningless. If you genuinely know tools that can save other people time, sharing them is valuable. The problem is stopping there. It’s fine to write this kind of post, but it’s a mistake to be satisfied with writing only this kind of post.

3. More in-depth technical articles

As work experience accumulates, technical understanding naturally deepens. At that point, it becomes possible to write about things with more substance: classic interview questions, source code reading, deep dives into specific concepts, or painful lessons from debugging a library or tool.

This type of writing is also the most painful.

The moment you try to explain something clearly, you often discover the exact place where your own understanding falls apart. If you can’t explain it, then you probably haven’t really understood it. That forces you back into the documentation, back into experimentation, and back into rewriting the idea in your own words until it actually makes sense.

That process is exhausting, but the payoff is huge. It improves your own grasp of the subject, and it usually ends up being much more useful to others as well.

4. Writing about things beyond tech

People are not machines. Even if technology is the main theme, sooner or later you want to write about other things too: thoughts about work, life, confusion, motivation, or your reaction to something happening around you.

This kind of writing feels more exposed. Readers may relate to it, or they may dislike it simply because they see things differently. And a lot of the time, you are not even sure whether your own view is mature or correct.

I used to worry about that too. I was hesitant to talk too openly about non-technical topics on my blog. Later I realized I had overestimated the risk.

In many cases, the final reader of these posts is yourself.

When other people read your work, they usually focus on whatever is useful to them. And even if what you wrote back then now feels naïve, that doesn’t make it worthless. It becomes part of your record of growth.

Whenever I feel lost, I sometimes go back and reread something I wrote when I had just entered the workforce about why I became a programmer in the first place. It reminds me not to forget how I ended up on this path.

So there’s no need to be afraid of writing about things outside technology. Those immature lines may end up encouraging you years later.

If you think you can’t write well enough

Some people worry that their writing is poor, that they don’t have enough vocabulary, or that they simply can’t produce that much text.

That worry is usually unnecessary.

To be honest, I don’t think my own writing is particularly good either. I can’t effortlessly produce polished, flowing prose. But that’s not the standard that matters most. If you can express your meaning clearly and put real feeling into it, that is already enough.

Write more. Keep writing.

A small protocol worth knowing: QOTD

QOTD stands for Quote of the Day. It is defined in RFC 865 and listens on port 17. It’s a protocol that is rarely used now, and only a handful of public QOTD servers still remain:

<table> <thead> <tr> <th>Server</th> <th>TCP Port</th> <th>UDP Port</th> </tr> </thead> <tbody> <tr> <td>djxmmx.net</td> <td>17</td> <td>17</td> </tr> <tr> <td>alpha.mike-r.com</td> <td>17</td> <td>17</td> </tr> <tr> <td>cygnus-x.net</td> <td>17</td> <td>17</td> </tr> </tbody> </table>

So what can you do with it?

One practical example is using GitHub Actions to periodically fetch quotations from djxmmx.net and update a GitHub profile with them.

A few reads and takeaways

Bash pitfalls that both beginners and veterans still hit

One piece I found especially useful is a collection of more than forty common Bash mistakes. What makes it good is not just the list itself, but the way each mistake is broken down: an incorrect example, an explanation of why it fails, and a better rewrite.

Shell scripting has a way of punishing assumptions, and even experienced users can slip into habits that look harmless until they cause subtle bugs.

Better Docker image builds

Another useful read focuses on improving Docker image builds. Most of the ideas are basic if you’ve been working with Docker for a long time, but they’re still very helpful for beginners.

It gives four tips. The first one is worth spelling out here.

Remove caches properly

Package managers such as apt and pip usually generate caches so future downloads can be faster. Inside a Docker image, those caches are often unnecessary, so they should typically be cleaned up right after installation:

RUN dnf install -y --setopt=tsflags=nodocs \
    httpd vim && \
    systemctl enable httpd && \
    dnf clean all

What you should avoid is splitting these into separate RUN instructions like this:

FROM fedora
RUN dnf install -y mariadb
RUN dnf install -y wordpress
RUN dnf clean all

Each RUN in a Dockerfile creates a new layer. In other words, this produces three layers: the first two include the cached data, and the third merely deletes it afterward.

There is, however, an important detail. Since Docker v1.13, the --squash option can compress all build layers into a single layer after the build finishes. That means the final Docker image contains only one layer, so in that case, placing the cleanup in a separate RUN step can still work.

docker build --squash

The other three tips are straightforward but useful:

  1. Put content that changes less frequently earlier in the build.
  2. Separate the build image from the runtime image.
  3. Inspect the final build artifacts.

JavaScript functional composition, explained plainly

Among articles on JavaScript functional composition, one of the clearest examples I’ve seen starts from the ground up and walks through compose, pipe, and flow step by step.

Its biggest strength is that it doesn’t assume you already buy into the style. It shows why composition can be useful.

For example, an Array-based chain might look like this:

const comments = commentStrs
  .filter(noNazi)
  .slice(0, 10)
  .map(emphasize)
  .map(itemize)
  .join("\n");

With functional composition, the same transformation becomes:

const comments = pipe(
  commentStrs,
  filter(noNazi),
  take(10),
  map(emphasize),
  map(itemize),
  join("\n")
);

One advantage is that you’re no longer restricted to methods on Array.prototype. You can insert custom steps freely:

const comments = pipe(commentStrs,
    filter(noNazi),
    take(10),
    map(emphasize),
    map(itemize),
    join('\n'),
+   chaoticListify,
);

Another advantage is that helpers like map can be reimplemented in completely different ways without forcing you to change the call site. For instance, you could switch to generators:

const map = f =>
  function* (iterable) {
    for (let x of iterable) yield f(x);
  };

const join = s => iterable => [...iterable].join(s);

The deeper value of this style is not just cleaner-looking code. It offers a different way of thinking about transformations and data flow.

A map of China’s hacker circles

One article that stood out for a very different reason looks back at the legendary hackers active in China from the late twentieth century into the early 2000s. If you’re curious about who those figures were and where they ended up, it’s a fascinating subject.

The comparison that stayed with me is that the information security world can resemble a martial arts underworld: schools and factions, famous aliases, gatherings, secret techniques, treasured tools, very few true heroes, and many more opportunists. Even regulation can feel strangely similar.

What makes those stories compelling is the kind of people they describe: people who, in much harsher times, could have lowered their moral standards just a little and lived comfortably, but did not; people with top-tier technical skill who could have escaped low pay through gray-market work, but did not; people who endured misunderstanding and the bad reputation created by others in the field, yet still kept pursuing the technology they loved.

There is something admirable in that kind of persistence.

Interesting links

  • zonemeen/musicn: a command-line tool for downloading high-quality music
  • Similarweb: traffic analysis for any website, extremely useful for site owners
  • Codeit: a mobile app that makes it much easier to browse code from Git repositories on your phone
  • Queue: a tool for publishing tweets through Notion
  • Coverview: a tool for generating article cover images