javanli / blog

blog
0 stars 0 forks source link

回顾一个大泥潭 #54

Open javanli opened 3 years ago

javanli commented 3 years ago

由于本文涉及比较多的负面评价,因此以Q项目代称。

简单交代一下背景。

Q项目是腾讯一个iOS应用,代码规模大概中百万行,开发人数几百人。

本人17年下半年本科毕业应届入职腾讯进入Q项目做iOS开发,20年初离职,现在回头想想这个项目的环境,仍是十分感慨。

大概从以下几个方面稍作探讨:

  1. 项目框架和模块化
  2. 基础组件
  3. 影响和溯源

1. 项目框架和模块化

这个项目一直是没有一个明确框架的,但存在一些模糊的演进。

混沌阶段

项目在19年之前是没有引入CocoaPods的,所有代码都堆在一个仓库,xcode项目下有几个子工程结构。

管理上有模糊的团队职责划分,比如好友团队、聊天团队等等,但映射到代码层面,边界是不清晰的,比如很多工具类就没有明确负责人,谁都不想管。

另外由于代码层面没有按团队职责解耦,很多代码是各个团队都经常去改一下的,比如聊天页面,虽然是聊天团队负责,但是好友团队也可能会往里面加功能,跳出来之后看,比较合理的做法是让其它业务团队向聊天团队提需求,让聊天团队去修改,才能保证代码的长期可维护。但当时就是各个业务团队自己直接进去改的。

总之,一个非常混乱的项目,完全不该是一个21世纪的大型工程该有的水平。当时我们隐隐约约能够意识到这种问题,但对这个项目到底有多烂其实并没有明确的认知,可能也没有烂太多呢?稀里糊涂地过呗。

跑偏了的模块化

众所周知,这种规模特别大的项目放在一个工程里,编译耗时非常久,IDE压力也很大,导致拖慢开发效率。因此大概是在19年的时候,此项目开始进行模块化拆分。

其实模块化拆分的更大意义在于逻辑解耦,能够很大程度上提升整体项目质量的下限。但当时Q项目团队还不太有这个意识,主要目的是为了优化编译耗时。

现在回头看,同时期业界大型应用已经有了比较成熟的基于CocoaPods的模块化方案。但Q项目这个闭塞的环境下,大家普遍对此认知非常浅薄。当时可能有个别同学有一定认知,但由于Q项目烂透了的技术管理体系并没能发声。

总之,这任务被摊派给了平台组的R同学。R同学经过一番冥思苦想和组内小范围的技术讨论后,硬怼出了一套模块管理方案。也不能算是完整的一套了,主要是写了一些Python脚本,能够帮助拆分好的模块编译.a静态库,并让主工程的每个模块在静态库编译和源码编译间切换。

我个人对R同学的评价是很高的,在不了解一个正常的模块化方案应该如何搭建的情况下,凭自己的理解,硬撸一套这样的脚本,并凭一己之力拆分出大部分业务模块,这个底子是真的很扎实,只是受限于当时Q项目整体的狭窄视野不知道怎么做才能更好,他好像也是应届进来没几年,强求他有更高的认知是不现实的。

总之,搞出了个缝合怪,对手Q算是进步,但仍然远远落后于时代。另外同阶段也引入了CocoaPods,但除了引入少量开源库,以及极少量的无依赖代码拆过去之外,没有对整体造成什么影响。

其实那个时候我们是知道CocoaPods的,只是没有深度使用,也不知道基于CocoaPods的成熟模块化方案。我没有跟R同学深入交流过,也就不清楚他为什么不选择在CocoaPods上做模块化。但后来经过回忆复盘,我觉得可能是因为一个小问题:CocoaPods的模块是不能依赖主工程的。几百万行的代码意味着没有人有能力一次性拆完 ,而现有代码的耦合非常严重,拆出来的模块和主工程间仍有错综复杂的耦合,不解决这些耦合,就没办法用CocoaPods管理这些拆出来的模块。比较直接的思路是从无依赖的底层库开始,慢慢迁移到CocoaPods,但这无法短时间内解决编译耗时的问题。所以R同学选择自己撸一套,模块通过子工程引入,是可以反向依赖主工程的。其实基于CocoaPods的话,解决方案也非常简单,开一个叫Main之类的库,把主工程整个丢进去,再往外拆,就可以渐进式地搞了。但是当时处在思维盲区,其实非常非常难想到。

2.基础组件

出来之后发现,Q项目的基础组件跟开源组件比起来,匪夷所思的难用。以配置系统为例(当时ABTest也是基于这套配置系统),配置key必须先在系统上申请,端上的组件只在初次下载和有更新时通知出去,业务方自己存储自己的配置。但其实存储这块逻辑是很容易写出点问题的,业务方一旦没存好配置,就真的丢了。

而业界常用的配置系统,存储是组件方做的,key也不需要先申请,可以在端上写个默认配置先用着,需要改的时候再去系统上下发就是了。就好用很多,对比之下Q项目的配置系统简直连个demo都不如。

