我如何构建 Python Web 框架并成为一名开源维护者
注意
这篇文章最初发表于blog.florimond.dev。
我已经有一段时间没写博客了。实际上,差不多两个月了。那么,我最近都去哪儿了呢?
首先,工程学最后一年占用了我比预想的更多时间。不过我并不抱怨——我学到了很多有趣又实用的东西,既有理论知识,也有实践经验。而且,我想借此机会充分享受这最后一年。
故事的另一面是——我一直在构建Bocadillo,一个开源的异步 Python Web 框架。这段旅程最初是为了让我了解 Web 框架的内部原理,但到目前为止,它一直令人兴奋不已。
这意味着,因为一天只有24小时,我不得不暂时放下博客。不过现在放假了,我终于可以抽出时间回顾一下这段时间发生的事情了。🥳
在这篇博文中,我想记录下我构建 Web 框架,尤其是启动一个开源项目的整个过程。从编程技巧到项目管理以及开发工具,我已经学到了很多东西,所以我想和大家分享我的经验!
菜单上有什么?
首先,让我来向你介绍一下 Bocadillo!(我保证,这次见面会很简短,也很精彩。)
Bocadillo 是什么?
(未维护)为每个人提供快速、可扩展且实时的 Web API
注意
Bocadillo 现已处于“未维护”状态。此仓库应该很快就会被归档。我们建议用户迁移到其他支持良好的替代方案,例如Starlette或FastAPI。更多信息请参阅#334 。

