![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
协议是软件开发的重要组成部分。它们降低了开发成本并使开发人员的生活更轻松。但有一个问题——它们常常使事情复杂化,因为它们没有被适当地记录下来,也没有像古老的童话那样通过口口相传在团队中传达。在传播的同时,协议也发生了变化。突然,新的细节出现了,旧的细节消失了。到最后,每个团队成员的脑海中都有自己的协议画面,甚至那幅画面有时也会消失。
更糟糕的是 - 当团队开始记录这些协议时,他们会随意地做,并且经常会创建一堆松散耦合的文档,其中一半甚至都不是最新的。
在本文中,我将告诉您记录协议的正确方法,它们会对您有所帮助。
那么,我们怎样才能使协议有用呢?我们不仅要记录它们,还要这样做:
它们易于使用;
遵循这些协议需要最少的努力;
如果这些协议仍然有效,将很容易理解;
很容易理解为什么这些协议会存在;
理想情况下 - 它们是自动化的。
人们可以想出很多方法来对协议进行分类。我将按它们的抽象级别将它们分开:
不同级别的协议需要不同的方式来记录它们并带来不同的好处。让我们来看看每个级别。
这些协议的目的是使代码统一、全面和可读。这里有些例子:
我们使用双引号而不是单引号。
除了在Config
类中,我们不直接从代码中调用 ENV,我们在其中将这些调用包装到方法中。
服务对象有后缀Service
和一个公共方法call
。
创建这些类型的协议是为了降低读者的认知负担并帮助他更快地习惯未知代码。正如 Martin 所说,阅读代码的次数是编写代码的 10 倍。
尽管您对 Ruby on Rails 框架有意见 - 它的核心具有令人难以置信的convention over configuration
,它允许任何 Rails 开发人员打开其他人的项目并立即很好地导航它。
那么如何记录这些约定呢?棉绒工具!如果没有合适的 linter 规则,请自己编写 lint。几乎每个 linter 都允许您这样做:这是Go 语言的示例,这是Ruby的示例。
将 linter 用于此类约定可为您带来三个好处:
开发人员无需考虑它们 - linter 会突出显示每个错误,甚至通常会为您修复它们。
如果你在你的团队中使用代码审查——你可以让你的审查者摆脱对这些事情的思考,并给他们更多的时间来关注更重要的事情。
开发人员会在开发周期的一开始就发现问题,因此他会立即解决问题,而无需花时间稍后返回上下文。遵守协议变得更便宜。
还有一个好处:编写新的 linter 规则是对初级开发人员的极好的培训。在完成这项任务的同时,他将学到很多关于代码解析和构建 AST 的知识,并更深入地理解语言。
这是一种更高级别的协议,旨在使您的架构周到、连贯和统一。几个例子:
我们在系统的高负载部分使用 Python 编写常规服务和 Elixir。
后端以描述的格式返回错误。
每个服务都需要在prometheus中发送指标,在/metrics
端点上,发送指标的端口由PROMETHEUS_PORT
环境变量配置。
这样的协议不仅减少了认知负担,还解决了另外三个问题:
降低运营成本。如果服务以相同的方式启动,使用相同的日志格式,发布相同的指标,那么维护服务和应对事件就会容易得多。
降低设计成本。开发人员不需要每次都从头开始设计架构——你提前想到了,现在他只需要设计一个特定的功能或服务,而不用担心基本的东西。
降低沟通成本。如果 Kafka 中服务器的响应或事件格式是预先确定的,那么开发人员就不需要每次都讨论他们的交互,而是可以简单地参考约定。
此类协议更复杂,我更喜欢分两步修复它们。
第 1 步 - 描述
Architecture Decision Record (ADR) 是一种用于记录此类协议的工具。它的魅力在于它捕获元信息和协议:为什么采用这样的协议;讨论了哪些备选方案;上次修订的时间;协议还有效吗?
这可以让新团队成员了解做出决定的原因,而不是问周围的人。
ADR 由几个主要模块组成:
协议解决什么问题?
考虑了哪些解决问题的选择,它们的优缺点是什么?
最后选择了哪个选项?
可能有额外的块 - 例如,实施成本计算。
将 ADR 保存在一个可以查看更改和讨论历史的系统中会更方便。我的选择是 Github 和 Notion,各有利弊。 Github 的优势在于它有开箱即用的审查工具和版本历史记录。由于使用数据库和标签的便利性,概念可能是一个很好的解决方案。而且 - 非开发人员可以轻松处理它。
如果您想开始使用 ADR,我建议您查看存储库,您可以在其中找到不同的 ADR 模板以及如何使用它们的示例。
第 2 步 - 自动化
ADR 的自动化比代码级约定更具挑战性:设计 linters 尚未发明(可惜!)。然而,可以部分自动化它们,这取决于它是什么类型的协议。
为有关语言、图书馆和将服务嵌入基础设施的协议创建和更新服务模板。那么开发者就不会从头开始编写新的服务,而是从模板中复制它,并立即收到配置的 Dockerfile、指标发布等。
同样,您可以在一个应用程序中创建类生成器。假设您已经就几个应用层达成一致(控制器 => 表单 => 服务对象)。在这种情况下,您可以制作一个简单的控制台命令,该命令将立即为新功能生成所有图层。
如果您已经同意一些不能以这种方式自动化的原则,您可以组织自动添加到合并请求或跟踪器中的任务的清单;因此,开发人员可以在继续执行任务之前快速浏览它们。
每个公司都有很多流程协议,例如:
描述公司的招聘方式。
发布推出过程的描述。
大型任务的设计审查要求。
每周召开两次团队会议,讨论当前的任务和障碍。
直到最近,我才考虑记录这些协议,尽管它们对公司的成功有重大影响。这些协议的文档不仅具有上述类型的好处,而且还允许您使流程合理化,将它们转移到可见平面并考虑它们的权宜之计。
我从那里得到了这个想法。他提出了一个类似于ADR的工具——Process Decision Record (PDR)。唯一的区别是,它描述的不是架构决策,而是关于流程的决策。此外,他建议在每个 PDR 中设置一个“重新思考日期”——一个你返回文档以查看它是否仍然以最佳方式解决你的问题的日期,在采用n个月后(顺便说一句,同样可以做与美国存托凭证)。
至于自动化,您无能为力。您可以通过在 Jira 中设置工作流、设置会议提醒或创建自动准备本周结果演示的机器人(不过,我是在一家外国公司这样做的)来自动化某些流程。
但通常,您无法真正实现流程自动化,而您的主要目标是让流程更容易遵循而不是不遵循。尽管如此,记录协议仍然会有帮助,即使您的流程已经很容易遵循 - 正规化和合理化将使您能够改进它们。
文档化和随后的自动化是有益的:花在开发上的时间减少了,应用程序变得更易于支持,流程变得更智能。
人们可能会认为所有这些都是不必要的官僚作风,因为“我们是好人——我们可以在没有它的情况下开发代码。”但事实上,协议将为您节省大量时间和金钱,并保护员工的神经细胞。当然,你不需要绝对地处理并拒绝任何违反协议的事情——这可能表明协议需要更新,或者你最初没有考虑它的某些方面。
如果您还没有开始在您的团队中记录协议,请从较低的抽象级别转移到较高的抽象级别:从代码级别协议开始,然后是架构级别,然后才处理流程级别。协议文档是团队养成的习惯,从不太抽象的概念开始会容易得多。
此外,本文并未描述所有类型。例如,您可以将设计协议记录为库组件。
每种新型协议都经历相同的三个阶段:
弄清楚如何记录它。
弄清楚如何使其自动化。
随着时间的推移,确保它节省的资源多于保留它所需的资源。
最后一个。在记录过程中,可能会发现一些现有协议显然没有任何理由,浪费您团队的时间,而且通常是有害的,但您已经习惯了。在这种情况下,你必须克服团队头脑中的习惯障碍,让你的团队相信拒绝协议有时比接受协议更重要。但那是一个完全不同的故事。
也发布在这里。