谈谈前后端分离之后

未来已来2018-09-06 10:53

作者:包勇明


引言

随着单页应用和移动互联网的兴起,软件工程师也很自然地被分成了多个工种,常见的有 Web 前端工程师、iOS 工程师、Android 工程师、后端工程师等,前三者也可以统称为客户端工程师。

既然研发的角色都已经做了区分,那对代码的物理分隔需求也是合理而且是必要的。因为谁也无法接受这样的情景:前端工程师提交了修改某个按钮的 CSS 代码却触发了整个工程的 CI 动作。

iOS 和 Android 的代码,从一开始就是和后端代码分开的。Web 端代码的分离,出现的要稍微晚一些,最近几年才开始流行起来,目前在一些分工较细的大团队,基本已经得到大家的共识。

我们假设有这么十个人,任何技术对他们来说都不是问题。让他们去开发某个项目,每个人单独负责项目的某个功能模块,他们需要一个月的时间。如果引入前后端分离的技术架构,让其中三个人负责前端部分,另外七个人负责后端部分,除非他们能并行开发,不然研发效率是不如分离前的。

上面只是很简单地算了一笔帐,为了说明前后端分离之后并行开发的重要性。还有一点没有提到,就是前后端分离架构模式下的协作成本,就算能够并行开发,很可能还会多出一个人月的成本。

本文并不讨论前后端为什么要分离。不过有一点我想说的是,前后端分离方案并不一定适合所有团队,这一点是毋庸置疑的。

本文想要探讨的是前后端分离之后,我们如何才能做到并行开发和降低协作成本,希望可以给打算尝试前后端分离的技术团队带来一点点启发。


前后端分离之后的前后端协作模式

尝试前后端分离的技术团队,相信都有正儿八经的前端工程师和后端工程师,让专业的人能够做更专业的事情。

前后端被分离之后,项目中的接口数量就会显著增加。之前直接在页面模板中输出的数据,绝大多数都需要改为通过异步接口的形式来获取,所以接口约定增加了前后端工程师的沟通成本。

前后端被分离之后,页面模板归属给前端工程师。页面模板由 HTML 标签和模型数据两部分组成,前端工程师只要学习一下模板引擎的知识就能胜任。模板引擎的语法相对来说都比较简单,前端工程师都有 JavaScript 的程序语言基础,学习起来相对是比较轻松的。如果模型数据不想通过异步接口获取,仍旧是想在服务端输出页面内容,这也难不到前端工程师,因为他们可以选用 Node.js。所以页面模板划分给前端工程师降低了前后端工程师的沟通成本。

模板的开发工作量本身就不多,前端仍旧需要专注在 UI 展示和用户交互体验的实现上面,后端没有模板这个烫手山芋后可以更加专注在数据服务上面,而且所有客户端可以共享使用所有的数据服务。当然还有很多其他工作,这些工作不管前后端有没有分离都是需要做的,比如页面性能优化、服务器的稳定性、数据的一致性等等。

所以,我们重点要关注的是接口约定。


前后端分离之后的接口约定形式

目前较为流行的接口数据格式是 JSON,还有像 RESTful 这样的接口规范。不管 REStful 规范本身是否最为合理,但它至少是一种规范,有了规范我们就可以研发自动化工具,这就是规范的魅力所在。

不管采取什么格式的接口,都需要得到前后端工程师的确认,并且一定有一份记录文档。

接口文档,传统的形式有 Word、Excel 这样的文件,也有些团队会使用 Wiki、Confluence 这样的平台,这些都是比较规范的做法,很多小团队都是通过邮件或者聊天软件沟通,甚至只是口头沟通的情况也不在少数。

有些技术团队早就意识到接口文档的重要性,他们会使用 Swagger 这样的工具,它可以通过代码注释,自动生成接口文档。当然也可以反过来,可以根据 Swagger 规范生成代码,这也再次说明了规范可以解放一部分生产力。

