面试时经常问的一个问题是,你最近或者做过的项目中挑战最大的内容,然后顺着其中的技术点挖一些更深入的内容,看看候选人了解多少,理解程度。
然后突然想了想我做的有什么难度比较大的项目,可以给大家分享下。
今天介绍下我一年前完成的一个两个独立系统的模块打通过程,换句话说就是A系统可以直接使用B系统的业务模块。
背景介绍
A系统是一个古老的系统,B系统是一个新做的系统,(原本是希望A系统的功能全部迁移到B系统上的,但是由于各种原因搁置了)当时结果导致两个系统在同时使用和升级。
随着业务的开发,很多需求在A和B系统之间产生了关联性,例如B系统上线了一个新产品,然后为了增加入口和使用量,需要在A系统上可以直接调用新产品的某个功能。
直观的解决方案是A系统上面复制粘贴一份B系统上面这个产品的功能,但是问题就来了,未来维护起来怎么办,同时维护两份代码?以后这样的需求多了怎么办,重复代码越来越多?
另外一个解决办法就是A,B两个系统间的融合。当然这样评估的一个前提是A和B虽然是两个系统,但是大家开发模式,底层依赖还是相似的。
需求分析
上面是这两个系统的基本架构,拆分成线上线下两个部分。
A
网站有两个业务模块A1
和A2
。
B
网站有三个业务模块,B1
,B2
,B3
。
现在的需求是B1这个模块不仅能在B系统中运行,而且可以共享到A系统中。
目标如下图:
那么问题来了:
问题一
支持业务代码的底层dep和common不一样。
随着时间的推移,dep依赖第一个是引入的库有些差别,第二个更加严重是是大部分库的版本已经不一样了。
业务模块的底层就像是生态环境,如果生态环境差别越大,那么这两个生态融合在一起的困难也就越大。
问题二
B1这个模块在A系统中调用时,如何找对路径。
举个例子:
B系统中有一个 module/b/c/d.js
;
B1中require了一个 module/b/c/d
,在B系统中是可以正确访问到的。
但是如果在A系统中调用到B1的require的module/b/c/d
。它是会找到A系统中的module/b/c/d.js
;
这只是其中的一个例子,由于系统中的AMD模式,路径的寻找也是一个坑点。
当然对于上面的问题可以通过map
方式(esl.js中有个map,require.js应该也有对应的)。当时是用过另外一种方式解决的。
问题三
编译两个问题,
一是路径问题,当时坑我最深的。
二是业务模块独立打包,A系统中应该是仅仅需要B1这个业务,而不是所有B系统中的代码。
问题四
如何对开发人员透明,这个很关键。如果系统融合了,一线的开发人员需要为此做很多事情,就比较失败了。
所以整个调用过程如何让开发无感知,B系统中正常开发一个模块,A系统通过一个api就能直接使用了,也不需要区分线上线下。
具体步骤
主要问题抛出了,后面就是看如何一一对应的解决问题了。
当然了上面介绍的以外,还有很多细节问题,例如融合后样式冲突这种很多细节上面的坑。只是这些没有上面四个问题那么严重。
第一步,底层打平
dep打平(1)A系统中补充B系统中新增的库,相对简单
dep打平(2)A和B系统中有差异的库,都升级到同样版本,这个非常坑,由于很多使用的是公司或者部门内部的库,升级不想外部jquery一样对开发透明,他们的升级绝对不是透明的,哪怕是百度最火的echart。所以解决升级库的兼容问题是一个工作量很大的活。
common基础依赖合并。找出不同内容互补,然后相同又冲突的内容,修改打补丁方式,虽然有坑,但是经理了dep的升级,觉得还ok。
完成上面三步后的一个期望的成果是,B1模块以及依赖的内容可以直接复制到A系统中,在A里面可以直接调用打开。
注意一些细节就是初始化是否相同,A和B如果初始化不一样,可能在A系统调用B1时,B1有些内容缺少初始化过程。(这种就是属于细节上的坑了)
第二部,处理path路径
当时处理思路比较简单,B1模块前面统一加上B1这个前缀,这样就能够在require时找到指定的路径了。
这个地方的难点在于打包编译,因为破坏了默认的打包规则,而且根据一些打包的扩展配置也无法达到期望。
当时解决的方式是仔细的研究了打包编译流程,很大程度上面重写了或者说hack了默认的打包规则。
其实打包编译都研究到这里了,也就顺便把问题三解决了。当时的对于打包的研究已经可以安装需要随意打包了。
这里的预期效果就是B1模块在B自己的系统中,A中可以调用打开了
第三部,对开发人员透明
完成上面步骤后,有一个遗留问题是,线上打开的方式和线下打开的方式不一样,对于开发人员非常不友好。
所以这一步应该是优化过程,让这个功能更加完善,所以写了一个简单的api,开发人员只需要调用api即可,不需要考虑线上和线下逻辑。这个复杂的逻辑包含到了api中处理。
项目难点
我个人认为这个项目的难点:
对于两个系统的架构要非常熟悉
对于打包编译需要非常熟悉,因为一旦涉及到线上和线下,编译就是必须要了解的内容
对于系统底层代码要熟悉,因为在升级dep过程中,很多版本兼容bug必须要定位到底层代码中
对于AMD需要熟悉,当时定位甚至发现了esl.js和require.js在某种场景的细微区别
目前状态
在最近一年中,A和B两个系统以及融合在一起了。
个人博客
http://tangguangyao.github.io/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。