Refactoring English: Month 18

Michael Lynch

重构英语:第 18 个月

一句话总结

书写完了!嗯,算是吧。

初次来访?

你好,我是 Michael(迈克尔)。我是一名软件开发者,也是小型独立科技企业的创始人。目前我正在写一本书,叫Refactoring English: Effective Writing for Software Developers(《重构英语:面向软件开发者的有效写作》)

每个月,我都会发布一篇像这样的回顾,分享我的新书以及整体职业进展。

亮点

  • 我已经完成了全书全部 22 章。
  • 我曾以为 AI 让原型开发更快了,但现在不太确定了。

目标评分

每个月初,我都会定下想要完成的目标。以下是我的完成情况:

让《重构英语》达到“内容完稿”

  • 结果:我已完成所有章节。
  • 评分:A

这件事感觉六周以来一直都只差一周就能完成,所以终于把所有章节都写完,让我如释重负。

创建一个能让《重构英语》读者在阅读时提供反馈的工具

  • 结果:该工具仅完成了约 40%。
  • 评分:C

这原本看起来应该只是个两三天的项目,但我发现它比想象中更难,尤其是受到大阻塞的影响。

《重构英语》数据

指标2026年4月2026年5月变化
独立访客2,5781,752-826 (-32%)
预售收入$587.73$407.61-$180.12 (-31%)

唉,我一直在忽视营销,数据也因此下滑。

我急于完成最后几章,所以只专注于写作,没有在营销上投入任何精力。

Bug bounty(漏洞赏金)数据

我仍在继续做安全方面的 Bug bounty,但已减少了投入的时间。并没有完全按照计划的 70/30 分配,大概是 60/40 吧。

我一直在合作的主要厂商又向我支付了 7千美元(累计已达 1.7万美元)作为漏洞报告的奖金,但他们处理报告的速度放慢了,所以我已基本停止在他们的代码中寻找新漏洞。

我向另外几个项目提交了漏洞,以看看是否有处理速度更快的,但都没有:

  • KeePassXC - 我于 5 月 18 日向 Zero Day Initiative 提交了一个 RCE(远程代码执行)漏洞,但尚未收到任何回复。
    • 对于 KeePassXC 的用户来说,这不是零点击攻击,也不是只需访问恶意网站就会导致数据库被攻破的问题,所以不必过于担心。
  • Cloudflare - 我于 5 月 22 日通过 HackerOne 提交了一个 DoS / logic bypass(逻辑绕过)漏洞。没有收到回复。
  • Proton - 我提交了一个低危问题。他们要求提供视频形式的 proof of concept,我在 5 月 29 日制作了一个,他们说会等候回复。

这本书何时算“完成”?

我已经完成了全书的所有章节,这让人松了一口气,但我并不认为它就算正式“完成了”。

在过去一年半里,我通常一次专注于一章来写这本书。我还从未把自己的书从头到尾完整读过一遍,以确保整体一致。我想在宣称完成之前,至少完整通读几遍。

为什么我没有持续修订这本书?

我原本计划根据读者的反馈持续修改这本书。这样一来,当我写到最后一章时,这本书就基本完成了,因为其他章节已经根据读者的评论经历了多次修订。

实际上,我整合读者反馈的程度远低于预期。

我发现很难在修订旧章节和撰写新章节之间分配精力。如果花一周时间修订旧章节,就感觉没有取得实质进展。而新增一章,则意味着公开进度条又前进了一点,这很有激励作用。

来自书籍网站的进度条

我没有持续修订的另一个原因是,我与读者沟通的次数远少于计划。部分原因是我总觉得书的进度落后,所以总想着:“先把这一章写完,然后再投入更多精力去联系读者。”

但即使我联系了读者,也很少对书产生实质影响。读者最常见的回复是“我喜欢这本书”或“我还没开始看”。

当我确实收到详细反馈时,我也不总是知道该如何整合。在某些情况下,我认同反馈,决定就很容易做。但通常情况下,读者会建议增加一些我认为没有必要的内容。这并不是说读者错了,但在违背直觉去修改之前,我希望能看到读者反馈中的某种规律,而我收到的反馈还不足以形成规律。

我的读者反馈工具

既然已经完成了所有章节,我觉得有更多余力去联系读者了。

我很喜欢Help this Book这个想法,它是一个能让读者直接在电子书中提供反馈的网页应用,但我不想把所有反馈都托管给第三方并按月付费。

我看到 Julia Evans(朱莉娅·埃文斯)为自己的产品定制了读者反馈工具,觉得很有意思,所以我也在做类似的东西。

我正在开发一个网页应用,以便读者更方便地就书的内容向我提供反馈。

AI 项目与大阻塞

总体而言,我发现 AI 在编程时确实让我更高效。在处理像解决 Git 合并冲突、调试不熟悉的代码或制作简单工具这类任务时,AI 的优势非常明显。

我曾以为 AI 在帮我启动项目方面很出色,但现在不太确定了。我不断遇到我称之为“大阻塞”的情况。

