乐于分享
好东西不私藏

二十五年的折腾:.NET 工程文档开源工具的沉浮

二十五年的折腾:.NET 工程文档开源工具的沉浮

最近随着 AI 热潮,技术文档因能为模型提供高质量上下文而重新成为热点。最近接触的几个开源项目在用一个叫 Lunet 的工具来生成 API 参考文档,我也就跟着评估了一下这个工具自己项目上的可用性。虽然它是个不错的 API 提取器,但设计者并没有尝试去解决更深层的问题让每个使用它的项目都自己高度定制,所以只好作罢。
LeXtudio Inc. 所有文档网站都已经基于开源的 Sphinx 基础设施搭建并且运行了很多年。自然而然,我又回到了一个十年前就思考过的问题,怎么把 .NET API 文档生成和 Sphinx 内容管理整合到一起。为什么我们不能直接用现有的 .NET 文档工具呢?答案需要回溯 .NET 文档工具这二十五年来的历史,一个关于生态分裂、战略转移,以及开源 .NET 社区得自己动手解决问题的故事。
NDoc 的年代:期许与沉寂(2001-2006)

故事自然从 NDoc 开始,一个起源于 2000 年代初的社区项目,由 Jason Diamond、Jean-Claude Manoli、Kral Ferch 等人参与维护,把 JavaDoc 的一套搬到了 .NET 平台。C# 编译器可以在生成程序集的同时输出 XML 文档注释,NDoc 就拿着这些输入,转化成视觉效果专业的参考文档,有多种演示风格,支持广泛的输出文件格式(甚至包含 LaTeX 这样罕见的)。对同时期兴起的开源 .NET 项目来说,NDoc 就是那个必备的工具。它的设计很务实,可扩展,免费开源。
当 .NET Framework 2.0 在 2005 年底降临时,NDoc 着实撞上了一堵墙。微软新添加的泛型是 NDoc 尚不支持列表上的主要问题,但也不是唯一问题。在 2005 年的一个帖子里,维护者 Kevin Downs 直白地说:泛型有”巨量的边界情况”,会导致 SDK 文档格式里”几乎每个细节”都改了,框架本身变成了”移动的靶子”。那时候微软的编译器和相关框架、工具都不开源,社区维护者既没有机会持续跟进这些变化,也难以在微软产品发布后及时跟进。结果可想而知:NDoc 对 .NET Framework 2.0 的支持停滞了,项目从此就没法跟上平台的进化脚步。
那个帖子现在仍然值得一读,因为它用作者自己的话描述了深深的挫折感。Kevin Downs 不是在抱怨某个缺失的功能,而是描述一整套文档管线变得难以维护,全方位的。这比起那个简化的说法——”NDoc 只是不支持泛型”——要好得多。
但故事没有就此结束。多年之后,NDoc 仍被不同的人用不同的形式一次次复活。SourceForge 上出现了 NDoc3,GitHub 上还托管着一个将 NDoc 和 NDoc3 合并后的小仓库。这种坚持在历史上有意义吗?即使原始项目实际上已经死了,开发者还愿意反复尝试复活这个想法,而不是彻底放弃。这是否反映了 .NET 生态的某些不良因素?
Sandcastle 的年代:微软的回应与社区的接力(2006-2015)
2006 年 7 月,就在 NDoc 官宣停止开发的几天后,微软在 CodePlex 上发布了自家用于 MSDN 文档项目的一个工具,Sandcastle。它当然比 NDoc 强大很多:在微软内部伴随着 .NET Framework 2.0 开发而不断进化,能理解泛型等新语法,也支持多种帮助输出格式和主题,最重要的还是它就是微软漂亮的 MSDN 文档背后那个实战考验过的工具。
但一开始这个项目就闹出个严重的信誉问题:最初在 CodePlex 上发布的时候,微软没有提供源代码。由于 CodePlex 打着开源项目托管网站的旗号,这个错位立刻引起了社区方面的怀疑。InfoQ 在 2008 年的对此总结为”围绕在开源网站 CodePlex 上托管一个闭源工具 Sandcastle 的喧嚣”。在 2008 年 7 月微软最终公开了它的全部源代码,但早期的混乱已经削弱了开源社区的信任。
为什么这很重要:许可证的不确定性会伤害到整个生态中其他项目对 Sandcastle 的态度,接纳还是排斥。一个处在不确定许可证下的强大工具往往还不如一个法律地位明确的弱工具有用——特别是很多开源项目还需要定制或修复这些工具才能获得最好的效果。
Sandcastle 还有第二个问题:它很重,特别是在内存消耗方面。从设计上,它需要运行多个转换管道,这个过程中要在内存里保存整个文档模型。这将消耗大量内容,也让工具运行得很慢。对于拥有专门文档团队和高端硬件的大公司项目,Sandcastle 或许能凑合着。对于开源项目的开发者来熟,这常常是令人望而却步的开销。
此外,.NET Compact Framework、Silverlight、Windows Phone、Portable Class Library 等多种框架的快速涌现带来了另一个维度的复杂性,项目文档需要处理.NET 生态的碎片化问题。Sandcastle 也在新版本中尝试解决这些问题。
从这个时期开始,有些开源项目慢慢迁移到了 Sandcastle,有些则改用商业解决方案或干脆自己搭建。有些干脆通过教程和博客文章来记录 API 而不生成具体的参考文档。
多年之后,Sandcastle 没有在微软转身后彻底消失。Eric Woodruff 作为 Sandcastle Help File Builder 工具的创造者从微软手工接受了这个项目的维护工作。最后一个来自微软的官方版本发布于 2010 年 6 月。虽然 Sandcastle 从来都不是许多社区开发者想要的那个开放、轻便的答案,但和被微软放弃的其他工具不同,它得到了一个社区归宿。Sandcastle 今天仍然被用在一些项目中,而不是只存在于历史注脚里的一个原因。
DocFX:内部转向(2015+)
当微软再一次尝试改进 .NET 生态并推动 .NET Core 成为现实时,旧时代的文档工具更难追上这波进步运动了。
当然这个时期我们还见证了其他语言生态里文档托管服务的兴起。Read the Docs 和 Sphinx 成了当时在开源社区里最受认可的文档技术栈,而不仅仅是孵化它们的 Python 社区。
有趣的是,ASP.NET 5 的文档网站在 docs.asp.net 时期曾经是托管在 Read the Docs 上的,用的就是 Python 和 Sphinx。Scott Hanselman 在 2015 年对这个事情做过记录。把 .NET 文档和 Sphinx 配对的想法不是纯粹的幻想,因为它确实在微软生态的某个时刻出现过一次。
不过 Sphinx 毕竟是为 Python 打造的。它对 .NET 类型、命名空间、API 结构是没有深刻理解。如果想为 Sphinx 生成高度定制化的 .NET 文档,这些问题就需要自己想办法绕过去。
在微软朝 Sphinx 再进一步之前,他们很快转向了内部的另一个项目 DocFX,Sphinx 的吸引力就快速消退了。
2015 年,微软在 GitHub 上正式推出了 DocFX,来担任新一代 .NET 文档工具。它支持 Markdown 输入,命令行工具能快速集成到 CI/CD 管道,对 .NET 各种特性也有原生理解,确实能工作得不错。
但对许多独立维护者来说,DocFX 就显得非常简陋了,不仅没有可视化用户界面,连一个漂亮主题也没有,这方面甚至赶不上有成熟生态的 Sandcastle。在产品路线图上,微软的摇摆和闪烁其词也带来了问题。2021 年用户问”docfx v3 有发布时间表的消息吗?”,到 2024 年才有维护者说”docfx v3 已作为内部项目移动去只支持 Microsoft Learn”,并且关闭这个公开讨论。再加上”Microsoft Learn 不再使用 docfx”的说明以及项目转到了 .NET Foundation 旗下的变动,都让人摸不着头脑,不知道到底背后发生了什么。总是个奇怪的故事。
从 Sandcastle 开始,微软确实保持了一定的开放性,将自己内部工具放到了开源平台上托管,也确实在解决一些来自社区的新需求。但是不公开的内部路线图,对外沟通的缺乏,都使得这些项目尽管技术野心很大,却难以赢得来自开源社区的信任。即使它一时能正常工作,你也感觉像是在借用别人的内部机器的一部分,而不是自己作为场外用户也享受到同等对待。
这种糟糕的模式在几个公开的 .NET 工具上也时不时显现出来。Try .NET、.NET Interactive/Polyglot Notebooks 在近期都被微软关闭。他们也都在揭示这个类似的信任问题:对更广泛的社区开发者有用的工具,一旦不再符合微软内部的优先级,就失去了动力或被下线。对独立维护者来说,教训当然不是每个微软支持的工具都注定失败。而是使用单个供应商控制的工具那永远都带着风险。
Lunet 的发现与 dotnet-sphinx 的出现(2026+)
Lunet 已经存在了多年,由 Alexandre Mutel 创立。它以 Scriban 为中心构建工作流并生成文档,所以还是个方便的工具。但当我认真去评估它时,我发现它在定制化方面没有体现出特别好的设计。当然我最后的实际结论是:自己还是想要一个更干净的通向 Sphinx 的桥梁,提供给项目更多的定制化选择。
Sphinx 是个被 Python、Django、Pallets、NumPy 和数千个开源项目用的文档生成器。它有成熟的主题(PyData、Furo、Alabaster),无缝集成 Read the Docs,有几十年长久的专业文档生成记录。当你发布用 Sphinx 构建的文档时,读者得到一个熟悉的、设计良好的体验。
多年来,很多实验性项目诞生过,像 SphinxForDotNet(2022 年 3 月存档)这样的项目曾尝试连接 .NET 和 Sphinx,但都没有被广泛采纳和持续维护。它们都被存档了或在创作者转向时停滞了。
dotnet-sphinx 是连接 .NET 到 Sphinx 生态的最新尝试,也是我写这篇文章的初衷之一。设计一个简便灵活的命令行工具,将 API 元数据并转换成 Sphinx 兼容的输出,在这个 AI 工具已经十分强大的时代花不了多少时间。剩下的就是 API 参考文档和示例、指南内容被放在一起,交给 Sphinx 系统处理,并生成最终网站。C# SNMP 文档仓库展示了最终效果,采用 Furo 主题,有一致的导航、内置搜索和边栏。
结语:构建韧性
.NET 文档工具的历史充满了生态分裂、优先级转移等各种混沌,以至于开源 .NET 项目开发者不得不自己去找解决方案。当然这也是个很好的进化过程,杀不死你的会让你更强大。
如果你想更系统地了解 .NET 的发展与工具演进,我正在撰写的新书《.NET 传奇(第二部)》将深入讨论这些主题,并收录大量案例。欲了解更多、订阅更新或支持本书,期待后续通知。
本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 二十五年的折腾:.NET 工程文档开源工具的沉浮

猜你喜欢

  • 暂无文章