3.影响和溯源

前面提到的烂都集中在代码层面,但代码层面的烂,意义是不够的。从技术品味角度,一切烂代码都是不对的。但落在实际项目上,我们需要更深入的思考,烂代码带来的负面影响是什么,有多大的必要去优化。

我曾经一度怀疑,提升代码质量有什么意义?看看这几百万行的shit,还能更烂吗?但是它也好好跑着不是吗?

如今跳出去一年半了,我大概可以回答这个问题了:有意义,即使抛开技术品味这类虚的理由,以及可扩展性这种当前不太痛的理由,仍然很有意义。

腐烂的代码给Q项目的负面影响主要有如下几点:

  1. 影响开发效率,拖慢版本节奏。

    • Q项目大体上是一月一版。这一个月的时间里,通常纯开发时间在2周左右,1周是边测试边修bug,还有一周说不清道不明,当初换领导的时候项目经理盘了半天没搞明白这一周到底是怎么被吃掉的,其实就是代码太烂,解决各种乱七八糟问题去了,这些问题太杂以至于很难明确分类,但是摊下来确实每个版本差不多能吃掉一周工作量。跳出来后的经历告诉我,同样的工作量,在一个质量优秀的项目里,完全可以压缩到2周一版。

    • 这个影响其实比成本更大。在大型互联网项目中,人力成本占比虽然不小,但是高一点低一点其实影响没有那么明显。但移动互联网时代迭代速度是非常大的优势,本就有些掉队的Q项目,迭代还慢,那不就更赶不上了?

  2. 增加测试成本。

    • 代码质量差导致更依赖测试,使得每个版本必须投入大量人力进行长周期的测试,并长期维护外部用户群体进行灰度测试。Q项目除了常规的测试岗位外,还有大量的外包测试人力。同时有专人维护一批活跃用户作为灰度用户体验新版。总体来讲测试成本是同规模项目的数倍甚至10倍。
  3. 影响产品功能AB。

    • 这个不纯粹是代码质量的问题,分一半的锅吧。另一半是安装包size的限制问题。
    • 项目质量的问题在于屎一样的配置系统,每次接入成本都很高,导致大部分功能都没有接入进行AB测试。这在移动互联网时代是非常落后的事情。
  4. 线上bug频出。

    • 多次大面积crash事件
    • 线上bug多(这个没有具体数据支撑,只是个感觉)
    • 热更新系统很差,线上问题通常选择扛到下个版本而不是修复

总而言之,虽然项目仍然可用,但劣质代码客观上拖累了Q项目的产品竞争力(虽然抛开技术问题,竞争力也不行,但这是另外的问题)。

最后追溯一下深层原因吧,为什么腾讯这样一个互联网巨头,里面一个这种体量的项目,能搞得这么烂呢?

  1. 产品导向和部门壁垒。
    • 产品导向在腾讯的崛起中起到了非常核心的作用。这使得腾讯相对其它互联网公司更加不重视技术,比如没有CTO,没有统一的基础技术团队等。
    • 部门壁垒可能来自腾讯的赛马传统,这使得各个部门各自为战,无法技术共享。
    • 这两点都是比较间接的原因,主要是拉低了下限,但很多更直接的问题上又能隐约看到这俩兄弟的影子。
  2. 晋级答辩体系。
    • 总体来讲腾讯的晋级答辩体系还是偏虚的。大部分需求其实没什么可讲的,答辩时也没什么亮点。自然催生出“没有困难就创造困难”的想法,明明有很好的开源方案,我偏不用,自己写一个出来,虽然不如开源方案,但是可以拿去答辩晋级啊。做基础组件的肯定比写业务的容易晋级啊,这就卷起来了。
    • 还有一个问题是,这种活开搞之前大家抢着搞,能答辩啊,但是第一个版本搞完之后,不太有人去做后续优化,不能吹牛逼啊。
  3. 技术团队管理层
    • 由于部分部门过度强调产品导向等各方面原因,导致技术团队的管理岗实际不怎么管技术,更多的是作为项目经理的角色,甚至常年不看、不写代码,全部工作就是沟通汇报。长期下来,技术团队管理层不懂/不管技术,技术决策都由小兵来做,做出的决策必然是狭隘且碎片化的。
    • 在一个稳定期团队里,空出的管理坑位肯定是要给内部晋升的,不可能从外部招聘。而内部员工大多来自小公司或校招,很难带来先进经验。甚至觉得团队现状才是正常的。
  4. 浮夸风气。
    • 很难讲具体成因,但总之结果就是,对大部分人来讲,吹牛逼重于做事。一些上面比较关注的事情,经常是写一天的代码,做两天的PPT,对着PPT每一页每个字每个图抠半天,我真的是吐了。还有很多人做事的时候糊弄糊弄,把PPT做得漂漂亮亮的,那就更牛逼了。
    • 不过总体而言,可能腾讯在这块还不算严重的,这大概是个社会普遍现象。