文档:https://bocadilloproject.github.io
Bocadillo 是一个Python 异步 Web 框架,它使构建高性能、高并发的 Web API 变得有趣且每个人都可以访问。
要求
Python 3.6+
安装
pip 安装 bocadillo
例子
从 bocadillo 导入 App,配置
应用程序 = 应用程序()
配置(应用程序)
@ app.route ( “/
” ) asyncdefindex ( req , res ) : res.json = { “ hello ”
: “ world ” }
将其保存为app.py
,然后启动uvicorn服务器(已启用热重载!):
uvicorn 应用程序:应用程序——重新加载
问好!
$ curl http://localhost:8000
{ “你好世界” }
准备好深入了解了吗?请访问文档网站。
变更日志
Bocadillo 的所有更改都记录在...
电梯演讲
Bocadillo 是一个现代的 Python Web 框架,它提供了一个健全的工具包,用于使用异步编程构建高性能 Web 应用程序和服务。它兼容 Python 3.6+ 并遵循 MIT 许可证。
想开始吗?阅读文档!
关键数据
Bocadillo 的首次提交是在 2018 年 11 月 3 日。截至 12 月 21 日,即一个半月后,Bocadillo 的情况如下:
这些数字当然很保守,但我已经很满意了。当然,如果你想支持 Bocadillo,你可以:
此外,如果您已经尝试过 Bocadillo,请通过 Twitter 或Gitter聊天室与我联系- 我很乐意听到您的声音!
哲学
从理念上来说,Bocadillo 对初学者友好,但同时也致力于为高级用户提供所需的灵活性。它注重开发者体验,同时鼓励最佳实践。
此外,Bocadillo 并非旨在追求极简主义(但也不是庞然大物)。其理念是包含一组精心挑选的内置功能,并设置合理的默认设置,以便您能够解决常见问题并立即提高工作效率。
目标
我的目标是让人们接受异步 Python 的新可能性,并让 Bocadillo 成为一种帮助人们更轻松、更高效地解决现实问题的工具。
要达到这个目标还有很多工作要做,但是马拉松已经开始了!
说到异步Python,让我来回答一个你可能已经问过自己的问题……
异步怎么样?
通常,Web 应用程序实例会花费大量(如果不是大部分)请求处理时间等待 I/O 完成 - API 调用、数据库查询、文件系统操作等。大多数这些操作都是阻塞的,如果多个客户端请求服务器,这通常会限制性能。
像 Bocadillo 这样的异步框架旨在构建不会阻塞 I/O 操作的应用程序。为了实现这一点,我们利用了异步编程以及 Python 语言的最新功能,例如asyncio和async/await——分别在 Python 3.4+ 和 3.6+ 版本中提供。这使得我们可以将处理请求视为一个“计划”在不久的将来(即 CPU 可用时)运行的任务。
因此,除了更好地利用 CPU 之外,这种架构还有一个非常有趣的优势——我们现在可以同时处理多个请求。
(注意:我没有写并行,因为异步仍然使用单个线程。并发不是并行。)
随着并发客户端数量的增加,这一特性最终会带来更稳定的吞吐量和性能。根据我自己(尚未发布)的基准测试,无论与 10 个还是 10,000 个客户端通信,Bocadillo 都能保持稳定的处理速率。另一方面,像 Flask 或 Django 这样的“同步”框架在高并发设置下,每秒请求数会显著下降。
想要了解更多关于 Python 异步编程的知识吗?以下是我推荐的几个讲座,可以按以下顺序观看:
执行
Bocadillo 基于Uvicorn(闪电般快速的 ASGI Web 服务器)和Starlette (便捷的 ASGI 工具包)构建。两者都是由Tom Christie创建的,他是 Django REST 框架的核心贡献者(以及其他贡献者)。
注意:ASGI是 WSGI 的异步版本,即有关 Web 服务器如何与异步Python Web 应用程序通信的规范。
特征
Bocadillo 已包含:请求、响应、视图(基于函数和基于类)、路由和路由参数、媒体类型、重定向、模板、静态文件、后台任务、CORS、HSTS、GZip、“recipes”(又称蓝图)、中间件、钩子,甚至还有 CLI。更多功能正在发布中!
不过,Bocadillo 目前还缺少数据库层。我构建的大多数 Web 应用或 API 都需要以某种方式持久化数据,所以我相信这一点(或者至少官方会建议如何集成异步数据库层,比如Tortoise ORM)应该在某个时候融入到框架中。
你好世界!
让我们以传统的“Hello, World”脚本结束吧!
# api.py
from bocadillo import API
api = API()
@api.route("/")
async def hello(req, res):
res.text = "Hello, World!"
if __name__ == "__main__":
api.run()
背后的故事
好了,关于 Bocadillo 的介绍就到此为止!既然你已经知道它是什么了,我想跟你分享一下促使我写这篇博文的故事。
它是如何开始的?又为何开始?其中有哪些最有意义的事件?让我们来一探究竟。
边做边学的项目
最初,Bocadillo 是让我深入了解 Web 框架内部原理的一种方式。在使用了近两年各种 Python 和 JS Web 框架之后,我希望能深入了解这些框架的幕后原理。我想知道它们究竟是如何运作的。
需要说明的是,Bocadillo 一开始并没有一个非常详细的计划。哎呀,我甚至都没想过是否需要另一个 Python 异步 Web 框架。我当时只想学习,什么都不想。
让我们重新发明轮子,并尽快发布它
于是,在 11 月 3 日那天,我开始实现一些非常常见的功能,感觉就像在重新发明轮子一样。这些功能包括请求、响应、视图、路由或应用服务器。“之前已经有数百个 Web 框架解决了这些问题”,我心想……
但我其实不在乎。正如@funkybob在推特上好心发给我的:
重新发明轮子是一种很棒的学习方式......有时你所学到的只是你现有的框架为你做了多少事情。
支持重新发明轮子的有力论据让我意识到 Django 是一个多么庞大的野兽。
无论如何,最初的努力最终让我于 11 月 4 日在 PyPI 上发布了v0.1 版本。首次提交仅两天后,人们就能够pip install bocadillo
构建一个极简的异步 Web 应用了。(谁说 Python 打包很麻烦?🐍)
潜力的初步迹象
v0.1 发布后,我继续实现更多功能,例如新类型的响应或错误处理。
11月6日,v0.2.1 版本发布。从那时起,我开始意识到 Bocadillo 很适合我的第一个成熟开源项目。这个想法很吸引我,所以我就这么做了!
那时,我还没有透露任何关于 Bocadillo 的消息,甚至连朋友都没透露过,所以我想先公开消息。我选择在 Twitter 上发布。
由于 Bocadillo 的初始代码设计和实现深受Kenneth Reitz 自己的异步框架Responder的启发,我决定向它致敬。

