30 秒看懂
Ron Minsky 与作家兼软件工程师 James Somers 讨论 Jane Street 的技术写作。他们谈及组织知识、文档工具、代码审查、自文档化代码的局限,以及如何服务不同背景的读者。 他们还比较编程与写作,探讨文学化编程,以及如何通过修改和插图让重要思想更容易被看见。
- 1理解读者的世界Somers 将编程与写作、编辑结合起来,以理解 Jane Street 独特的工具和开发者体验。
- 2保存知识与代码负责人交谈很有用,但文字能为不在场的人留下可搜索的记录。
- 3让文档可执行、可发现构建系统检查代码块,可以标记过时的示例;搜索和读者反馈则帮助人们找到并改进文档。
- 4写作暴露设计问题Minsky 在代码审查中利用说明;两位嘉宾都发现,难以解释某项修改可能揭示更深层的缺陷。
- 5让文档适合读者示例驱动的指南可以介绍形式语法难以讲清的工具,而经验丰富的读者可能更喜欢简洁的参考资料。
- 6发送前修改Somers 建议作者即使写普通邮件也要重读和精简,删除对读者没有帮助的上下文。
要点建议
- 技术写作者需要足够的实践背景,才能理解系统和读者遇到的困难。
- 文档将知识保存在个别对话之外,帮助组织扩大规模。
- 可执行示例、搜索和读者反馈有助于保持文档最新且易于发现。
- 撰写和审阅说明可以暴露代码中的概念性错误。
- 不同读者需要不同形式的文档,从教程到简洁的参考资料皆有用处。
- 好的写作和软件都受益于反复修改以及对读者的关注。
按章节阅读整理后的全文
工程组织中的作家
Somers 介绍如何将软件工程与写作、编辑结合起来。两人探讨组织知识为何需要持久的文字记录。
Ron Minsky 介绍 James Somers,他是 Jane Street 的职业作家和软件工程师。Somers 说,自己大约四分之三的时间用于编程,其余时间担任驻场作家和编辑,帮助同事撰写和改进文档。
Somers 认为,首先成为一名实际工作的程序员,有助于他理解写作所面向的组织。Jane Street 拥有自己的 OCaml 程序库、开发工具、测试和构建系统,以及部署和监控方式。亲身经历这个独特的生态,才能真正理解其中开发者的处境。
Minsky 同意好的写作需要理解主题,但他询问为什么组织需要专门关注写作的人。Somers 说,文档很难写,也容易被忽视,尤其是开发新软件比解释现有工作更令人兴奋的时候。
刚完成程序库之后可能是最不适合写文档的时候:作者沉浸在实现细节中,而不是从外部读者的问题出发。Somers 把自己的角色描述为一个始终站在外部的人,试图达到忙碌或缺乏耐心的读者可能具备的理解程度。
Somers 说,Jane Street 认真对待文档,并投入工具保持文档更新,但仍面临常见问题。其文化将软件与构建和维护它的人紧密联系在一起,因此答案可能来自打电话给合适的人,而不是搜索结果。
代码审查系统记录文件的负责人,让人们可以找到最熟悉某部分代码的人。项目负责人的名单本身就可能是有用的文档。但电话交谈不会留下可搜索的记录,后加入或未参与谈话的人无法查阅。
写作能长期保存知识,并大规模传播。Minsky 回忆,Jane Street 在他的任职期间从约 40 人增长到 1,500 人;专门的系统和低人员流动率让个人积累了深厚的专业知识,但规模扩大使记录这些知识变得更加重要。
Minsky 将文档与公司测试实践的发展作比较。早期系统更多依靠少数人的知识和 OCaml 类型系统提供的保护。随着代码库增长,人们构建测试工具,让可测试性成为普遍关注的问题;他希望文档也发生类似的文化转变。
文档工具与激励
文档往往更直接地惠及他人,而不是作者本人。可执行示例、发布反馈和搜索可以让文档更容易维护和发现。
Somers 认为激励有所不同。测试框架可以几乎立即让作者自己的开发工作更轻松,而文档往往先带来额外工作,主要帮助其他人。即使作者个人没有立即获得生产力提升,组织也需要认识到集体收益。
Minsky 回应说,测试也有共同收益:测试充分的代码库让同事有信心修改不熟悉的部分。好的文档同样帮助人们学习和修改陌生系统,尽管作者可能需要其他形式的反馈来了解文档的价值。
Somers 从事文学化文档的工作:Markdown 文件中包含可以编译的代码块。如果程序库的 API 变化导致示例失效,构建过程会像检查代码一样标记文档。这不能解决所有文档问题,但有助于防止示例过时。
他还负责将构建系统生成的文档发布到内部网站。阅读量、评论或点赞等功能可以让作者了解自己工作的影响。内部搜索引擎可以汇集 Wiki、文学化文档、API 文档、博客、邮件列表和代码审查评论。
即使文档或工具非常出色,如果人们找不到它,用处也很有限。Minsky 将工具的作用归纳为三方面:提高可发现性、提供文档使用情况的社会反馈,以及在代码变化与需要更新的文档之间建立联系。
Somers 补充说,文档构建失败不只是机械性错误:它会促使开发者重新阅读说明,判断内容是否仍然合理。知道页面有人阅读可以激励作者改进;知道无人使用也有助于决定精力该花在哪里。
写作、代码审查与修改
撰写说明可以暴露软件中的概念问题。Somers 和 Minsky 比较散文和编程中的修改过程。
Minsky 介绍自己审查代码时,先看说明、注释和命名,再看实现。他经常请作者解释某个功能,或在审查期间自己写文档。这个过程不仅改善措辞,还可能发现概念性错误和真正的漏洞。
Somers 也有类似体验:冗长的提交信息有时是在为糟糕的决定辩解。想象审查者阅读这段说明时,他可能意识到实现本身也只是初稿。文字和代码都可能需要重做。
当被问到编程和写作是否相似时,Somers 说,两者在微观层面不同。编程的自由度更少,因为语言和程序库的限制缩小了选择范围;散文中的句子、段落或整篇文章则有更多出错方式。
在更大的层面,两种工作都需要愿意修改。Somers 将这种耐力比作长跑者承受里程的能力:优秀程序员和作家一样,会反复回到自以为已经完成的工作中。Minsky 补充说,代码组织、命名和注释可以讲述系统的结构。
两种工作都需要在脑中建立读者模型,并整理自己的思想。冗长、费力的解释也可能表明底层设计过于复杂。
自文档化代码的局限
好的命名和类型有帮助,但代码难以解释所有取舍或操作注意事项。两人讨论类型、文化和架构。
Minsky 问到一种观点:代码应当清晰到不需要文档。Somers 在 Ruby 社区见过这种观点的强烈版本,富有表现力的领域专用语言看起来几乎像英语。但优雅的接口可能掩盖复杂的实现机制,而这些机制值得解释。
有些有用的信息不容易自然地写进代码,例如函数的运行复杂度,或如何在不同数据结构中作选择。Somers 回忆一个异步文件写入 API,其中有一个 exclusive 标志;一段多段落注释解释了这个标志本身无法传达的操作系统与锁定细节。
Minsky 认为,即使复杂的类型和清晰的抽象也有局限。宏可能在错误信息中暴露转换后的实现细节,而实用的类型系统无法表达所有相关属性。一个看似简单的接口很少能完全消除解释行为和权衡的必要。
尽管如此,Somers 认为自文档化代码是一种有用的引导。程序可以使用带验证和方法的有意义类型,而不是用未验证的字符串表示社会保障号码和疫苗接种状态。Minsky 指出,这些类型让值的含义在整个程序中清晰可见,而编辑器也能显示局部变量的类型。
他们讨论语言是否决定文档和测试文化。Somers 回忆一家重视测试驱动开发的 Ruby on Rails 咨询公司,但他认为应用背景也很重要:交易系统的故障成本与一家测试用户是否喜欢某项功能的小型网络公司不同。
Minsky 补充说,文化和架构可能与语言同样重要。Jane Street 将早期系统重写为 OCaml 时,团队、架构和实践也发生了变化。Somers 曾在语言和程序员不变的情况下,看到糟糕的设计,也看到好的设计。
面向不同读者的文档
形式语法和示例驱动指南满足不同需求。教程、操作指南、参考资料和解释性文档可以构成更容易导航的生态。
Minsky 观察到,一些 OCaml 文档简洁、精确,却假定读者已经建立了心智模型。他询问经常撰写示例驱动指南的 Somers,如何看待简短描述与示例之间的取舍。
Somers 回忆自己的第一项文档任务:改进一个查询 S 表达式的工具的 README。原有文档基本上是一份形式语法。新手很难看出工具有什么用、实际应该执行哪些任务,因此他写了一份示例驱动指南。
Minsky 记得原作者知道文档可以改进。形式化描述对有深厚编程语言背景的人来说是合理的,但也可能体现知识的诅咒。不过,对于已经理解设计空间的资深读者,简洁资料也可能非常高效。
Somers 建议为这些读者提供分别标明用途的文档。对于一个 OCaml Web 框架,初学者可能需要解释浏览器背景的教程;React 用户可能更喜欢熟悉的 API 与新工具之间的对应说明。一份文档无法同时满足所有读者。
他们讨论了四种文档形式:教程、操作指南、参考资料和解释性文档。Minsky 回忆起写学术论文时的一条建议:尽早提供有用信息,因为读者会在不同位置停止阅读。他也在想,工具是否能让读者在简洁的类型视图和示例之间切换。
Somers 说,约定形成的文体能帮助作者和读者导航。新闻报道通常先给出最重要的事实,有经验的学术读者则知道去哪里快速寻找结果。可辨认的文档类型也能让读者了解预期,并帮助作者组织内容。
Minsky 提出另一种类别:说服人们尝试某个想法或工具的写作。他认为,重视谨慎和精确的工程文化可能让这种倡导变得困难。Somers 指出,如果没人为某个工具提出有说服力的理由,组织可能会留下多个相似的替代方案。
文学化编程与抽象
他们探讨 Donald Knuth 将文字和代码交织在一起的方法。两人都质疑杰出个人的实践能否很好地推广到更大的团队。
他们转向 Donald Knuth 的文学化编程。Somers 觉得其中一些说明和例子很难理解。Minsky 概述了 Knuth 的工作,包括 TeX,并询问这种方法与普通代码和文档有何不同。
Somers 描述了将代码和文字交织在一起的方式:读者沿着线性的解释叙事前进,而不是在文件之间跳转。Minsky 补充说,发布的叙事可以采用与源文件不同的顺序,以便按照最适合解释的次序呈现整个程序。
Somers 认为,这种方法在 Knuth 这样的高手手中可能非常强大,但对大多数程序员而言很困难。Minsky 将 Knuth 能自如跨越系统深层工作的能力,与自己理解复杂软件时对抽象的迫切需要作比较。适合杰出个人的实践不一定容易扩展到更大的程序。
Somers 说,一个人创建的软件与团队维护的软件可能有不同的架构,从前者过渡到后者尤其具有挑战。两人承认 Knuth 工作的持久影响,同时质疑他的个人方法能在多大范围内适用。
写作工具与修改
Somers 介绍自定义编辑器、笔记和 John McPhee 的工具。他建议反复修改草稿,重视日常邮件。
Somers 用 TextMate 记录笔记,并自定义语法高亮。他区分自己的想法与引文,还能直观看出草稿是否过度引用资料。到了协作编辑或后期草稿阶段,他通常转到 Google Docs。
他介绍非虚构作家 John McPhee 自定义的 KEDIT 环境,它有助于将笔记组织成嵌套分组,并找出重复使用的不常见词。Somers 希望更多作家无需深厚技术知识就能调整自己的工具。
Minsky 问 Somers 是先规划结构,还是从头到尾写下去。Somers 说,这取决于需要探索多少内容。为陌生程序库写文档时,他像记者一样工作:与人交谈、阅读、试用工具并整理笔记,然后构建解释。
即使结构很容易形成,再写一稿也能改善内容。Somers 将编辑比作压缩文本:一条消息的字数常常远超表达意思所需。Minsky 补充说,缩短文字也能让重点更清楚,实际上为读者增加有用信息。
Somers 举例说,一封邮件可能包含 14 行异常堆栈。与其贴出全部内容并告诉读者哪些行重要,他可以直接删除无关行。他建议重新阅读和修改,不要把初稿当成完成稿;Minsky 有时会在修改时发现一封邮件根本不需要发送。
许多技术写作是普通邮件,而不是正式指南或设计文档。邮件不断占用同事的时间,因此 Somers 认为在邮件上多花一点心思就能带来显著效果。
作为描绘的技术写作
Somers 欣赏软件文档、生物学和风的描述中的范例。他认为,有效的解释会突出对人类读者重要的内容。
谈到欣赏的例子,Somers 提到 Rust API 文档一致的示例和源代码链接,以及 TensorFlow 的手写数字识别入门教程。他也关注软件以外的领域,包括分子生物学家兼艺术家 David Goodsell 用插图解释蛋白质的作品。
Somers 提到《Defining the Wind》和蒲福风级,其描述把风速转化为树叶和旗帜运动等可观察细节。他认为,精确的语言既有诗意,也能帮助读者识别物理现象。
海岸线的绘图有时比照片更能传达其显著特征,因为插画师会选择和强调重要内容。Somers 认为,有效的技术写作也进行类似的转换:通过缩短、配图和突出重点,让重要内容更容易被理解。
他建议作者在探索代码或程序库时,相信自己对有趣和乏味之处的反应。记录这些反应可能带来不那么正式或全面、但对有相同疑问的读者更有用的解释。Minsky 总结说,技术写作既关乎技术,也深深关乎人。
Somers 不喜欢“技术作家”这个头衔带来的枯燥联想:这项工作与其他写作没有根本区别,而且人们一直在实践它。Minsky 感谢他参与这场对话;两人经常处理这个主题,却很少有机会在这样的层面讨论它。
同频道的其他文章
1:48:29EN → 简体中文
1:05:45EN → 简体中文
1:25:00EN → 简体中文
1:16:29EN → 简体中文
4:41EN → 简体中文
1:34:29EN → 简体中文