媒体与新闻

媒体报道与出版物

DevOps之动态表单——优雅地把工作量甩给后端

转载本文需注明出处:微信公众号EAWorld,违者必究。


一个IT公司的日常就是程序员、产品经理、UI等同事们的互相残杀:



有时候程序员内部也会相虐相杀,此话要从前后端分离说起。自从前后端分离的开发模式被广泛应用,不少前端同学就备受煎熬,除了修改需求的魔咒外,还有后端同学的重构和调整接口诅咒,即便需求没改,后端接口或数据结构的调整前端也要巴巴的陪着改,甚至还要为此做大型重构。但是前端重构就真的只是前端重构,和后端一毛钱关系都没有,工作量还是前端的,bug永远是先提给前端,简言之就是,修改需求前端要改,修改接口前端要改,改bug前端要先看(此处省略血泪史一万行)难道我们前端同学就不能反杀一波,摆脱困境了吗?当然可以,答案就是动态表单,自从有了它,我们可甩掉不少工作量(偷笑)。


前端开发最烦人的事之一就是写一堆大同小异的表单,他们使用的控件类型有很强的规律性,同类型控件调用的后端接口类型也非常相似,但是每个表单用到的具体接口、控件种类和控件数量又不尽相同,就算封装控件复用也是杯水车薪,无法提升工作效率。



看过前面卜壮同学的文章的朋友一定知道,前端为了应对后端接口不断调整修改,在框架层上封装了一套接口调用机制,很大程度上降低了后端接口url调整给前端的影响,不论他们怎么改只要接口名称不变,前端统统可以一键搞定,而且还同步建立了数据管理机制,提升前端性能(还没看过的同学传送门在这里)。


这次,面对这些讨厌而又常用的表单,我们前端的态度一样是不能忍的(因为已经被逼疯)。俗话说得好,既然不能躲避,那就想办法解决。因此我们开发了一套动态表单,从表单内容到数据提交统统由后端配置,前端只需要读取解析表单配置渲染相应内容即可,用户完成表单后提交数据发送的请求也是由后端配置,前端做的只是按照要求发送数据即可。这样,前端在表单这一块就再也不用被产品经理和后端同学影响,不论需求怎么改,表单怎么加,都不需要前端在做附加工作了,留下产品经理和后端研发互相伤害,前端同学在一旁观战帮着改改bug就是,这样岂不是美滋滋。



动态表单对很多前端开发人员来说并不陌生,前后端约定好表单配置数据模型,前端只需要实现动态表单解析功能即可。但是一套完整的产品怎么可能只有简简单单的表单配置能,联动表单、表单校验等对前端来说依旧是个比较棘手的问题。今天我们就以DevOps动态表单为例来说说表单联动问题如何解决。


表单联动主要有两种形式,一是表单项的数据联动,再来就是表项显示联动。
我们先来说说表单项数据联动,举个例子:表单中包含代码库和branch/tag/commitId两个输入项,显然后者的显示内容取决于用户选择了哪个代码库,此处就需要前端检测用户对代码库的选择,然后将选定后的数据作为参数向后端发送请求查询branch/tag/commitId项的列表。



这样的功能看着并不复杂,只需要监听代码库的选择实事件然后在事件处理中调用branch/tag/commitId项的查询请求即可。但是,别忘了你现在在写动态表单,一切对你来说都是配置好的模型,不能针对单独的某字段名写if else做特殊处理(否则还叫什么动态表单),代码是固定的,你不能写任何个性化的代码来处理事件,而且这只是一个简简单单的两项联动,真正的项目开发中,多项联动比比皆是。为了解决这一问题,前端在数据模型的设计上做了一定的思考,要求后端在配置动态表单的数据获取url时将需要的参数以冒号加对应表单项的字段名形式配置,示例:api/repo/commit?repoId=:repoId。此后,前端在解析整个表单的时候会给每一个表单项传递完整的表单数据对象,当表单数据中的某项发生改变时,需要向后端发送请求的一些表单项会监听整个表单数据的变化,将与改变的表单项字段名相匹配的url进行重写,替换上对应的值,然后用发生改变的url向后端发送请求获取新的数据。配置示例如下:


[{ attrId: 'repoId', defaultValue: null}, { attrId: 'branchId', defaultValue: null, url: 'api/repo/commit?repoId=:repoId'}]


再来就是动态表单联动显示问题,如下图显示,当用户选择不同的介质策略时,显示的表单项也是不同的:




针对这一功能,我们目前采用的解决方案是,在配置项上加上指定的eventName,当数据项发生改变时,针对不同的数据情况显示或隐藏表单项,代码如下:


artifactStrategyChange: (attrValue) => {
  if (attrValue === 'latest') {
    $this.delete('artifactRepositoryId')
    $this.delete('artifactName')
    $this.delete('aliasName')
    $this.add('artifactVersion')
    $this.add('artifactUrl')
    $this.add('artifactPath')
  }
},


当然,这部分代码还是免不了要在前端实现,但这已经比一个个的写完整的表单工作量少了太多太多。


我们的DevOps产品的CICD部分全部采用动态表单体系实现,在功能扩展上是极为迅速的,只要后端完成开发,基本整个功能扩展就接近了尾声。经过我们的实践,这套表单体系仍然有许多可优化之处,我们也在不断的进行优化和调整,力求将它应用到更多产品中,尽可能的减少开发人员的工作量,提升产品质量,缩短产品交付时间。


动态表单虽好但是也要充分考虑使用场景和开发代价,不要为了过分抽象代码反而本末倒置,过度设计反而提高了研发成本。


END


关于作者夏夏,前端工程师,参与普元DevOps产品开发,以及微服务、容器云等产品开发,负责前端页面设计、架构搭建等工作。善于架构搭建、组件封装及相关算法设计。








关于EAWorld:微服务,DevOps,数据治理,移动架构原创技术分享。长按二维码关注!

咨询