Twitter 上关于 Bocadillo 的第一个公告,以及 Kenneth Reitz 的回答。❣️
Kenneth 的回答以及他转发该公告后的反应让我认为Bocadillo 确实很有潜力。
仅仅一天时间,这个 repo 就获得了 20 颗星(这已经是个人最高纪录了!),尽管这看起来微不足道,但我认为这真的很酷。
嘘:如果您想帮助 Bocadillo 出名,您也可以为其加星标并传播这个消息!
因此,在 v0.2 发布后,我感到有动力继续开发 Bocadillo,并添加更多功能。
直到我意识到一些事情……
文档在哪儿?真的文档吗?
我很清楚:我希望 Bocadillo 成为我的第一个开源项目。我希望认真对待它,以便从中尽可能多地学习。
因此,从一开始,我就编写了一份内容详尽的README 文件,整理了一份CHANGELOG(借助keep a changelog功能),并添加了贡献指南。随着 11 月 6 日至 11 月 18 日之间越来越多的版本发布,我更新了变更日志,并在代码库的 README 文件中记录了新功能。
但很快,这种做法就变得不切实际了。README 文件越来越大,即使有目录,导航也变得很困难。

这是 11 月 17 日 repo 的目录。看到“使用情况”部分变得多么庞大了吗?
就在那时我意识到我需要适当的文件。
如果你仔细想想,好的文档是让人们使用你所构建的东西的必要条件。而考虑到 Bocadillo 的规模,冗长的 README 并不算好的文档。
然后,我突然意识到——我使用和喜爱的许多大型开源工具、库或框架都有一个文档网站。
这就是促使我于 11 月 18 日发布 v0.5 的原因,它有一个重要的附加功能:一个全新的文档网站,我用VuePress构建并托管在GitHub Pages上。

Bocadillo 的文档站点主页(2018 年 11 月底)。
关于良好文档的必要性——Masonite 框架的创建者 Joe Mancuso曾经与我分享过这条很好的建议:
如果没有记录,它就不存在。
这就是为什么我非常重视文档并努力使其尽可能完美——你正在从事的每个项目也应该如此。
然后,在构建文档站点时,我做出了现在认为对于任何开源项目来说都非常重要的决定……
让 Bocadillo 独立发展
在发布文档之前,我将 Bocadillo 从个人仓库移至其自己的 GitHub 组织,即BocadilloProject。
当时我的主要动机是想用该组织的 GitHub Pages 域名bocadilloproject.github.io
来存放文档。它绝对比 GitHub Pages 更简洁、更易访问florimondmanca.github.io/bocadillo
。🙃
然而,这也带来了积极的效果,让 Bocadillo 拥有了属于自己的在线空间。它不再与我的个人 GitHub 帐户绑定——该组织成为了 Bocadillo 源代码的新家。
后来,当我意识到 Bocadillo 公告正在接管我的个人 Twitter 帐户时,我创建了一个专用的 Twitter 帐户。
重点是:开源项目的存在不受其创建者的影响,这一点很重要。
现在,回到故事本身——11 月 18 日,我上线了一个文档网站,供大家访问。接下来呢?
开放开发流程
截至 11 月 20 日,我都是通过私人 Trello 板来跟踪积压工作和进度。
这对我来说非常实用:我用 Trello 做各种各样的事情。但我意识到访问这个代码库的人根本不知道接下来会发生什么,也不知道他们能做出什么贡献。
事实上,从访问者的角度来看,我认为这个 repo 看起来就像任何其他个人项目一样 —— 没有问题,没有 PR,只是来自一个人的大量提交 —— 而不是社区驱动的努力,也就是我希望 Bocadillo 成为的样子。
因此,根据我的一位密友的建议并受到Dhanraj Acharya 的这篇文章的启发,我决定公开开发过程。
我把所有 Trello 卡片都转换成了 GitHub 问题,并添加了有意义的标签(参见Dave Lunny 的Sane GitHub 标签)和描述。我觉得现在的仓库能更好地展示项目,也让新手更有动力。
我从中认识到,开源不仅仅意味着开放源代码。你还必须对开发过程保持开放态度。
我现在希望,通过充满问题和公共 PR 的 repo,它将吸引第一批开源贡献者。
剧透警告:确实如此!
耶!第一批贡献者!
大约在同一时间,随着 Bocadillo 规模的扩大,我开始感到需要外部建议。我担心自己可能会做出错误的设计决策,或者代码本来可以更好。简而言之,我需要贡献者。
幸运的是,11 月 20 日,我非常高兴地迎来了对该 repo 的第一位贡献者,Alin Panaitiu对新“hooks”功能的PR #3进行了评论。
Alin 帮我修复了一些我最初不太确定的功能问题,并提出了一些改进建议,使其更加实用。他甚至 fork 了这个代码库,并给我发了一个 diff 来展示修复后的版本。
后来,11 月 23 日,Alin 的第一个 PR 被合并了。Bocadillo 正式迎来了第一位贡献者!🎉

