文档驱动开发模式在 AIMS 中的应用与实践
摘要:程序员常会说:我最讨厌别人写的代码没有文档,我也最讨厌自己需要写文档。
有一个很老的梗: 我最讨厌别人写的代码没有文档,我也最讨厌自己需要写文档。
有这种想法的程序员应该算是一个老鸟了,对于大多数程序员来说,对于他们来说: 文档是什么。
对于大规模,超大规模的项目,并且历时很长,需要大量人员协同开发的项目,没有文档简直不可想象。但是由于时间紧,任务重,大多数的项目中的开发者都没时间写文档,而且,文档也不计入考核指标,导致开发者也没有动机写文档。这就造成了很多项目都缺少规范化文档,项目的交接和接口的对齐都是靠口口相传,接口定义准确度低,并且项目的整体开发效率低下。
作为一个文档爱好者的笔者来说,平常很重要的一件事儿就是将自己的工作归纳总结并整理成文档。即便如此,笔者也面临着很多问题:
· 需求很快就变了,光是改代码就已经耗尽了我的精力了,哪有时间同步文档。
· 要么先改代码,要么先改文档,总之文档和代码之间存在一个不一致错位期。
除此之外,由于我们主要从事 AI 相关能力的研发,所以在开发过程中还存在以下特殊的问题:
· 开发者不得不写大量重复的网络编程相关的业务代码,这些代码的质量通常不高,并且在后期的反复修改中变得越来越臃肿,从而难以维护。
· 因为重复的业务代码开发工作占比过大,严重压缩智能化研发人员在 AI 方面的精力投入,这就导致了企业投入大量人力却无法得到好的效果。
经过不断的摸索和实践,AIMS 项目组采取了一套文档驱动的开发模式,可以有效地解决上述在项目中广泛存在的问题。
1. AI 接口开发的特点
不同于传统 API 的 CRUD 接口的开发,AI 的开发模式通常包含了以下步骤:
数据清洗;
模型训练;
参数调优;
API 上线。
前三项都是我们组的强项,也是我们的工作重点。但是在实际工作中,却是 API 上线消耗了我们的大部分精力。AIMS 项目组大都从事的是 AI 方向相关的工作,对于 API 的相关库 flask、tornado 也不是很熟悉,这就导致开发人员需要花大量时间去了解网络编程相关内容,开发出来的程序质量可能也不是很高。而且,在接口开发后,还需要准备一份 Swagger UI 给前端的开发人员,这又是一项繁重的工作。为了解决如上所述的痛点问题,AI 接口开发就需要满足以下两个特点和需求:
API 的核心函数是现成的;
需要将 API 开发工作量降到最低。
2. 文档驱动的开发模式
我们发现 API 的接口文档中已经包含了实现 API 接口的所有信息。也就是说,API 接口文档的信息熵和 API 接口代码的信息熵是一样的。因此,我们只需要完成代码或者文档中的一项即可,另外一项可以交给框架自动生成,这就避免了把同样一件事情重复做两遍的问题。考虑到文档不论从可读性、易写性还是可维护性都胜过代码,我们决定写文档,然后根据文档生成对应的代码。
我们参考了 OpenAPI Specification3.0.1 标准,以及 JSON Schema 定义了一套 API 描述语言,开发者基于这个 API 描述语言撰写 API 文档。当完成文档时,API 的开发工作也随之完成,大大节省了 API 接口的开发工作量。经过初步估计,使用文档驱动模式开发一个 API 接口,通常可以减少 40%–70%的工作量。
3. AIMS 框架介绍
为了实现文档驱动的开发模式,AIMS 基于 tornado 实现了一套 Web 后端框架,如下图所示。
1.1. Application Router 组件
每一个 API 都会有一个路径,即一个正则表达式[1]。一个微服务中的多个 API 的所有路径会组成一个 API 路径列表。
当 Application Router 接收到请求时,会根据请求中的 URI 在路由表中查找。如果匹配到某一个 Request Handler,路由模块会将请求转发给响应的 Request Handler。如果所有的路径都不匹配,则返回 404 结果[2]。
1.2. Request Handler 组件
Request Handler 处理来自 Application Router 的响应,是 AIMS 架构的核心,而 Document 则是 Request Handler 的核心。在 AIMS 架构中,Document 是指函数的文档,即__doc__。Request Handler 是在服务的启动阶段动态生成的。
事实上,在 AIMS 架构图中,只有 Document 是开发者必须写的[3]。其它的组件都是由 AIMS 提供的,或者是由 Document 自动生成的,所以 AIMS 开发模式也被称为文档驱动型开发模式。开发者只需要维护 Document 即可,从而实现减少开发者工作量的目的。
1.1. Watchman 组件
Watchman 组件可以通过设置来订阅某些接口的异常,当被订阅接口出现任何异常时,Exception Handler 便会触发 Watchman 组件。
因为 Recorder 组件记录了 Arguments,Watchman 甚至可以自动产生一个可以复现该问题的测试用例,方便开发人员定位问题。
1.2. Recorder 组件
Recorder 是一个采集器,可以采集每一次请求的所有细节信息,包括请求 ID、请求参数、远程 IP、被调用的接口、响应时间、工作目录和进程号等各种信息。这些数据具有以下两个作用:
系统的维护者可以利用 Recorder 中的数据快速定位,复现现网问题,可以看做是一个更强大的日志系统。
通过请求 ID,训练数据收集系统可以将请求参数、响应数据与用户反馈数据关联起来,· 这就相当于是一条有标记的数据。
1.3. Logger 组件
Logger 是 AIMS 封装的日志模块,用法和 python 自带的 logging.Logger 使用方式一致,最大限度地降低开发者的学习成本。
1.4. 补充说明
我们注意到,在 AIMS 架构图中,Argument Parser、Schema Checker、Swagger UI 和 OpenAPI Specification 是同源的,即都是来自 Document。这就不会出现文档(Swagger UI、OpenAPI Specification)与函数实现(Argument Parser、Schema Checker)不一致的情况。开发者也不需要同时维护 Argument Parser、Schema Checker、Swagger UI 和 OpenAPI Specification 相关代码。
以上就是文档驱动开发在 AIMS 框架中的优势,既降低了开发者的工作量,又解决了一致性的问题。事实证明,自动产生的组件质量也是优于开发者自行开发的代码,并且不易出错,从而提升整体服务的质量以及稳定性。
[1] 在 AIMS 开发中,这个字段是写在__doc__中的 api_path 字段中。
[2] 事实上,路由模块会将请求转发给 NotFoundRequestHandler,然后由 NotFoundRequestHandler 进行响应。
[3] 在 AI 相关微服务开发过程中,Function,也就是核心功能函数,是已经准备好的。
本文分享自华为云社区《文档驱动开发模式在 AIMS 中的应用与实践》,原文作者:zqmillet 。
版权声明: 本文为 InfoQ 作者【华为云开发者社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/a9638e8a23cc7359696d1062b】。文章转载请联系作者。
评论