本文为作者在GMTC全球移动技术大会上的演讲整理。演讲PPT见:http://ppt.geekbang.org/slide/show/194本文标题解耦。有很多方法可以谈论脱钩。本文以架构演进为线索,与大家分享移动天猫的解耦之路。我觉得在移动天猫的成长过程中,一些形而上的思考和沉淀对大家是有参考价值的,但是工具和解决方案的参考价值更大。因此,本文将在流程和原因上花费更少的篇幅,而在工具和解决方案上花费更多的篇幅。什么在推动进化?作为一个技术团队,我们升级技术架构的原因是多种多样的,但是哪些因素是最关键的,又可以是什么原因可以进化呢?业务升级最重要的因素一定是业务升级。不产生商业价值的技术不值得关注,更不用说实施了。好的技术总是比业务领先一步,不远不及业务赶超——技术驱动业务。所以,业务的不断升级,需要我们的技术架构跑得更快。Teamsize&cooperationmode另一个推动架构演进的重要因素是团队规模。技术架构最重要的作用之一就是保证生产效率和生产质量。那么人的因素就很关键了。当人多,协作复杂的时候,必须升级技术架构,保证这么多人一起工作,效率高,不出问题。代码规模&工程规模代码规模和工程规模是自然发展的结果。随着业务越来越复杂,团队越来越大,人数越来越多,代码规模和工程规模必然会越来越大。一个几十万DAU的APP和一个千万级DAU的APP,规模上的差距不是必然的,但也是很有可能的。一个人,几十个文件,完成一个功能简单的产品,十几个人,几千个文件,完成一个功能复杂的产品,再进一步到十几个团队,几百个模块,一个平台,一个产品的技术架构一定是千差万别。新技术、新技术是工程师自己的事情。行业中总会有新技术。该技术可能由其他工程师开发,以适应他们的业务发展和架构演进。但技术没有边界。如果新技术很好,能给我们带来价值,提高我们的效率,那我们就用它。比如:Facebook的RN出来了,大家都觉得不错,应该也有很多公司确实大规模使用过。大规模使用RN进行开发,同样需要升级你原有的架构。当然,更重要的是如何平衡快速升级技术架构的好奇心和刚好满足业务和团队的需求。过分追求技术架构创新,过分追求新技术,不仅不能推动业务和团队,反而会造成灾难。所以,作为一个优秀的技术团队,要时刻权衡做还是不做,多做还是少做。架构是如何演变的?架构演进的哪些方面?作为技术团队,我们如何实现架构演进?这个问题因项目、团队和方向而异。本文仅介绍手机天猫发展过程中解耦相关的演进过程。升级开发模式开发模式的概念有点大,本文只讨论与解耦相关的:团队合作方式和工程组织形式。这在下面的单独部分中讨论,所以我不会在这里详细介绍。各个维度的解耦项目大了之后,就需要拆解,不管是组件化还是插件化,或者什么,解耦都是第一步,都是各个维度的解耦。在完善工具集模型的演进和解耦的过程中,会衍生出很多工具。在进化过程中,我们也会思考哪些工作需要工具化,并积极开发工具。一套完整的工具集会大大提高团队的生产力,可以说是最有价值的部分。发展模式升级。天猫团队从三个终端不到十人的小团队发展到近200人的大团队。下面的文章将详细介绍开发模式是如何发生变化的?三年前的一个项目,手机天猫团队刚刚组建,工程师十人左右,正在开发最新版本的天猫App,只有基本功能。整个团队就那么几个人,包括iOS、Android和Server,一个平台也就三四个人;App的功能也很简单,可以完成基本的导购和交易流程。天猫App采用最简单的架构,独立项目,MVC架构。而且我们判断这样的架构在这种情况下是完全足够的,确实是。模块化随着无线业务的发展,移动天猫团队开始爆发式扩张。很快一队变成两队,两队变成四队。随着团队的增多,团队分工,项目越来越大,我们开始发现原来的架构已经不够用了,拆分模块势在必行。现阶段手机天猫的模块拆分也很简单。先把项目按功能横向分层,然后在业务层纵向梳理。简单的将不同的模块代码放在一个文件夹中,项目的组织形式并没有改变。通过这样的拆分,我们实现了代码独立性,跨团队基本不会在同一个模块代码上发生冲突。随着插件的进一步发展,业务越来越复杂,团队工作越来越细分,人数越来越多,代码量越来越大。使用文件夹组织模块的简单方式似乎无能为力。多业务跨团队,不同的开发节奏,复杂的依赖关系导致我们要花费大量的时间来解决无法编译的问题。等待其他模块的集成成为了我们开发效率的瓶颈。如何解决这个问题,我们的解决方案是插件化。那么插件和模块有什么区别呢?我认为两者之间最大的区别是独立性。插件可以独立开发、独立发布、独立运行,而模块则必须依赖于主工程的环境。独立插件可以很好的隔离跨团队之间的依赖关系,相互独立开发,按照自己的节奏发布版本。基于这种思路,我们引入依赖管理设施(iOS引入CocoaPods,Android使用Maven);将之前的模块进一步拆分成独立的项目,分别进行版本管理;每个独立的插件负责发布的版本号,无论其他插件还是主项目都依赖插件发布的稳定版本。然而,但是,外挂这东西并没有我们想象的那么好。代码出来了,但是不能独立编译。依赖管理设施可用,但管理不善。由于我们之前从未梳理过依赖关系,无论是模块还是插件,都只是一种代码管理和发布流程的工作方式,无法解决独立开发和独立运行的问题。在这个阶段,我们选择了忍受这个问题,因为独立开发和独立运营这两个东西对我们来说似乎并没有那么大的价值,而无法实现这两件事并没有成为我们的瓶颈。所以大家还是在同一个项目中,只是把代码提交到不同的仓库,然后通过依赖管理工具和版本号组装到主项目中,最后源码一起跑起来。独立出版而不独立出版会带来哪些问题?很明显,慢!插上一段时间后,我们发现慢的问题严重影响了我们的效率。现阶段我们已经有十多个团队,iOS项目源代码文件超过10000个。由于主工程是通过各个插件的源码组合起来的,所以每次重新索引编译需要半个多小时。要解决这个问题,就需要将插件进行到底,实现插件的独立开发和独立运行的另外两个独立性。今天最重要的工作就是对我们的主题进行解耦,梳理各个插件之间的依赖关系。让每个独立的插件尽可能少的依赖其他插件,在最小范围内正常编译和执行。每次发布不再是一个稳定的版本号,而是一个稳定的二进制包。有了这样的依赖,我们把半个多小时的编译过程拆分成了几十个模块,主工程依赖了几十个二进制包,所以编译速度很快。整个模型升级基本经历了以下几个阶段:代码独立,首先将独立代码工程与形式解耦,打好独立运行的基础并梳理依赖,独立项目可编译并摒弃源码依赖,加速集成一路编译,一步一步,最终实现完全解耦。在这个过程中,我们积累了很多方法论和最佳实践。我觉得有两个工具值得介绍,下面会详细介绍。解耦工欲善其事,必先利其器。每个人都这么说,但不是每个人都能做到。一个拥有工具文化的团队,在质量和效率上都会有很大的优势。对于一个从最初的状态迅速扩张到天猫现在体量的项目,依赖关系之复杂,超乎想象。在这个扩展过程中,我将耦合分为三类:界面耦合,即在用户操作过程中,从首页-到搜索-到详情-再到商店,这些界面跳转是硬编码依赖耦合,顾名思义,两个模块之间存在依赖关系,这就是耦合项目的耦合。每个模块都有自己的生命周期和运行时,每个模块在生产环境需要依赖主项目的运行时Beehive(Beehive是开源的,可以在Github上找到,源码见:https://github.com/alibaba/BeeHive)Beehive是一个主要解决依赖耦合和工程耦合的运行时框架。说到耦合,手机天猫这么大的一个app,各种依赖肯定是非常复杂的,模块之间的耦合必然是千丝万缕。我们要做的不是将这些依赖和耦合一一处理,而是把不合理的进行梳理、发现和解决,让整个项目处于一个健康合理的依赖和耦合范围内。问题依赖基本上有以下几种类型:模块间的循环依赖层间的反向依赖非强函数依赖下图是依赖的示意图。几条虚线的依赖是我认为有问题的依赖。将有问题的模块抽象出来并引入到Beehive中后,依赖关系会把所有的红线都引到Beehive模块上,Beehive模块是独立于每一层的。外部。Beehive的原理是每个对外提供服务的模块都需要向Beehive提供的Interfaces(接口池)注册一个抽象接口。请注意,此池中只有抽象接口。在开发阶段,调用者依赖接口池中对应的接口,以接口为参数,通过Beehive提供的工厂方法获取服务实例。该实例可以正常服务。在运行阶段,Beehive工厂方法根据服务的注册配置构造服务实例。如果:当前运行环境不依赖于提供服务的模块,则返回空;if:当前运行环境有完整的依赖,开始构建服务并返回。通过这样的方案,可以实现模块之间的解耦。UnifiedJumpProtocol&RewriteEngine统一调协议是一种基于URL的重定向方案,配合Rewrite引擎实现所有App调用的解耦。之前AppleCore上有一篇文章详细介绍过,这里就不赘述了:http://pingguohe.net/2015/11/24/Navigator-and-Rewrite.htmlBeehive和Unified的区别Jump&RewriteBeehive和UnifiedJumpprotocol的目的是解耦,两者的侧重点不同。通条主要是接口解耦服务,业务要求接口链接动态性强;Beehive是为了模块解耦,解决了开发阶段模块强依赖带来的痛点。以上就是我们这几年经历的整个手机天猫的解耦过程。在这个过程中,我们想了很多,踩了很多坑。当然,我们也积累了很多有用的工具。希望以后有更多的机会与大家分享,也欢迎大家与我们交流,相互学习。手机天猫其他文章推荐:别写死!天猫App动态配置中心实践天猫AppA/B测试实践安全模式:天猫App启动保护实践