PR #18 的屏幕截图。
我非常感动。
更棒的是,Alin 居然坚持了下来。在 v0.7 版本中,Alin 贡献了两个新功能(GZip 和 ASGI 中间件),从代码到合并的时间大概不到几个小时。谢谢 Alin,太棒了!
进入维护模式
从11月底开始,项目的进度慢了下来。一方面,我有点着急,学校的项目和考试都排在日程表上,但这并不能解释一切。我经历了一些其他的事情。
你知道,一开始,向 Bocadillo 提交代码感觉很容易。几乎没有什么遗留问题,所以很兴奋,我有很多想法。一切都还有待完成。
但随着功能的增加,工作量开始加大。发布时间也变长了——从几天变成了一周。测试、重构和文档撰写成了开发流程的主要部分。此外,我现在还负责管理 Bocadillo 的线上业务。
别误会——我没抱怨。事实上,我很高兴能够克服最初的兴奋,进入维护模式。此外,对于一个试图获得发展动力并接触社区的项目来说,这绝对是正常的转变。
现在我很享受开发 Bocadillo 的过程,不用像刚开始那样耗费我晚上的时间了。这引出了我的下一个想法……
这不是短跑,而是马拉松
我最近注意到我对这个项目的态度发生了变化。
我现在不再急于尽快推出功能,并希望大量用户涌入,大量发送星星,喜爱这个框架并乞求更多,而是更加平静地接受项目增长缓慢的想法。
这是因为维护一个开源项目是一场马拉松,而不是短跑。
换句话说,成功应该永远是一个副产品,而不是目标。
你可能已经注意到,Bocadillo 的目标声明中没有提到名气,也没有提到用户数量的门槛。它只是说,我希望 Bocadillo 能帮助一些人解决问题。如果至少有一个人实现了这一点,我就认为这是一个胜利。如果很多人都实现了这一点,我就只会把它看作是一个副作用。