让 AI 来做原型

六个月前,我会给 AI 代理一个高层次的需求概述,让它实现一个基础的 v1 版本。我知道代理的输出会很混乱,但那只是个原型,所以我可以不断给出反馈,直到它符合我的编程品味。

结果发现,清理一个糟糕的原型比我预期的要难得多。一旦原型糟得足够彻底,我甚至很难理清代码到底想做什么。

AI 似乎有一种奇怪的倾向,会为已有的代码辩护。如果我告诉 AI 某个组件让人困惑,因为它对同一份数据迭代了三次,它只会坚持认为由于 X、Y 和 Z 的原因必须迭代三次。但它从不质疑 X、Y 和 Z 是否是人为制造的约束。

这就是阻塞。我被困在试图跨越 AI 构建的那堵由混乱代码构成的巨墙。

如果我不修复核心逻辑,问题只会越来越严重。代码异味像霉菌一样滋生并蔓延到整个代码库。我在薄弱的地基上继续构建,而 AI 只是不断复制已有的糟糕模式。

拆解原型

好吧,一个简单的解决办法是:让 AI 代理分更小的块来创建原型。把 AI 的缰绳收紧一点,不让它跑得太偏。不要让 AI 一次性创建整个原型,而是先从欢迎页面开始。审核并合并后再添加一个简单功能,依此类推。

这种方法在遇到复杂模块(比如身份验证)之前都运行良好。AI 会生成一个包含 2千到 5千行混乱代码的拉取请求,这就成了一堵巨大的墙。我想不出还能如何进一步拆解这个功能,于是又被一个巨大的 PR 卡住了,也就是另一次大阻塞。

不仅 4千行代码的变更比 400 行代码的变更需要多花 20 倍的时间来审查,它还需要更长的连续审查时间。如果我有 20 分钟的空档,可以处理 400 行的变更,但如果是 4千行代码的变更,光是建立上下文就需要 20 分钟。要在不把大部分时间浪费在上下文切换上的情况下,对 4千行代码的变更取得实质进展,我需要 90 分钟的连续时间,这对于周末项目来说很难得。

示例:为 Little Moments 实现身份验证

举个例子。对于Little Moments,我采用通过邮件发送魔法登录链接的方式来实现身份验证。几周来,我一直想不出如何在不引入无用代码或破坏功能的前提下拆解这个功能。我无法只实现一半的登录流程。

在一点点啃这个巨大 PR 啃了几周后,我意识到其实我可以实现“一半的登录”。PicoShare 是我维护的另一个应用,它的身份验证流程很简单。应用假定只有一个授权用户,所以身份验证只是一个口令,甚至不是用户名/密码对。与其从无验证直接跳到基于邮件的验证,我可以先从无验证过渡到口令验证。

于是,我实现了口令验证,但从口令验证转向魔法邮件登录仍然是一个相当大的 PR,需要我花数周来审查。在连续几天的攻关后,我意识到还可以进一步拆解。

与其真正发送带有登录链接的邮件,我可以先直接把用户重定向到本来会发送给他们的链接。这仍然是一个 1.7千行代码的 PR,但比真正发送邮件要更易于管理。而且它把真正发送邮件的部分缩减到了区区 1千行代码。

AI 为什么让这件事变得更难

让我怀疑 AI 在这类工作上是否为正向收益的原因在于,我知道如果不使用 AI,我本会发现这些拆解问题的机会。我绝不会创建一个 4千行代码的 PR,然后说“嗯,这有点大”。随着 PR 越来越大,使用起来会越来越痛苦,所以我会自然而然地找到机会,将变更拆成更小的部分。

AI 打破了这种自然的反馈循环。使用 AI 时,创建一个 4千行代码的 PR 毫无痛苦可言,因为它在两分钟内就完成了,而我只是在查看邮件。我可以轻松地对这个 4千行代码的 PR 给出修改意见,并感觉自己在取得进展,但巨大的变更让我很难识别出哪些部分可以抽出来作为独立的更小变更。

既然我已经认识到为复杂变更生成巨大、难以管理的 PR 是多么容易,我就可以改变使用 AI 的方式,在复杂功能生命周期的更早期投入更多精力,将功能拆解成更细小的变更,并更严格地检查 AI 的输出。

总结

完成了什么?

  • 发布了本书的最后几章。
  • 为书籍反馈应用创建了部分原型。
  • 为 Little Moments 部分实现了身份验证。
  • 为 PicoShare 发布了两个新版本。

经验教训

  • 使用 AI 消除了促使我以更小粒度构建软件的自然反馈循环。
    • 我认为解决办法是在复杂功能生命周期的更早期更努力地将事务拆解成更小的块,并更严格地检查 AI 的输出。

下月目标

  • 在改进《重构英语》网站上投入至少五小时。
  • 为《重构英语》网站吸引 3 万独立读者。
  • 完成我的读者反馈工具。

原文由 Michael Lynch 发布

本文章由 muse-spark-1.2-contributor 进行翻译