软件工程一些最佳实践 - simonwillison


许多团队也将考虑“最佳实践”的一些软件工程实践,下面是一些建议:

1、文档与代码在同一个 repo 中的
内部文件最重要的特点是信任:人们是否相信文件既存在又是最新的?

如果他们不相信,他们就不会去读它或为它做贡献。

我所知道的提高文档可信度的最好的技巧是把它和它所记录的代码放在同一个仓库里,原因有以下几点。

  • 你可以把文档更新作为代码审查过程的一部分。如果一个PR修改代码的方式需要文档更新,审查者可以要求包括这些更新。
  • 你可以得到有版本的文档。如果你正在使用一个库的旧版本,你可以查阅该版本的文档。如果你使用的是当前的主分支,你可以看到该分支的文档,而不会因为什么是最新的 "稳定 "版本而感到困惑。
  • 你可以将你的文档与你的自动化测试结合起来!我在《文档单元测试》中写到了这一点,它描述了一个内省代码的模式,然后确保文档至少有一个与特定概念相匹配的章节标题,如插件钩子或配置选项。

2、创建测试数据的机制
当你在大型产品上工作时,你的客户将不可避免地找到令人惊讶的方式来强调或破坏你的系统。例如,他们可能会创建一个有超过一百种不同类型的票据的事件,或者一个有一千条评论的问题线程。

这些都会暴露出不影响大多数用户的性能问题,但仍然可能导致服务中断或其他问题。

你的工程师需要一种方法来在他们自己的开发环境中复制这些情况。

处理这个问题的方法之一是提供工具,将生产数据导入本地环境。这涉及到隐私和安全问题--如果一个开发人员的笔记本电脑被偷了,而这个笔记本电脑恰好有一份你最大客户的数据,怎么办?

一个更好的方法是有一个强大的系统来生成测试数据,涵盖各种不同的场景。

你可能会在某个地方有一个按钮,用来创建一个有一千条假评论的问题线程,并在上面注明这有助于模拟的错误。

任何时候有新的边缘案例出现,你就可以给这个系统添加一个新的配方。这样,工程师就可以在本地复制问题,而不需要生产数据的副本。

3、坚如磐石的数据库迁移
在大规模的软件维护中,最困难的部分不可避免地是你需要改变你的数据库模式的部分。

(我相信,NoSQL数据库在过去十年中流行起来的最大原因之一是人们与关系型数据库因模式变化而产生的痛苦。当然,NoSQL数据库模式的修改仍然是必要的,而且往往是更痛苦的!)

因此,你需要投资于一个真正好的、版本控制的机制来管理模式变化。还有一种方法可以在生产中不停机地运行它们。

如果你没有这样的机制,你的工程师就会对模式变化产生恐惧感。这意味着他们会想出越来越复杂的黑客手段来避免这些变化,这就造成了技术债务的堆积。

这是一个很深的话题。我主要使用Django来开发大型数据库支持的应用程序,Django拥有我个人经历过的最好的迁移系统。如果我在没有Django的情况下工作,我会尽可能地复制它的方法。

  • 数据库知道哪些迁移已经被应用了。这意味着当你运行 "migrate "命令时,它可以只运行那些仍然需要的迁移--这对于管理多个数据库(例如生产、暂存、测试和开发环境)非常重要。
  • 一个单一的命令可以应用未完成的迁移,并更新数据库中记录哪些迁移已经运行的行。
  • 可选:回滚。Django迁移是可以回滚的,这对于在开发环境中进行迭代是非常好的,但是在生产环境中使用回滚的情况实际上是非常少的:我通常会发送一个新的迁移,以扭转变化,而不是使用回滚,部分原因是为了在版本控制中保留错误的记录。

更难的是在不停机的情况下进行模式改变的挑战。
我总是有兴趣了解这方面的新方法:GitHub gh-ost 是MySQL的一个很好的解决方案。

这里的一个有趣的考虑是,很少有可能让应用程序代码和数据库模式的变化在同一时间进行。因此,为了避免停机,你需要在设计每一个模式变化时考虑到这一点。这个过程需要。

  1. 设计一个新的模式变化,可以在不改变使用该模式的应用程序代码的情况下应用。
  2. 将该变化发送到生产中,升级你的数据库,同时保持旧代码的工作。
  3. 现在发送使用新模式的新应用程序代码。
  4. 发送一个新的模式变化,清理任何剩余的工作--例如,删除不再使用的列。

这个过程是一个痛苦的过程。它很难做到正确。唯一的方法是随着时间的推移不断地练习,以获得良好的效果。

我的原则是:模式的改变应该是枯燥和常见的,而不是令人兴奋和罕见的。

4、新项目和组件的模板
如果您使用微服务,您的团队将不可避免地需要构建新服务。
如果您在 monorepo 中工作,您的代码库中仍然会有具有相似结构的元素——组件和某种功能实现。
一定要有真正好的模板来创建这些“正确的方法”——具有正确的目录结构、README 和带有单一、愚蠢的通过测试的测试套件。
为此,我喜欢使用 Python cookiecutter工具。我还使用了 GitHub 模板存储库,我什至有一个巧妙的技巧可以将两者结合起来
这些模板需要维护并保持最新。做到这一点的最好方法是确保它们被使用——每次创建新项目时都有机会修改模板并确保它仍然反映推荐的做事方式。

5、自动代码格式化
这个很简单 为你的语言选择一个代码格式化工具——比如Python的Black或 JavaScript 的[url=https://prettier.io/]Prettier[/url](我非常嫉妒 Go内置gofmt的方式)——并在你的 CI 流中运行它的“检查”模式。
不要争论它的默认值,只需遵守它们。
这在两个地方节省了大量时间:

  • 作为个人,您可以收回过去用于思考格式化代码的最佳方式的所有精力,并可以将其用于更有趣的事情。
  • 作为一个团队,您的代码审查可以完全跳过关于代码格式的迂腐争论。巨大的生产力胜利!

6、针对新开发环境的经过测试的自动化流程
任何软件项目中最痛苦的部分是不可避免地设置初始开发环境。
当你的团队发展到不止几个人的时候,你就应该投资让这项工作变得更好。
至少,您需要一个用于创建新环境的文档化流程——并且它必须是已知的,因此任何时候有人开始使用它时,都应该鼓励他们解决文档或随附脚本中的任何问题,因为他们遇到了他们。
更好的是一个自动化的过程:一个单一的脚本来启动和运行所有的东西。在过去十年中,像 Docker 这样的工具让这一切变得容易多了。
我越来越相信这里最好的解决方案是基于云的开发环境。单击网页上的按钮并在几秒钟后运行一个全新的工作开发环境的能力对于大型开发团队来说是一个游戏规则的改变者。
GitpodCodespaces是我在这个领域尝试过的两个最有前途的工具。
我见过开发人员每周都会因为他们的开发环境问题而损失几个小时。在大型团队中消除这一点相当于雇用了几名新的全职工程师!

7、自动预览环境
如果您可以实际尝试更改,那么审查拉取请求会容易得多。
最好的方法是使用自动预览环境,直接链接到 PR 本身。
这些变得越来越容易提供。VercelNetlifyRenderHeroku都有可以做到这一点的功能。通过一些工作,也可以在Google Cloud RunFly Machines之类的东西之上构建自定义系统。
这是另一件需要一些前期投资的事情,但会通过提高生产力和评论质量多次获得回报。