两个人站在灰色瓷砖路面上。@goian,unsplash.com
这就是 Bocadillo 背后的故事!正如你可能从这些讨论中注意到的那样,到目前为止,我一直很享受这段经历,而且现在我确信,当我决定克服对评判的恐惧,构建自己的 Web 框架时,我做出了正确的决定。这也引出了这篇博文的最后一部分。
启动您自己的开源项目的技巧
如果我希望你从这篇文章中得到什么,那一定是这样的:
开源是一种很棒的学习方式。你今天就应该开始自己的项目!
“听起来不错”,你想,“但我该怎么做呢?你有什么建议吗?”
嗯,我确实有一些。😋
首先,也是最重要的,尽可能多地学习,并确保自己乐在其中。开源永远不应该成为你的负担,如果真的成为了负担,试着找到可以委托他人或依靠社区来推动项目前进的方法。
对于其余部分,请做好准备——前面有分类的要点!
注意:如果您不确定如何实现以下任何项目和/或想了解我在实践中如何使用或配置工具,请随时查看Bocadillo 的 repo并复制您感兴趣的部分 - 毕竟它是开源的!
项目定义
- 决定您想要构建什么。
- 决定你为什么要构建它——尽管它不必很深奥或抽象,但有明确的动机来源会有所帮助。
- 考虑范围和设计理念:这将有助于做出明智的设计决策,并防止功能蔓延。
- 确定您的目标客户:您的用户是 Web 开发人员、系统管理员、项目经理……?
- 明确定义用户技能期望:您的用户应该熟悉什么,以及熟悉程度如何?
- 决定如何分发您的项目(例如 PyPI 包)。
营销与传播
- 建立身份:至少要有一个名字和一个标语。尽量简短、醒目、易记。并在各个地方展示它们(代码库、PyPI 页面、文档网站……)。
- 创建视觉识别:这是您的标志和图形章程。一个可以接受的临时标志总比没有标志好。
- 确定一个入口点,即一个人们可以自然地在线查找你的项目的位置。它可以是 GitHub 仓库、文档网站,或者任何合适的地方,但必须存在。(对于 Bocadillo 来说,我相信入口点是文档网站。)
- 让您的项目拥有自己的生命:创建一个单独的 GitHub 组织或社交媒体帐户是一个好主意。
- 使用社交媒体来传播新闻、公告和提示,并开始聚集人们参与项目(我使用 Twitter 来实现这一点)。
- 为人们提供了解您前进方向的方法——路线图、问题列表、变更日志中的“未发布”部分等。
社区
- 实施开源最佳实践:完善的README 文件、贡献指南、行为准则、问题/PR 模板等等(使用 GitHub 的清单!)。这将使代码库更受潜在贡献者的欢迎,并展现您对社区的关心。
- 支持他人并友善待人。感谢他们的提问。提供有用的资源。
- 创建一个非正式讨论的场所或许是个好主意。我最近决定尝试一下Gitter聊天室。
项目管理
- 使用GitHub Issues列出你的待办事项。这样,当你还在犹豫下一步该做什么时,只需提交工单,开始处理即可!
- 设置有意义的问题标签(请参阅Sane GitHub Labels)。
- 您还可以设置一个GitHub 项目来在看板中显示您的问题和 PR。
代码质量
- 设置CI/CD 管道。
- 对测试要毫不宽容——除了确保您的软件按预期运行之外,它们还会帮助您和每个人捕捉回归并在进行更改时充满信心(我使用pytest作为测试框架)。
- 测量测试覆盖率(我使用pytest-cov进行 pytest/coverage.py 集成,使用CodeCov进行覆盖率报告)。
- 强制PR 在合并之前通过测试。
- 每个 PR 都应包含所有 3 个项目:代码、测试和文档。
- 使用代码格式化程序来减少代码审查中的语法/代码样式噪音(我使用自以为是的Black格式化程序以及预提交钩子)。
- 如果你没有其他审阅者,可以给自己发 PR,让他们先处理一下,过几天再回来。这样更容易看出代码是否乱了。
文档
- 编写一份清晰且信息翔实的自述文件,其中至少包含项目描述、安装说明、快速启动示例以及文档链接或用户可以了解更多信息的地方。
- 保留更新日志,您以后会感谢自己的。
- 如果您要构建的不仅仅是一个简单的库,请构建一个文档站点(我使用VuePress作为静态站点生成器)。
- 构建您的文档:教程、讨论、操作方法、参考(提示:我使用PydocMd直接从我的 Python 文档字符串生成 Markdown API 参考)。
- 请记住:如果没有记录,它就不存在。
- 在您的 README 中添加漂亮的徽章(例如使用shields.io)。
版本控制和发布
- 使用语义版本控制(参见SemVer)。
- 使用bumpversion等工具自动进行版本升级。
- 自动化发布流程。我使用TravisCI将标记的提交发布到 PyPI。
- 设置特殊的发布分支。例如,我用于
release/docs
文档部署和release/test
发布到测试 PyPI。
成就解锁了吗?
这篇博文即将结束,让我们总结一下吧!
尽管 Bocadillo 最初只是让我了解 Web 框架内部结构的一种方式,但它现在已经变成了一个成熟的开源项目。
我已经付出了很多努力来构建框架、记录框架、配置 repo 和管理版本,现在我开始将自己视为一名开源维护者——我认为这是一次非常丰富的经历!
虽然我为自己迄今为止取得的成就感到自豪,但这一切也让我感到谦卑。我现在意识到管理一个开源项目是多么具有挑战性,更不用说围绕它建立一个社区了。这太难了!
话虽如此,我确实相信你应该去尝试并创建自己的开源项目。它可以是一个简单的工具或库,也可以是一整套应用程序框架——无论哪种方式,你都会在这个过程中学到很多东西。
当然,如果您正在寻找构建开源项目或设置工具的灵感,欢迎随时查看Bocadillo 仓库。opensource.guide上也有大量精彩资源,不妨也看看这个网站!
感谢您阅读本文!一如既往,我们非常欢迎您的反馈。我尤其想听听您维护开源项目的故事。另外,如果这篇文章对您有所启发,请务必留言!❣️
祝大家节日快乐。✌️
保持联系!
如果您喜欢这篇文章,您可以在 Twitter 上找到我,了解更新、公告和新闻。🐤
鏂囩珷鏉ユ簮锛�https://dev.to/bocadillo/how-i-built-a-python-web-framework-and-became-an-open-source-maintainer-3okd