nbdev+Quarto:提高效率的新秘密武器
原文发布于 Fast.ai 博客
我们提高效率的新秘密武器
今天我们激动地宣布,我们已与 Quarto 合作,赋予 nbdev 超能力。nbdev 为 Python 程序员提供了一套通用工具,用于使用 Jupyter notebooks 来
- 编写&分发软件包
- 测试代码,以及
- 编写文档和技术文章
尽管 Notebooks 已经广泛用于一次性探索性工作,但它们完全能够编写高质量软件这一点却鲜为人知。事实上,在过去三年中,我们已将 nbdev 用于各种软件项目,包括 深度学习库、 API 客户端、 Python 语言扩展、 终端用户界面 等。我们发现它不仅能够编写出色的软件,而且 我们的生产力还提高了 300% 或更多。使用 nbdev,开发者只需用轻量级标记编写 notebooks,即可免费获得高质量的文档、测试、持续集成和打包!Nbdev 使我们能够维护和扩展许多 开源项目。拉取请求通常附带详细文档和测试——贡献者只需编写 notebooks。
这就是我们激动地分享 nbdev v2 的原因。它从零开始重写,包含许多备受期待的功能,其中包括
- 与非 nbdev 代码库的互操作性,用于文档等任务
- 支持任何静态网站生成器
- 多种输出介质,如博客、论文、幻灯片和网站
- 更快的 Jupyter 内核,这意味着更快的测试
- 更简洁、更可扩展的 API,支持自定义指令、自定义模块导出器等
nbdev 在行业中的应用
我们已在多家公司试用 nbdev。我们很高兴收到以下反馈,这与我们使用和开发 nbdev 的自身经验一致
David Berg,关于在 Netflix 使用 nbdev 进行内部文档工作: “在使用 nbdev 之前,文档是我们软件开发过程中最繁琐的部分……使用 nbdev 使我们能够花更多时间围绕许多代码片段创建丰富的散文,确保整个体验是稳健的。nbdev 将曾经的苦差事变成了我们已经在进行的基于 notebook 的测试的自然延伸。”
Erik Gaasedelen,关于在 Lyft 生产环境中使用 nbdev: “我在公司生产环境中使用这个。它是一个很棒的工具……nbdev 简化了一切,所以我可以在一个地方编写文档、测试和代码……打包也非常周到。从我的角度来看,这与传统的 Python 库开发相比,几乎是帕累托改进。”
Hugo Bowne-Anderson,关于为 Outerbounds 使用 nbdev: “nbdev 改变了我们编写文档的方式。API 更改时或因复制&粘贴代码到 markdown 文件中的人为错误而担心代码示例损坏的日子一去不复返了。nbdev 的编写体验……使我们能够在统一的界面中编写散文和实时代码,这允许进行更多实验……最重要的是,nbdev 允许我们在文档中包含单元测试,这减轻了随着时间推移维护文档的负担。”
Roxanna Pourzand,关于为 Transform 使用 nbdev: “我们非常激动能使用 nbdev。我们的产品技术性很强,因此生成的文档包含大量基于代码的示例。在 nbdev 之前,我们无法维护代码示例并确保其命令输入和输出都是最新的。这一切都是手动的。有了 nbdev,我们现在可以以可持续的方式控制这一切。自从部署这些文档以来,我们还遇到了一种情况,能够在一个接口中识别出一个 bug,这是通过查看文档中输出的错误发现的。”
什么是 nbdev?
Nbdev 以传统 IDE 和软件开发工作流程无法实现的方式,拥抱 Python 的动态特性和 REPL 驱动的开发。三年前,我们在这篇 首次发布文章 中详细讨论了 nbdev 的动机、历史和目标。Jupyter 的创建者 Fernando Pérez 告诉我们
[nbdev] 应该得到更多赞扬和使用——我将你的 nbdev 原始博文标签在 Chrome 中保持打开状态长达数月,因为我经常引用它并将这项工作推荐给其他人
简而言之,nbdev 融合了 文学化编程 和 探索性编程 的思想。这些范式已在 XCode Playgrounds 等平台以及 Smalltalk、LISP 和 Mathematica 等语言中得到重新审视。通过 nbdev,我们试图通过将其应用于世界上最流行的动态编程语言之一 Python,进一步推动这些范式。
尽管 nbdev 因与 Jupyter Notebooks 集成而最广泛应用于科学计算社区,但我们发现 nbdev 非常适合更广泛的软件领域。我们已使用 nbdev 编写 深度学习库、 API 客户端、 Python 语言扩展、 终端用户界面 等!
Hamel:当我使用 nbdev 时,我的同事们常常惊讶于我创建和分发高质量 Python 包的速度。我认为 nbdev 是一种超能力,它使我能够轻松创建测试和文档,这让我的所有项目都更易于维护。我还发现使用 nbdev 编写软件更有趣、更高效,因为相对于更传统的软件工程工作流程,我可以非常快速地迭代想法。最后,使用 nbdev,如果我愿意,我也可以使用传统的基于文本的 IDE,所以我可以兼得两者之长。
使用 nbdev 三年后我们学到了什么
虽然 nbdev 最初是为了简化各种 fast.ai 项目 的软件开发工作流程而开发的,但我们发现用户希望扩展 nbdev 以用于
- 使用 Jupyter Notebooks 编写和发布博客文章、书籍、论文及其他类型的文档
- 为非 nbdev 编写的现有代码库生成文档
- 适应传统的 Python 约定——对于那些在代码组织和格式方面受到限制的人
- 使用 任何 静态网站生成器发布内容
虽然我们创建了诸如 fastpages 和 fastdoc 等项目来完成其中一些任务,但我们意识到拥有一套灵活的工具来完成所有任务会更好。为此,我们非常激动地发现了 Quarto,一个基于 Pandoc 构建的开源技术出版系统。
Hamel:我使用 nbdev 创建 Python 模块越多,就越想用它来撰写博客和为现有代码库编写文档。其自定义 Notebook 渲染方式(隐藏与 显示单元格、剥离输出等)的能力,以及包含单元测试的功能,使其成为我所有技术内容的首选创作工具。我很激动 nbdev2 为每个人解锁了所有这些可能性!
Quarto 的登场:一个 Pandoc 超级处理器
Quarto 是一个支持 Jupyter Notebook、VSCode、Observable 和纯文本编辑器的技术出版项目。此外,Quarto 支持以 HTML、PDF、ePub、PowerPoint 幻灯片等多种格式发布高质量的文章、报告、网站和博客。Quarto 由 RStudio 维护,该公司在支持文学化编程的产品方面有着悠久的历史,例如 RMarkdown 和 RStudio。
Quarto 构建于 Pandoc 之上,Pandoc 是一个通用文档转换器,几乎支持你能想到的任何格式。Pandoc 通过将文档表示为一个通用的抽象语法树 (AST) 来实现这一看似神奇的功能,该 AST 作为不同格式之间转换的媒介。通过扩展,Quarto 允许你以几乎任何你想要的格式生成内容!你可以使用 pandoc 过滤器 来修改 AST 和输出格式,这允许你使用任何你想要的静态网站生成器,并以编程方式修改和生成内容。
Quarto 允许你 在处理管道中组合 Pandoc 过滤器,并将它们应用于特定文档或整个项目。你还可以 将过滤器作为 Quarto 扩展分发,这使得 Quarto 具有极高的可定制性。
我们还发现 Quarto 很有吸引力,因为诸如 注释指令(以 #|
开头的注释)之类的用户界面与 nbdev 相关联。事实上,我们甚至了解到 nbdev 在这方面启发了 Quarto!总的来说,Quarto 和 nbdev 有许多共同目标,并且 Quarto 团队对我们的建议反应非常迅速。例如,创建 notebook 过滤器 的能力,以便在渲染之前修改 notebooks。下面是使用 Quarto 和 nbdev 渲染的 Jupyter notebook 截图。
最后,Quarto 支持的编程语言不仅限于 Python,并且正在以惊人的速度添加新功能和修复 bug。这让我们有信心未来能够扩展 nbdev 以支持更多用例。我们在总结部分讨论了其中一些未来方向。
一个极速的 Notebook 内核:execnb
nbdev 的核心组件之一是程序化地执行和测试 notebooks。此 notebook 运行器以最小开销执行以保持我们提供愉悦开发者体验的目标,这一点非常重要。这就是我们构建 execnb 的原因,它是一个轻量级的 Python 内核 notebook 运行器,能够极速执行 notebooks。此外,execnb 支持 notebooks 的参数化执行。
Hamel:我一直是像 papermill 这样程序化运行 notebooks 的工具的热心用户,这些工具可用于 创建仪表盘 或启用 新型机器学习工作流程 等用例。我相信 execnb 凭借其在 notebook 任何位置注入任意代码的能力以及传递在单元格执行之前和/或之后运行的回调的能力,解锁了更多可能性。这开启了使用 notebooks 创建新型工作流程的可能性,我很高兴在不久的将来探索这些可能性。
迈向一种拥抱 Python 动态特性的方言
理解 nbdev 的一种方式是,它是旨在利用 Python 动态特性进行 REPL 驱动软件工程的生态系统的一部分。类似于 Clojure,我们的目标是提供工具,消除在编程工作流程中使用 REPL 的所有障碍。我们相信 REPL 通过上下文感知的自动补全、签名检查和文档(所有这些都基于代码的实际状态)增强了开发者工作流程,而这些功能在仅依赖静态分析的 IDE 中是无法获得的。我们发现正因如此,以 Jupyter notebook 为基础的 nbdev 使得编程效率显著提高,并且更加愉快。
我们支持 REPL 驱动开发和文学化编程的努力不限于 nbdev。我们维护着许多扩展 Python 以增强这种编程体验的库。其中最著名的是 fastcore,它在 测试、 代码文档化、 元编程、 属性助手、 对象增强表示 和 Notebook 友好型 修补(patching) 方面扩展了 Python。这篇 博文 对 fastcore 进行了温和的介绍。除了文学化编程之外,fastcore 还鼓励简洁和有效利用垂直空间等约定,这样你就可以用少得多的代码完成更多工作。例如,下面是一个简单的装饰器,它可以实现 Notebook 友好型 修补(patching)
@patch
装饰器我们相信,这种新的开发者工作流程 (nbdev)、Python 扩展 (fastcore) 和相关规范的结合形成了一种新的 Python 方言,其核心在于利用其动态特性——这与日益增长的 静态分析 趋势形成对比。我们认为这种 Python 方言在许多场景下对程序员来说会更高效。我们将这个生态系统称为一种“方言”,因为它仍然是 Python,并且熟悉该语言的任何人都可以上手。此外,尽管 nbdev 采用 Notebook 工作流程,我们的工具会生成纯文本模块,可以使用基于文本的 IDE 进行导航和编辑,如果他们愿意,程序员可以体验两者的优点。
Hamel:我认为将 nbdev 视为一种 Python 方言是正确理解它的关键。虽然可能会被 nbdev 的特定功能或技术细节所吸引,但从宏观角度理解其创建更好工作流程的整体意图,而不是过于僵化地遵循现有流程,会非常有益。一个很好的类比是 TypeScript 与 JavaScript 的关系:它是对现有编程语言的扩展,支持一种新的编程方式。我鼓励你以类似的方式看待 nbdev:愿意尝试新的编程方式,并观察哪些权衡对你来说更合适。至少,我相信 nbdev 是一种体验不同软件编写方式的有趣方式,它将拓宽你在编程方面的视野,而且无需学习一门全新的编程语言!
nbdev 的未来
虽然我们对 nbdev2 感到兴奋,但我们相信我们只是触及了其可能性的皮毛。我们正在考虑以下功能:
- 支持除 Python 外的更多语言,例如 Julia、R 和 JavaScript
- 提供执行模拟 Python 脚本的参数化 Notebooks 的接口
- 更多静态网站生成器和过滤器的扩展
- 支持其他测试后端,例如 pytest
- 支持更多 docstring 格式,例如 Google 风格 docstrings
- 更多选项来使用除 JSON 以外的纯文本或人类可读的 notebook 后端
如何开始使用 nbdev
我们的项目网站是 nbdev.fast.ai,未来几天我们将在那里发布教程、示例和更多文档。
致谢
nbdev 的这个新版本是许多杰出人士团队合作的成果。我们想重点提及两位做出了杰出贡献的人
Wasim Lorgat 在多个领域发挥了关键作用,包括对 fastcore、execnb 和 nbdev 做出了重要贡献,以及实现了新的 nbdev 主页。在 Wasim 的帮助下,我们得以将 nbdev 的功能和质量提升到新的水平。
JJ Allaire 不仅是 RStudio 的首席执行官,也是 Quarto 的管理者。JJ 对与我们合作 nbdev 反应非常迅速且热情,并专门为 nbdev 在 Quarto 中添加了许多功能,例如 notebook 过滤器。我们还对他们对细节的关注以及修复 bug 的速度感到惊讶。没有 JJ 的帮助,这个新版本的 nbdev 是不可能实现的,我们很高兴能继续与他合作。
我们还要感谢出色的 fastai 社区,特别是 Isaac Flath、 Benjamin Warner 和 Zach Mueller 在这个项目上的不懈努力。
与 JJ Allaire 的对话
为了庆祝 nbdev v2 和 Quarto 的发布,Jeremy 与 Posit(前身为 RStudio,Quarto 背后的公司)首席执行官 JJ Allaire 坐下来,讨论了软件开发、科学出版、R、Python、文学化编程等等。