Write while learning

Write while learning / 边学边写

September 19, 2026 / 2026年9月19日

When learning new topics, we always ask questions we can’t find answers to. “Why are there two APIs that do seemingly the same thing?” “How do I achieve this goal?” “Why does this code not work even though it looks similar to the example?” 在学习新课题时,我们总会遇到找不到答案的问题。“为什么有两个 API 看起来功能一样?”“我该如何实现这个目标?”“为什么这段代码看起来和示例差不多,却无法运行?”

As we research and get more familiar with tools, we gain understanding. At some point, we become experts and know how to answer earlier questions. But it’s worth covering how we get from point A to point B to help others make progress, too. In my experience, it’s common that the answers seem obvious post-factum, but there’s a missing link between facing questions and knowing the terms to look for. 随着研究的深入和对工具的熟悉,我们逐渐理解了其中的奥秘。在某个时刻,我们成为了专家,知道如何回答当初的问题。但我们有必要记录下从 A 点到 B 点的过程,以帮助他人取得进步。根据我的经验,答案往往在事后看起来显而易见,但从“面对问题”到“知道该搜索什么术语”之间,往往存在着缺失的环节。

Usually I have to get familiar with the project architecture, read its code, look at what it interacts with, scan the bug tracker, etc., before I build a model in my head that answers my questions. And then I discover that the model is easy to understand and has docs, and I agree with experts that it’s a reasonable and well-designed model – forgetting that I-the-novice failed to find it despite the documentation existing! 通常,我必须先熟悉项目架构、阅读代码、查看交互对象、浏览错误追踪器等,才能在脑海中建立起解答问题的模型。随后我发现,这个模型其实很容易理解,而且文档齐全。我也会认同专家们的观点,认为这是一个合理且设计良好的模型——却忘了当初作为新手的我,即便文档就在那里,也依然没能找到它!

Example / 示例

For example: I recently got into Minecraft modding, and KubeJS, a tool for reconfiguring Minecraft with JavaScript, uses syntax like this to add an item to a tag: 例如:我最近开始接触《我的世界》(Minecraft)模组开发。KubeJS 是一个用 JavaScript 重新配置游戏的工具,它使用如下语法将物品添加到标签中:

ServerEvents.tags('item', (event) => { event.add('tag_name', 'item_name') })

Immediately I’m left wondering: what is ServerEvents, and why are the operations performed in the closure? Is that closure invoked immediately and it’s just a way to get access to event? Why is it called “event” if it doesn’t react to any player action? 我立刻产生了一连串疑问:什么是 ServerEvents?为什么操作要在闭包中执行?这个闭包是立即调用的吗?这只是获取 event 对象的一种方式吗?如果它不对任何玩家操作做出反应,为什么叫它“事件”(event)?

It turns out that the answer is: KubeJS integrates with a mod loader, in this case NeoForge, which offers events. The examples on that page show events like “entity jumps”, which are clearly game-related events, but at the very bottom we have: 事实证明,答案是:KubeJS 集成了一个模组加载器(本例中为 NeoForge),它提供了事件机制。该页面上的示例展示了诸如“实体跳跃”之类的事件,这些显然是与游戏相关的事件,但在页面最底部我们看到了:

Lifecycle events run once in every mod’s lifecycle during startup. […] The registry events […] include NewRegistryEvent, DataPackRegistryEvent.NewRegistry and, for each registry, RegisterEvent. 生命周期事件在每个模组启动时的生命周期中运行一次。[……] 注册事件 [……] 包括 NewRegistryEvent、DataPackRegistryEvent.NewRegistry,以及针对每个注册表的 RegisterEvent。

After more research, I understand that the closure I’m registering really is an event handler, and NeoForge delivers this event when the world is loaded and handles it synchronously. I also understand that this is closer to a mixin/patch point than an event, but it uses the same underlying mechanism and is thus called the same. 经过进一步研究,我明白了我所注册的闭包实际上是一个事件处理器,NeoForge 在世界加载时会同步触发此事件。我也理解了这与其说是一个事件,不如说更像是一个 mixin/补丁点,但因为它使用了相同的底层机制,所以被冠以相同的名称。

To obtain this information I had to: 为了获得这些信息,我必须:

  • Read KubeJS docs. / 阅读 KubeJS 文档。
  • Read KubeJS code to learn about the connection with NeoForge. / 阅读 KubeJS 代码以了解其与 NeoForge 的联系。
  • Read NeoForge docs. / 阅读 NeoForge 文档。
  • Read NeoForge code to learn about the connection to mixins. / 阅读 NeoForge 代码以了解其与 mixin 的联系。

Resources / 资源

