随着单页应用和移动互联网的兴起,软件工程师也很自然地被分成了多个工种,常见的有 Web 前端工程师、iOS 工程师、Android 工程师、后端工程师等,前三者也可以统称为客户端工程师。
既然研发的角色都已经做了区分,那对代码的物理分隔需求也是合理而且是必要的。因为谁也无法接受这样的情景:前端工程师提交了修改某个按钮的 CSS 代码却触发了整个工程的 CI 动作。
iOS 和 Android 的代码,从一开始就是和后端代码分开的。Web 端代码的分离,出现的要稍微晚一些,最近几年才开始流行起来,目前在一些分工较细的大团队,基本已经得到大家的共识。
我们假设有这么十个人,任何技术对他们来说都不是问题。让他们去开发某个项目,每个人单独负责项目的某个功能模块,他们需要一个月的时间。如果引入前后端分离的技术架构,让其中三个人负责前端部分,另外七个人负责后端部分,除非他们能并行开发,不然研发效率是不如分离前的。
上面只是很简单地算了一笔帐,为了说明前后端分离之后并行开发的重要性。还有一点没有提到,就是前后端分离架构模式下的协作成本,就算能够并行开发,很可能还会多出一个人月的成本。
本文并不讨论前后端为什么要分离。不过有一点我想说的是,前后端分离方案并不一定适合所有团队,这一点是毋庸置疑的。
本文想要探讨的是前后端分离之后,我们如何才能做到并行开发和降低协作成本,希望可以给打算尝试前后端分离的技术团队带来一点点启发。
尝试前后端分离的技术团队,相信都有正儿八经的前端工程师和后端工程师,让专业的人能够做更专业的事情。
前后端被分离之后,项目中的接口数量就会显著增加。之前直接在页面模板中输出的数据,绝大多数都需要改为通过异步接口的形式来获取,所以接口约定增加了前后端工程师的沟通成本。
前后端被分离之后,页面模板归属给前端工程师。页面模板由 HTML 标签和模型数据两部分组成,前端工程师只要学习一下模板引擎的知识就能胜任。模板引擎的语法相对来说都比较简单,前端工程师都有 JavaScript 的程序语言基础,学习起来相对是比较轻松的。如果模型数据不想通过异步接口获取,仍旧是想在服务端输出页面内容,这也难不到前端工程师,因为他们可以选用 Node.js。所以页面模板划分给前端工程师降低了前后端工程师的沟通成本。
模板的开发工作量本身就不多,前端仍旧需要专注在 UI 展示和用户交互体验的实现上面,后端没有模板这个烫手山芋后可以更加专注在数据服务上面,而且所有客户端可以共享使用所有的数据服务。当然还有很多其他工作,这些工作不管前后端有没有分离都是需要做的,比如页面性能优化、服务器的稳定性、数据的一致性等等。
所以,我们重点要关注的是接口约定。
目前较为流行的接口数据格式是 JSON,还有像 RESTful 这样的接口规范。不管 REStful 规范本身是否最为合理,但它至少是一种规范,有了规范我们就可以研发自动化工具,这就是规范的魅力所在。
不管采取什么格式的接口,都需要得到前后端工程师的确认,并且一定有一份记录文档。
接口文档,传统的形式有 Word、Excel 这样的文件,也有些团队会使用 Wiki、Confluence 这样的平台,这些都是比较规范的做法,很多小团队都是通过邮件或者聊天软件沟通,甚至只是口头沟通的情况也不在少数。
有些技术团队早就意识到接口文档的重要性,他们会使用 Swagger 这样的工具,它可以通过代码注释,自动生成接口文档。当然也可以反过来,可以根据 Swagger 规范生成代码,这也再次说明了规范可以解放一部分生产力。
以上所有接口文档的形式,或多或少都有些许不便之处,理想中的接口文档应该具备以下功能:
那有没有这样的平台呢?答案是肯定的。这里也推荐一下我这几年一直在开发和维护的 NEI 接口管理平台。有兴趣的朋友可以先看一下官网上的视频教程,看完后对 NEI 提供的功能会有一个大致的了解。
前面已经介绍过,前后端分离后,模板归属给前端工程师。所以前端工程师需要能解析模板的工具。模板本身的开发和维护对前端工程师并没有多少挑战,这一点技术经理们完全可以信任前端工程师。
模板中的内容可以根据项目而定:
比如受登录保护的系统,模板可以是一张很简单的骨架页面,所有的内容都是通过 JavaScript 动态生成。此时的模板相当于一张很简单的 HTML 页面,所以可以直接由 Nginx 这样的工具提供服务即可。
如果是内容型的页面,而且不受登录保护,意味着要考虑 SEO 等问题,此时就需要能解析模板的模板引擎。前端工程师一般都会考虑 Node.js,因为有天然的语言优势。当然也可以选择其他的服务端语言,比如后端工程师常用的 Java,只是很少见罢了。当然了,SEO 的问题不一定非得这么处理,比如可以给爬虫生成专门的页面。
前后端能“并行开发”,基于这么一个前提:
前端工程师严格使用接口定义,后端工程师严格实现接口定义,这样后期双方联调时理论上是零成本。
这是一种非常理想的完美场景,在实际工作中很难做到,但值得我们竭尽所能地追求。
在定义完接口后,可以自动生成 Mock 数据。前端工程师没有什么特殊理由,都会使用这份 Mock 数据。所以,“严格使用接口定义”,这一点对前端工程师来说,也没什么挑战,流程上没什么会导致前端工程师放弃使用这份 Mock 数据的重大缺陷。
Mock 数据毕竟只是 Mock 数据,它们本身是随机生成出来的,是没有意义的。有些朋友可能不理解为什么要使用有意义的 Mock 数据,我举个例子,比如时间这个字段,要根据场景,它可能需要是比今天早、比今天晚或者是某个区段的时间等等,如果只是简单的随机生成,会影响页面本身的业务或者交互逻辑。
虽然我们可以增加一些功能来生成更有意义的 Mock 数据,比如:
上述功能可以在一定程度上缓解问题,但还是无法彻底解决“有意义”这个问题。如果只是想让接口管理平台来生成有意义的 Mock,这是不可能的任务。还有朋友建议使用大数据分析技术,这也是不可能解决问题的。大数据分析再怎么智能,生成的所有 Mock 数据不可能对用户都有意义。
既然“接口平台 -> 用户”这条路走不通,我们可以反过来走“用户 -> 接口平台”这条路,也就是让用户主动将测试数据保存到接口平台上面来,因为数据本身就是用户填写的,所以必然是有意义的。这就是下文将要介绍的 MockStore 功能。
MockStore,顾名思义,是指保存 Mock 数据的能力,它可以将用户的测试数据持久化到接口平台上。它要具备以下功能:
offset
、limit
等查询参数返回相应页码的数据。因为需要运行用户编写的脚本代码,所有需要考虑语法报错、运行耗时过长、死循环、恶意脚本等问题,这是另外一个话题,在此就不展开讨论了。
前面我们一直没有讨论接口应该由谁来定义比较合适。这个问题很多人都会问。我以前的回答是“前端架构师”,因为他对接口的使用方和实现方都有所涉及,是衔接双方的合适人选。今天我想换个答案,也就是选择团队中最适合的人来定义接口,他可以是技术经理、前端架构师、后端架构师等任意人,只要他对接口的使用方、实现方以及系统业务都很理解即可。
注意,我并没有说所有的接口全部由某个人来定义,在实际工作中,这不具备可操作性。他可能很忙,可能请假了,而且现代的互联网产品都相当复杂,模块多则上百个,这已经不是一个人能掌控的。前面我们已经说过,所有人都应该参与到接口文档的建设中来,具体到特定的模块,推选对模块业务最了解的、同时既懂前端又懂后端的人来定义接口始终是一个不错的选择。
也就是从什么时候就可以开始定义接口?一般来说,有了交互稿后,接口就能马上被定义出来,此时前端和后端工程师都还没开始开发功能,所以时间上没有什么问题,不会耽误双方的工作。
但有些接口在有交互稿之前就可以定义出来,比如用户的注册和登录接口,几乎所有系统都有这样的接口,还有特定领域模型,产品交互再怎么变化也离不开领域模型,比如通用商品模型,它的字段基本上是可以固定的,它也肯定有增删查改的接口。当然,有交互稿再去定义接口会容易很多。
人无完人,技术再全面的人也可能定义出中看不中用的接口来。所以,接口定义完后,可以进行一次小型的接口评审会议,把相关人员都召集到一起,及时发现问题,规避风险。
同一件事情,让不同的人去做,最终的结果肯定是不同的。同理,同一个接口,让不同的人去定义,最终的结果肯定也不一样。所以,我们要定义一些规范,比如接口的地址全部使用小写,参数使用驼峰等等。
产品会发展,团队会壮大,新人会不断加入团队,他们需要定义新接口,我们对他们新定义的接口要进行审核,看是否符合团队之前制定好的规范。
如果审核这个工作交由人工进行,则必然会增加团队的负担,而且审核者可能对业务已经不太了解了,再让他去审核也不合理。
所以,接口审核,应该工具化自动化,不符合团队规范的接口,在平台上直接限制输入,这样就保证了新创建的接口都是规范的。
有时,需要变更接口,此时接口可能已经发布或者提交测试,所以变更有很大的风险,相信大家都遇到过这样的情况:代码修改上线但没有通知到相关人员导致线上故障。
所以,需要将变更的详细信息及时通知到该接口的所有干系人,并能得到他们的反馈确认。所有人都确认完毕后,才能重新发布上线。实际操作起来会比较麻烦,极有可能还是要靠线下沟通。这个流程还有非常大的优化空间,值得深入挖掘,因为一旦能从流程上解决这种问题,收益是相当大的。
前面我们已经说过,后端工程师要严格实现接口定义,一定要保证接口交付质量,这是最基本的要求。为了保证接口实现的正确性,后端工程师要抛弃使用诸如 POSTMAN 这样的接口测试工具,要使用接口管理平台提供的接口测试工具。
接口平台的接口测试,要具备以下的能力:
此外,后端工程师还要承担维护接口定义的任务。如果每次更新代码,都要手工去接口平台上更新,这已经不是成本的问题了,而是流程上有明显的缺陷,因为这件事情很容易被忘记。
可以开发工具,在每次提交代码时,将最新的接口数据同步到接口平台上面。接口数据可以直接从 Controller 文件中分析提取出来,由于编程语言语法的复杂性,所以应该制定一些规范的写法,方便分析。规范制定后,还要向团队推广并保证所有人都遵循,说起来却简单,执行起来却不容易。
有一些团队可能没有专业的测试工程师,此时,建议后端工程师承担测试的相关工作。
前后端分离后,接口的数量显著增加了,作为测试工程师,需要保证接口的正确性、稳定性、可用性等,需要:
不光是线上的接口要监控,开发阶段的接口也要监控起来,消除“一定要先用接口才能进行测试”带来的滞后性,比如可以培训后端工程师使用测试工具,监控线上环境的接口和监控开发环境的接口,肯定可以使用同一套工具,所以没有开发工具的成本,重要的是要建立起这个意识。
将开发阶段的接口监控起来,意义也是非常大的,等到前后端联调时才发现问题,已经晚了,严重的情况就是导致项目延期,谁都不想看到这样的结果。
我们假设团队的技术架构和方案最终是技术经理拍板的。
技术团队从一种开发方式向另外一种方式转变后,必然会有一段痛苦期,还可能会遭到团队中很多成员的抵抗、挑战或者干脆不执行。此时,技术经理必然是最痛苦的,也会质疑当初的选择是不是太鲁莽了。
从我的经验来看,大概有以下几种情况:
新项目,小团队。没有历史包袱,整个产品一共也没多少接口。引入前后端分离的流程后,反而增加了很多开发之外的工作,而且项目又要赶进度。此时,可以从产品发展的角度和团队成员进行沟通,也就是以后肯定会有越来越多的新人加入团队,到时正确的、完整的、规范的文档对团队都是无价之宝,谁都不想被每个新人重复问相同的问题。
历史项目的重构。已经意识到前后端不分离的问题,所以安排重构。此时需要和团队成员说清楚以前的开发方式到底会有哪些问题。然后可以从项目的重要程度、需求的响应速度等方面和团队成员沟通,要让大家意识到你们不是没事可做才去重构,重构这件事是非常有必要并且对产品发展也是非常重要的。
新技术方案的尝试。项目本身不复杂,可能是团队中的技术骨干想尝试一下新的技术方案。此时是考验他执行力的时候,说服团队其他成员是必需的工作,如果他自己都虎头蛇尾,那就当做是一次教训吧。
总之,要让大家明白前后端分离的意义,鼓励大家去开发自动化工具,同时还要让大家看到产品的希望,谁都不想白忙活。
本文只讨论了前后端分离后,各个角色应该承担什么职责,应该有什么样的工具和平台来支撑分离后的前后端协作方式。相信通过工程师们的不断思考和总结,这样的工具和平台会不断涌现。
网易云大礼包:https://www.163yun.com/gift
本文来自网易实践者社区,经作者包勇明授权发布