以上所有接口文档的形式,或多或少都有些许不便之处,理想中的接口文档应该具备以下功能:

  • 保存在云端。这意味着它是一个 Web 在线平台,可以在多种设备上查看,方便开发人员随时都可以拿出来讨论。
  • 所有人可以编辑,还要有权限控制。如果一个项目中的接口让一个人来定义和维护,这是不现实的。所有人都应该参与到接口文档的建设中来。
  • 定义接口要方便。操作一定要方便,不然很多团队没有精力会来维护接口文档,最后形同虚设。比如:
    • 可以提供数据模型的概念,根据数据模型可以自动生成相应的 CRUD 接口,稍微思考后我们不难发现,基本上所有的接口都是在操作某个数据模型。
    • 可以导入 JavaBean 文件来生成数据模型,并支持批量导入。也可以反过来,根据数据模型生成 JavaBean 文件。
    • 可以导入 Controller 文件来生成接口定义,并支持批量导入。也可以反过来,根据接口定义生成 Controller 文件。
  • 维护接口要方便。比如接口变更后,后端修改了代码,此时要在接口文档平台上面更新。如果每次都要手动更新,最终的文档必然也是形同虚设和实际不符,没人会再来维护。所以接口平台需要提供开放接口来同步接口文档,后端修改代码后,可以通过工具和流程规范限制,自动同步到平台上。
  • 在线 Mock 服务,可跨域调用。这是做到并行开发的关键所在,在后端没有提供真实可用的接口之前,前端工程师可以使用 Mock 服务进行页面开发。
  • 接口测试。平台要提供接口测试功能,可以验证后端开发的接口是否和平台上定义的一致。
  • 在线文档并能导出。有一个统一的查看入口,可以查看项目的所有接口定义,并能导致各种格式的文件。

那有没有这样的平台呢?答案是肯定的。这里也推荐一下我这几年一直在开发和维护的 NEI 接口管理平台。有兴趣的朋友可以先看一下官网上的视频教程,看完后对 NEI 提供的功能会有一个大致的了解。


前后端分离之后的前端工程师

模板

前面已经介绍过,前后端分离后,模板归属给前端工程师。所以前端工程师需要能解析模板的工具。模板本身的开发和维护对前端工程师并没有多少挑战,这一点技术经理们完全可以信任前端工程师。

模板中的内容可以根据项目而定:

  • 比如受登录保护的系统,模板可以是一张很简单的骨架页面,所有的内容都是通过 JavaScript 动态生成。此时的模板相当于一张很简单的 HTML 页面,所以可以直接由 Nginx 这样的工具提供服务即可。

  • 如果是内容型的页面,而且不受登录保护,意味着要考虑 SEO 等问题,此时就需要能解析模板的模板引擎。前端工程师一般都会考虑 Node.js,因为有天然的语言优势。当然也可以选择其他的服务端语言,比如后端工程师常用的 Java,只是很少见罢了。当然了,SEO 的问题不一定非得这么处理,比如可以给爬虫生成专门的页面。


严格使用根据接口定义生成的 Mock 数据

前后端能“并行开发”,基于这么一个前提:

前端工程师严格使用接口定义,后端工程师严格实现接口定义,这样后期双方联调时理论上是零成本。

这是一种非常理想的完美场景,在实际工作中很难做到,但值得我们竭尽所能地追求。

在定义完接口后,可以自动生成 Mock 数据。前端工程师没有什么特殊理由,都会使用这份 Mock 数据。所以,“严格使用接口定义”,这一点对前端工程师来说,也没什么挑战,流程上没什么会导致前端工程师放弃使用这份 Mock 数据的重大缺陷。


Mock 服务增强

Mock 数据毕竟只是 Mock 数据,它们本身是随机生成出来的,是没有意义的。有些朋友可能不理解为什么要使用有意义的 Mock 数据,我举个例子,比如时间这个字段,要根据场景,它可能需要是比今天早、比今天晚或者是某个区段的时间等等,如果只是简单的随机生成,会影响页面本身的业务或者交互逻辑。

虽然我们可以增加一些功能来生成更有意义的 Mock 数据,比如:

  • 默认值。
  • 生成规则。用户可以编写函数来生成自己想要的数据。
  • 集成功能较为完善的第三方 Mock 工具,比如 Mockjs等。

上述功能可以在一定程度上缓解问题,但还是无法彻底解决“有意义”这个问题。如果只是想让接口管理平台来生成有意义的 Mock,这是不可能的任务。还有朋友建议使用大数据分析技术,这也是不可能解决问题的。大数据分析再怎么智能,生成的所有 Mock 数据不可能对用户都有意义。

既然“接口平台 -> 用户”这条路走不通,我们可以反过来走“用户 -> 接口平台”这条路,也就是让用户主动将测试数据保存到接口平台上面来,因为数据本身就是用户填写的,所以必然是有意义的。这就是下文将要介绍的 MockStore 功能。


MockStore 服务

