随着业务渠道及产品的增长,你的代码是否开始陷入IF-ELSE组成的泥潭,难以脱身?git
小码同窗一来到新公司,就负责起了一个新开始,但具备无限想象空间的后台开发项目。就像全部的互联网项目同样,业务变化极其迅速,为了减小初期试错成本,小码同窗选用了流行、便捷的贫血模型,也就是Service+DAO/RPC结构,作了简单的关注点分离——业务以及基础设施(存储/远程服务)的分离。github
业务很给力,主要流程模式已逐渐成型,同时也增长了不少的营销渠道,有公司内部的 App、有公众号、小程序、H5,也有各种外部的合做伙伴的渠道,小码同窗一直都在高负荷地工做着,彻底来不及思考要怎么优雅地解决这些渠道增长带来的问题。然而,每一个渠道会有一个渠道相关的小特性,这意味着在 登陆、注册、作业务等等各个Service里,每增长一个渠道时,都要增长一段关于渠道判断的IF-ELSE判断语句。量变引发质变,当渠道加到近十个时,小码懵逼了,理清代码逻辑脉络变得极为困难,由于看一遍代码,须要将要受到近十个不一样渠道分支代码的干扰。同时代码也变得难以并行开发,多个渠道的拓展会由于同一个Service的修改而更容易发生冲突。
小程序
其实这里小码可能会采起另一种作法,陷入另一种困境,小码同窗每增长一个渠道就将原来的代码复制一份,而后针对渠道进行简单的修改,而后就能够安全高效地完成业务需求了。然而复制代码一时爽,一直复制一直爽,当咱们须要修改一些渠道公共实现,理清不一样渠道实现的区别并修改时,近十个渠道就会让咱们就变得痛不欲生了。
segmentfault
小码同窗想了下,不管多忙都要从这个困境中破局,因而他想出了如下方案:
安全
将公共的逻辑下沉,将各个渠道特有的判断及逻辑都上提。如此一来咱们能够从代码中分离渠道和公用业务逻辑——要理解渠道特性,咱们能够从渠道所在模块(微服务/package/service)的代码得知,若是要理解通用的信息,则到公共
业务逻辑层查看对应的实现。架构
但若要使用本解决方案解决目前系统的问题,则须要引入大量的重构,由于该实现须要将大量已有存在的渠道逻辑变动其发生的逻辑时间点,这须要大量的开发及测试人力支持。框架
因而小码同窗开始在网上搜索相关的解决方案,了解到阿里有个能够解决相似问题的框架实现COLA,并以此为参考开展了本身的扩展点设计微服务
https://github.com/alibaba/COLA
其引入了一种名为 扩展点/插件 的机制(扩展点是一个Interface,扩展点实现为interface的一个特定实现),让咱们能够达到如下效果:测试
要实现这个效果,强制咱们把相关业务语义显式化,例如 通用业务逻辑Service在没有引入扩展点前,写的校验身份的代码为编码
if(is渠道B) { 渠道B的一大堆代码进行身份校验 } else { 默认实现的一大堆代码进行身份校验 }
而引入扩展点后,在通用业务逻辑Service写的则是
校验身份扩展点.执行校验();
其显式化了业务语义,并像 公用逻辑下沉 的解决方案同样 分离了主干的代码逻辑和特定实现的代码逻辑,还能保证原有特定渠道逻辑执行的相对位置不变。
在扩展点机制的支持下咱们只须要定下规范——在通用业务逻辑层不能出现任何关于Channel渠道的IF-ELSE判断,这样就可收获大量有基础抽象的通用业务逻辑代码,提升识别基础抽象的能力。
扩展点本质上就是个带有自动路由功能的策略模式,其根据业务上下文信息,自动推断出应该选用哪一个具体的扩展点实现。
扩展点的机制和原理简单,使用也很简单,但其给业务系统代码带来倒是变革性的。
小码同窗利用扩展点已经阻止了渠道增长带来的代码腐化加重问题,小码以保守起见:
但新的问题出现了,项目中也有一个与渠道相似的,会不断扩展实现的概念——产品。
在小码的系统中,每增长一个产品也是按照相似先前增长渠道的形式,以IF-ELSE完成扩展。因而,小码但愿直接套用以前的扩展点机制,然而事情并无这么顺利。
在上一幅图中,contextCode为
companyY.channelB
其表征的是渠道维度的身份信息,咱们以该信息为依据,来匹配最适合的渠道相关的实现。与此相似,咱们须要引入产品维度的身份信息,同时也要将不一样维度的contextCode加以区分,然而COLA的实现中并不支持此类多维扩展实现,因而小码开始设计了本身的ConextCode及ImplementCode规范,增长了维度标识符:
channel:companyY.channelB product:companyY.ProductO.subProductE
经过维度标志,小码分开了不一样维度的扩展点以及其对应的实现,解决了大部分的问题。
引入多维扩展点后,大多数扩展实现都在各自的维度良好运行,井水不犯河水。然而,有少数扩展点却出现了须要多维同时决定实现的场景,如:
当前如果渠道A且是产品X的状况下须要使用特定的扩展实现。
目前基于维度隔离的扩展点感受没法支持此类需求,因而,小码继续查找相关资料,了解到了阿里TMF2.0框架的实现:
https://segmentfault.com/a/1190000012541958
TMF2.0按文中介绍,其为一个二维的扩展点实现,这两维分别是:
与小码以前设计的维度隔离扩展点不一样,TMF2.0中行业维度与产品维度会共享扩展点,然而当出现扩展点冲突时,TMF2.0会以业务身份为线索,经过可视化界面配置特定业务身份在遇到扩展实现冲突时应该选择哪个扩展实现,并将其固化成配置,运行时依据配置选择最终扩展实现。
然而该设定并不符合项目的现状,相关UI的开发设计也是一个巨大的工程,所以小码设计了另一种折中的设定:
以下图所示
这个设定的实现虽然繁琐,可是实际状况下,出现多维共同干预扩展实现选择的状况应该相对少,相对于扩展点维度隔离获得的好处,其应该能够接受。
扩展点的理论简单易用,其使得
今后小码和他的小伙伴们今后摆脱了996,与基友们过上了幸福快乐的生活。
多年金融行业经验,现为某Top2互联网银行高级搬砖工,曾在两家TOP3股份制商业银行及一家互金创业公司工做(架构、核心业务主程),EasyTransaction做者,欢迎关注我的公众号,在这里我会分享平常工做、生活中对于架构、编码和业务的思考