真的好久好久没有写博客了,年终总结都拖了3年了…有些事情我真的还没想清楚,等我想清楚了写个5年总结吧
先说问题
言归正传说说技术架构的事情,目前随着移动开发越来越成熟,大型APP也越来越多了,动则30万行以上代码量的工程也越来越多了,随着代码量上涨,工程越来越庞大,一般情况下公司为了方便管理和一些实际的产品发展的需要,会把客户端团队分拆成多个小团队各自独立开发需求,现在按发布APP算整Team的话,客户端工程师很容易就超过20个人了,我个人经验超过10个人的团队,如果分工和架构设计不合理,很容易就会出现扯皮的事情,这个情况我自己经历和听说都很多了。
如果没有专门针对这种大规模的客户端团队去设计合适的架构,常见的问题一般都是下面几种,首先假设整个客户端团队又分为a,b,c,d四个小团队:
- 1.a团队某个工程师不小心忘记提交了某个文件,在他的开发环境里编译运行都没有问题,但别人一拉代码,直接就编译错误,正巧这个工程师提了代码就去开会了,然后b,c,d三个团队的人全都歇着了,因为整个APP工程编译错误…
- 2.a团队负责的业务部分的代码有一个偶现的bug,会有20%的概率导致APP崩溃,是个很诡异的问题,查了两天了还没查出来,结果在a团队没有解决这个问题之前,整个客户端团队会在效率在很低的level上运转…
- 3.a,b,c,d四个团队正在为APP的1.2.1版本开发各自业务功能,预计在某天发布版本,但到了那天以后,发现a团队部分实现的功能一直提测不通过,无法达到发版要求(好吧,怎么老是a团队,这里我只是举例,但碰巧的是,实际情况中恰好容易出问题的那个团队正好经常是同一个团队),整个发版计划延期了,因为大家都在同一个git仓库上提交代码,a团队没办法把自己的提交单独回滚回去,至少很麻烦,容易引起更严重的问题..
这里我列举的三种情况只是我经常遇到或者听说过的case,实际上可能还有很多其他蛋疼事情没有涵盖进去,但大家可以看到,这里有些问题是通过一些简单粗暴的手段是可以解决的,我的前提条件设置比较简陋,就是这个团队的架构师完全没有任何这方面的概念,或者压根就没有人去用心思考过架构的问题。
实际需求
客户端的架构设计应该是个什么样的,应该以需求出发,这里我总结了一下我自己遇到的大部分情况的实际架构诉求,也就是一个客户端工程通常包含哪些部分:
- 纯技术驱动的公共模块
不管哪个客户端总会需要处理很多和具体业务无关的纯技术需求,比如语音播放,视频播放,网络,长连接,推送等等,这部分通常大家都会有专门的一层和专门的人来维护
- 公共的产品部分
这一部分在大部分复杂的app中都是存在的,但在实际的架构设计中,又有不同的处理方式
- 各个团队的单独产品模块逻辑部分
这个部分的复杂度和粒度是和实际产品以及团队的划分相关的,可大可小
- 最终的发布出口
这里我用了‘发布出口’这个词,其实是我自己意淫的,我只是想更严谨地表达发布的这个概念,因为它不一定就是一个工程一个项目,很可能就是一个脚本,具体看怎么做了
这个样子
根据实际需求来说,最终整个客户端的架构设计应该是这个样子的:
好吧,看了这个架构图,很多人会觉得我说了一大堆废话,因为大部分的客户端架构都大约长这个样子,但实际上我看过的很多项目都只是概念上是这个样子的,随着产品需求不断改动,实际上的模块基本上最终都成了一坨,除非特殊需要的时候,是不会有人去把这个架构坚持维护下去的。所以为了让它可以持续地保持可供大型客户端团队进行迭代开发而不变形,我们应该有些原则性的东西在里面。
我认为每一个方块代表的部分都应该遵循一下几个原则:
- 一、它和所有其他方块代表的模块是物理隔离的
- 二、它对于他的上面的方块都应该暴露一个发布版本号,并且应当对自己的旧版本向下兼容
- 三、它只依赖它以下的方块代表的某个版本的模块就可以独立编译运行
- 四、除非情况特殊,它提供给其他模块的调用方式不应该利用反射
如果加上了这几条原则,那么我们的最终架构图的层级没有改变,但会成为一个包含很多映射关系的拓扑结构,抱歉xmind用得太烂,画不好,懂我的意思就行了:
简单来说,其实就是把团队内部的开发方式搞成了类似接入外部sdk的开发式,但是我们模块间调用上隐含了更多的产品逻辑上的依赖,包含了更多整个产品层面上定制化的东西,所以又不能完全采用外部sdk的方式进行开发。
复盘问题
针对之前提到的几个问题,这样的设计是不是真的解决问题了可以一个一个看:
原则一和三由于物理隔离和单独编译运行,让各个产品线之间的开发调试各自独立进行互不影响,小团队内部的错误不会向大团队扩散。
原则二的版本管理,让各个模块都可以灵活地进行升级和回滚并且对其他模块产生最小的影响
关于损耗
上面讲了解决的几个问题,但任何架构设计解决了一些问题必然会引入另外一些问题:
- 整个团队灵活性大大降低,在团队不算多的情况下,效率大打折扣(想像一下最底层模块修改了一点东西然后发布版本向上冒泡的过程)
- 设计的复杂导致沟通成本上升
- 各自独立开发测试的结果可能会在最终发布出口上产生冲突,如果在最终发布APP的测试覆盖不够全面,问题就会很容易地被暴露给用户
关于粒度控制
如果不单独写一套粒度控制模块,各个平台理论上最差都可以做到页面级别的粒度(客户端开发很多东西都和ui关系比较紧密),比如Android上的Activity和Fragment以及ios上的UIViewController,但如果希望进行更精细的粒度控制,那就必须做一些代码设计了,这个做法千差万别,我觉得找到最适合自己团队的方式就好了。
Different Platform
其实以上的这些东西是不分平台的,不管是ios还是android理论上都可以这么设计,不同点在于工程构建工具的选择上面,只要能包含版本管理,工程依赖,资源管理的工具我觉得就可以满足需求了,ios开发推荐cocoapods,应该没有其他更合适的了,android平台maven和gradle听说都很厉害,实在找不到合适的,自己针对性地开发一套,成本也不会非常高,只是要趟很多蛋疼的坑罢了,其实用工具也会趟很多坑..
完
好吧,我的逼装完了,感觉用架构这个词会被很多人喷得体无完肤,毕竟很多工程师都不喜欢被别人架构,但这里又找不到合适的词表达这个意思,如果觉得这个东西说得太简单没什么收获,绕道就好了,求不喷