MockStore,顾名思义,是指保存 Mock 数据的能力,它可以将用户的测试数据持久化到接口平台上。它要具备以下功能:

  • 在线编辑并保存 Mock 数据。
  • 可以通过调用平台提供的在线接口,增加、修改、查找和删除 Mock 数据,要支持批量操作。
  • 建立接口之间的关联性。比如调用创建商品的接口后,再调用获取商品列表的接口时,包含了之前创建的商品数据。
  • 前置业务逻辑脚本,在将数据保存到存储中之前进行一些处理,比如校验输入参数是否合法。
  • 后置业务逻辑脚本,在接口返回 Mock 数据之前再进行一些处理,比如分页功能,可以根据 offsetlimit 等查询参数返回相应页码的数据。

因为需要运行用户编写的脚本代码,所有需要考虑语法报错、运行耗时过长、死循环、恶意脚本等问题,这是另外一个话题,在此就不展开讨论了。


前后端分离后的接口定义流程

接口定义者

前面我们一直没有讨论接口应该由谁来定义比较合适。这个问题很多人都会问。我以前的回答是“前端架构师”,因为他对接口的使用方和实现方都有所涉及,是衔接双方的合适人选。今天我想换个答案,也就是选择团队中最适合的人来定义接口,他可以是技术经理、前端架构师、后端架构师等任意人,只要他对接口的使用方、实现方以及系统业务都很理解即可。

注意,我并没有说所有的接口全部由某个人来定义,在实际工作中,这不具备可操作性。他可能很忙,可能请假了,而且现代的互联网产品都相当复杂,模块多则上百个,这已经不是一个人能掌控的。前面我们已经说过,所有人都应该参与到接口文档的建设中来,具体到特定的模块,推选对模块业务最了解的、同时既懂前端又懂后端的人来定义接口始终是一个不错的选择。


接口定义时机

也就是从什么时候就可以开始定义接口?一般来说,有了交互稿后,接口就能马上被定义出来,此时前端和后端工程师都还没开始开发功能,所以时间上没有什么问题,不会耽误双方的工作。

但有些接口在有交互稿之前就可以定义出来,比如用户的注册和登录接口,几乎所有系统都有这样的接口,还有特定领域模型,产品交互再怎么变化也离不开领域模型,比如通用商品模型,它的字段基本上是可以固定的,它也肯定有增删查改的接口。当然,有交互稿再去定义接口会容易很多。


接口评审

人无完人,技术再全面的人也可能定义出中看不中用的接口来。所以,接口定义完后,可以进行一次小型的接口评审会议,把相关人员都召集到一起,及时发现问题,规避风险。


接口定义审核

同一件事情,让不同的人去做,最终的结果肯定是不同的。同理,同一个接口,让不同的人去定义,最终的结果肯定也不一样。所以,我们要定义一些规范,比如接口的地址全部使用小写,参数使用驼峰等等。

产品会发展,团队会壮大,新人会不断加入团队,他们需要定义新接口,我们对他们新定义的接口要进行审核,看是否符合团队之前制定好的规范。

如果审核这个工作交由人工进行,则必然会增加团队的负担,而且审核者可能对业务已经不太了解了,再让他去审核也不合理。

所以,接口审核,应该工具化自动化,不符合团队规范的接口,在平台上直接限制输入,这样就保证了新创建的接口都是规范的。


接口变更确认

有时,需要变更接口,此时接口可能已经发布或者提交测试,所以变更有很大的风险,相信大家都遇到过这样的情况:代码修改上线但没有通知到相关人员导致线上故障。

所以,需要将变更的详细信息及时通知到该接口的所有干系人,并能得到他们的反馈确认。所有人都确认完毕后,才能重新发布上线。实际操作起来会比较麻烦,极有可能还是要靠线下沟通。这个流程还有非常大的优化空间,值得深入挖掘,因为一旦能从流程上解决这种问题,收益是相当大的。


前后端分离后的后端工程师

接口自测

前面我们已经说过,后端工程师要严格实现接口定义,一定要保证接口交付质量,这是最基本的要求。为了保证接口实现的正确性,后端工程师要抛弃使用诸如 POSTMAN 这样的接口测试工具,要使用接口管理平台提供的接口测试工具。