We all value learning resources, but I find that most often, we offer docs for beginners and for experts, but few for those transitioning from one to another. 我们都重视学习资源,但我发现大多数情况下,我们提供的文档要么是给初学者看的,要么是给专家看的,很少有为那些处于过渡阶段的人准备的资料。

I remember the time when I didn’t know how Web worked, and all articles on the topic went like “your computer sends ones and zeros to Google, and Google sends ones and zeros back”. But how do they reach Google specifically? Now I know that Ethernet uses certain bit sequences to start packets, and about IP addresses being resolved to MAC addresses via ARP, and about HTTP and cryptography. But I learned pretty much all of that by accident, like learning how packet boundaries work from a school teacher or finding out about ARP by seeing packets in WireShark. 我记得当初我不懂 Web 是如何工作的时候,所有相关文章都写着“你的电脑向 Google 发送 0 和 1,Google 再发回 0 和 1”。但它们具体是如何到达 Google 的呢?现在我知道以太网使用特定的位序列来启动数据包,知道 IP 地址如何通过 ARP 解析为 MAC 地址,也了解 HTTP 和加密技术。但我几乎都是偶然学到这些的,比如从老师那里了解到数据包边界的工作原理,或者通过在 WireShark 中抓包发现了 ARP。

Try it for yourself: tell me how someone who heard that HTTPS makes connections secure go from the Wikipedia page on HTTPS to Diffie-Hellman without prior knowledge that asymmetric crypto is the main thing that gives HTTPS its guarantees. 你可以试着想一下:如果一个人只听说过“HTTPS 让连接更安全”,在没有“非对称加密是 HTTPS 安全保障的核心”这一预备知识的情况下,他该如何从 HTTPS 的维基百科页面跳转到 Diffie-Hellman 协议?

Of course, Wikipedia is the epitome of “experts writing for experts”, but our accessible documentation is seldom better: “experts writing for 5-year-olds” is just as annoying when you need to know the details. 当然,维基百科是“专家写给专家看”的典型,但我们所谓的“易懂文档”也好不到哪去:“专家写给 5 岁小孩看”的内容,在你真正需要了解细节时同样令人恼火。

My plea / 我的呼吁

I started this blog as a way to teach cool stuff to people who only know the basics. My goal is to raise readers to my own level, not just above baseline, like pop-sci journals do. Sometimes I have to make concessions and adjust complexity, but I think it works great overall. I try to follow the same approach when writing documentation: for each high-level API, I try to mention the low-level details it’s based on, like which algorithm is used, to let people follow breadcrumbs and educate themselves. 我创办这个博客是为了向那些只掌握基础知识的人传授酷炫的技术。我的目标是将读者提升到和我一样的水平,而不是像科普杂志那样只停留在入门阶段。有时我不得不做出妥协并调整复杂度,但我认为总体效果很好。我在编写文档时也尝试遵循同样的方法:对于每个高级 API,我都会提及它所基于的底层细节(例如使用了哪种算法),让人们能够顺藤摸瓜,自我提升。

But I-the-expert no longer remember all the issues I-the-novice was facing. The only time when I still remember my confusion and the terms I tried to search for, while also knowing the solution, is just after struggling and finally finding an answer. 但作为专家的我,已经不再记得当初作为新手时所面临的所有困惑。只有在经历挣扎并最终找到答案的那一刻,我才能同时记得当初的困惑、尝试搜索的术语,以及最终的解决方案。

Which is where I get to the title of the article. When you face a problem and spend days finding a solution, write about your successes – or even failures. This will help others who are stuck on the same issue, and it will help experts find missing information or unclear wording in their docs (which is why documenting failures is useful, too). Blogs, social networks, anything goes, really – even if only your friends see it, some of them may still find it useful. 这就是我写这篇文章标题的原因。当你遇到问题并花费数天找到解决方案时,请写下你的成功——甚至失败的经历。这将帮助其他陷入同样困境的人,也能帮助专家发现文档中缺失的信息或表述不清的地方(这就是为什么记录失败也很有用)。博客、社交网络,什么形式都可以——即使只有你的朋友能看到,对他们中的一些人来说也可能很有用。

Even if it takes you a while to reach a simple conclusion, that’s most likely not your fault – quite the opposite, it’s very useful to know that something trivial is so inaccessible! It’s valuable to learn about such omissions: for any person like you, there are ten people who could easily comprehend the answer, but failed to find it. Maintainers will thank you for that, and if not them, then others who face the same problem will. 即使你花了一段时间才得出一个简单的结论,那很可能不是你的错——恰恰相反,知道某些看似琐碎的事情竟然如此难以获取,是非常有价值的!了解这些缺失的信息很有意义:因为像你这样的人,背后还有十个人能轻松理解答案,却找不到它。维护者会为此感谢你,如果他们不感谢,那么其他遇到同样问题的人也会感谢你。