Gergely Orosz 发起了一个 Twitter 对话,询问为开发团队推荐的“软件工程实践”。
(我真的很喜欢他在这里对“最佳实践”一词的拒绝:我总是觉得将某事宣布为“最佳”是规定性和误导性的。)
我决定将我的一些回复充实到更长的帖子中。
与代码在同一个仓库中的文档
内部文档最重要的特征是信任:人们是否相信文档既存在又是最新的?
如果他们不这样做,他们就不会阅读它或为它做出贡献。
我所知道的提高文档可信度的最佳技巧是将它与它所记录的代码放在同一个存储库中,原因如下:
- 作为代码审查过程的一部分,您可以强制执行文档更新。如果 PR 以需要更新文档的方式更改代码,审阅者可以要求包含这些更新。
- 你会得到版本化的文档。如果您使用的是旧版本的库,则可以查阅该版本的文档。如果您正在使用当前的主分支,您可以查看相关文档,而不会混淆与最新“稳定”版本对应的内容。
- 您可以将文档与自动化测试集成!我在文档单元测试中对此进行了描述,它描述了一种内省代码的模式,然后确保文档至少有一个与特定概念相匹配的节头,例如插件挂钩或配置选项。
创建测试数据的机制
当您处理大型产品时,您的客户不可避免地会发现令人惊讶的方式来给您的系统施加压力或破坏您的系统。例如,他们可能会创建一个包含一百多种不同类型票证的事件,或者一个包含一千条评论的问题线程。
这些可能会暴露不会影响大多数用户的性能问题,但仍可能导致服务中断或其他问题。
您的工程师需要一种在他们自己的开发环境中复制这些情况的方法。
处理此问题的一种方法是提供将生产数据导入本地环境的工具。这会影响隐私和安全——如果开发人员笔记本电脑被盗而恰好有您最大客户的数据副本怎么办?
更好的方法是建立一个健壮的系统来生成测试数据,涵盖各种不同的场景。
您可能在某处有一个按钮,该按钮创建一个带有一千条虚假评论的问题线程,并附有一条注释,引用了有助于模拟的错误。
每当出现新的边缘案例时,您都可以向该系统添加新配方。这样工程师就可以在本地复制问题,而无需生产数据的副本。
坚如磐石的数据库迁移
大规模软件维护中最困难的部分不可避免地是您需要更改数据库模式的地方。
(我相信 NoSQL 数据库在过去十年中流行的最大原因之一是人们因模式更改而与关系数据库相关联的痛苦。当然,NoSQL 数据库模式修改仍然是必要的,而且通常它们甚至更痛苦!)
因此,您需要投资一个非常好的、版本控制的机制来管理模式更改。以及一种无需停机即可在生产中运行它们的方法。
如果你没有这个,你的工程师会害怕模式改变来回应。这意味着他们会想出越来越复杂的黑客来避免它们,这会增加技术债务。
这是一个深刻的话题。我主要将 Django 用于大型数据库支持的应用程序,而 Django 拥有我亲身体验过的最好的迁移系统。如果我在没有 Django 的情况下工作,我会尝试尽可能地复制它的方法:
- 数据库知道已经应用了哪些迁移。这意味着当您运行“迁移”命令时,它可以只运行仍然需要的那些——这对于管理多个数据库很重要,例如生产、登台、测试和开发环境。
- 应用挂起迁移并更新记录已运行迁移的数据库行的单个命令。
- 可选:回滚。 Django 迁移可以回滚,这对于在开发环境中进行迭代非常有用,但在生产环境中使用它实际上非常罕见:我经常发布一个新的迁移来反转更改而不是使用回滚,部分原因是为了保持记录版本控制中的错误。
更难的是在不停机的情况下进行模式更改。我一直有兴趣阅读有关这方面的新方法 – GitHub 的gh-ost是 MySQL 的一个很好的解决方案。
这里一个有趣的考虑是,应用程序代码和数据库模式更改几乎不可能在完全相同的实例中及时发生。因此,为了避免停机,您需要在设计每个架构更改时都考虑到这一点。该过程需要是:
- 设计一个可以在不更改使用它的应用程序代码的情况下应用的新模式更改。
- 将该更改交付到生产环境,升级您的数据库,同时保持旧代码正常工作。
- 现在发布使用新模式的新应用程序代码。
- 发布一个新的架构更改,以清理任何剩余的工作——例如,删除不再使用的列。
这个过程很痛苦。很难做对。掌握它的唯一方法是随着时间的推移大量练习。
我的规则是:架构更改应该是无聊和常见的,而不是令人兴奋和罕见的。
新项目和组件的模板
如果您正在使用微服务,您的团队将不可避免地需要构建新的。
如果您在 monorepo 中工作,您的代码库中的元素仍然具有相似的结构——组件和某种功能实现。
确保有非常好的模板来创建这些“正确的方式”——具有正确的目录结构、自述文件和带有单一、愚蠢的通过测试的测试套件。
我喜欢为此使用 Python cookiecutter工具。我还使用了 GitHub 模板存储库,我什至有一个巧妙的技巧将两者结合起来。
这些模板需要维护并保持最新。最好的方法是确保它们被使用——每次创建新项目时,都有机会修改模板并确保它仍然反映推荐的做事方式。
自动代码格式化
这个很容易。为你的语言选择一个代码格式化工具——比如用于 Python 的Black或用于 JavaScript 的Prettier (我非常嫉妒 Go 是如何内置gofmt的)——并在你的 CI 流中运行它的“检查”模式。
不要与它的默认值争论,只要承诺它们。
这在两个地方节省了大量时间:
- 作为一个人,你会找回你曾经花在思考格式化代码的最佳方法上的所有精神能量,并且可以把它花在更有趣的事情上。
- 作为一个团队,您的代码审查可以完全跳过关于代码格式的迂腐争论。巨大的生产力胜利!
针对新开发环境的经过测试的自动化流程
任何软件项目中最痛苦的部分是不可避免地设置初始开发环境。
当您的团队超过几个人时,您应该投资于使这项工作更好。
至少,您需要一个记录在案的过程来创建一个新环境——并且它必须是已知的,因此无论何时有人使用它,都应该鼓励他们修复文档或随附脚本中的任何问题他们遇到他们。
更好的是一个自动化的过程:一个让所有东西都启动并运行的单一脚本。在过去的十年里,像 Docker 这样的工具让这件事变得容易多了。
我越来越相信这里最好的解决方案是基于云的开发环境。单击网页上的按钮并在几秒钟后运行一个全新的、可工作的开发环境的能力是大型开发团队的游戏规则改变者。
Gitpod和Codespaces是我在这个领域尝试过的两个最有前途的工具。
我看到开发人员每周都会因开发环境问题而浪费数小时。在一个大团队中消除这一点就相当于雇佣了几个新的全职工程师!
自动预览环境
如果您可以实际尝试更改,则查看拉取请求会容易得多。
最好的方法是使用自动预览环境。
这些变得越来越容易提供。 Vercel 、 Netlify 、 Render和Heroku都有可以做到这一点的功能。在Google Cloud Run或Fly Machines等系统之上构建自定义系统也可能需要一些工作。
这是另一件需要一些前期投资的事情,但会通过提高生产力和评论质量而获得多次回报。
原文: http://simonwillison.net/2022/Oct/1/software-engineering-practices/#atom-everything