接口平台的接口测试,要具备以下的能力:

  • 支持测试 localhost 接口,可跨域调用,支持发送自定义 Cookie,方便测试受登录保护的接口。
  • 方便填写测试数据,自动填写对实际没有影响的内容,减少手工输入成本。
  • 可以保存接口测试用例,方便后端工程师自测。
  • 导入测试用例数据,可以在线导入,或者通过平台提供的开放接口导入。
  • 详细的测试报告,包括但不限于:
    • 缺失字段检测。
    • 类型匹配检测。
    • 多余字段检测。
  • 测试集,批量测试功能。
  • 前置数据发送脚本,方便对发送前的数据进行特殊处理,比如给密码加密。
  • 后置数据接收脚本,方便对从服务端接收到的数据进行特殊处理,比如将毫秒数值的时间值转换为年月日的格式。
  • 提供测试接口测试集的开放接口,可供第三方平台调用,方便集成到 CI 环境。
  • 接口监控,支持定时运行接口测试集的任务。


接口文档维护

此外,后端工程师还要承担维护接口定义的任务。如果每次更新代码,都要手工去接口平台上更新,这已经不是成本的问题了,而是流程上有明显的缺陷,因为这件事情很容易被忘记。

可以开发工具,在每次提交代码时,将最新的接口数据同步到接口平台上面。接口数据可以直接从 Controller 文件中分析提取出来,由于编程语言语法的复杂性,所以应该制定一些规范的写法,方便分析。规范制定后,还要向团队推广并保证所有人都遵循,说起来却简单,执行起来却不容易。


前后端分离后的测试工程师

有一些团队可能没有专业的测试工程师,此时,建议后端工程师承担测试的相关工作。

接口测试和监控

前后端分离后,接口的数量显著增加了,作为测试工程师,需要保证接口的正确性、稳定性、可用性等,需要:

  • 对接口全方位测试,不同的参数,是否能得到想要的结果。这部分工作量很大,要想办法自动生成测试用例,减少手工录入成本。这是非常有意义的工作,值得所有团队大力投入资源进行研究。
  • 对接口进行压力测试,及时发现问题接口。
  • 全面监控接口,至少要把线上的 P0 级别的接口全部监控起来,有异常时及时发出报警信息给相关人员。

监控范围覆盖开发阶段

不光是线上的接口要监控,开发阶段的接口也要监控起来,消除“一定要先用接口才能进行测试”带来的滞后性,比如可以培训后端工程师使用测试工具,监控线上环境的接口和监控开发环境的接口,肯定可以使用同一套工具,所以没有开发工具的成本,重要的是要建立起这个意识。

将开发阶段的接口监控起来,意义也是非常大的,等到前后端联调时才发现问题,已经晚了,严重的情况就是导致项目延期,谁都不想看到这样的结果。


前后端分离后的技术经理

我们假设团队的技术架构和方案最终是技术经理拍板的。

技术团队从一种开发方式向另外一种方式转变后,必然会有一段痛苦期,还可能会遭到团队中很多成员的抵抗、挑战或者干脆不执行。此时,技术经理必然是最痛苦的,也会质疑当初的选择是不是太鲁莽了。

从我的经验来看,大概有以下几种情况:

  • 新项目,小团队。没有历史包袱,整个产品一共也没多少接口。引入前后端分离的流程后,反而增加了很多开发之外的工作,而且项目又要赶进度。此时,可以从产品发展的角度和团队成员进行沟通,也就是以后肯定会有越来越多的新人加入团队,到时正确的、完整的、规范的文档对团队都是无价之宝,谁都不想被每个新人重复问相同的问题。

  • 历史项目的重构。已经意识到前后端不分离的问题,所以安排重构。此时需要和团队成员说清楚以前的开发方式到底会有哪些问题。然后可以从项目的重要程度、需求的响应速度等方面和团队成员沟通,要让大家意识到你们不是没事可做才去重构,重构这件事是非常有必要并且对产品发展也是非常重要的。

  • 新技术方案的尝试。项目本身不复杂,可能是团队中的技术骨干想尝试一下新的技术方案。此时是考验他执行力的时候,说服团队其他成员是必需的工作,如果他自己都虎头蛇尾,那就当做是一次教训吧。

总之,要让大家明白前后端分离的意义,鼓励大家去开发自动化工具,同时还要让大家看到产品的希望,谁都不想白忙活。


小结

本文只讨论了前后端分离后,各个角色应该承担什么职责,应该有什么样的工具和平台来支撑分离后的前后端协作方式。相信通过工程师们的不断思考和总结,这样的工具和平台会不断涌现。


网易云大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者包勇明授权发布