为何如此强调代码规范
笔者的前几篇文章一直在探索如何将代码质量检查切实执行下去的方案。有感于方案推行过程遇到的种种,不禁生出种种感慨。借此机会将一直以来的想法做一些总结。
背景
笔者现在所在的公司主要业务是电子政务方向,有过类似从业经验的同仁应该对内部的技术水平有了解,互联网公司或大型传统软件公司里的那些司空见惯,习以为常的技术管理流程或工具很多都是缺乏的,至于其它方面的欠缺这里就不多赘述,毕竟这不是檄文,而且幸运的是总有一部分人能够认识到这些差距,并不断尝试拉近距离。
随着政府信息化程度的增加,以及公司追求更高利润的天然诉求,传统电子政务的研发正在加速由之前的定制化开发演变成产品化开发,试图在收益不变的前提下采取批量复制的方式来大幅降低成本以攫取最大化的利润。
但往往理想很丰满,现实很骨感;这里直接引用笔者偶然发现,读来心有戚戚焉的一段场景描述:
我在某金融软件公司工作,随着客户数的增多,成本与效率/质量的矛盾日益凸显。
设想下,从一波人维护一套代码,渐渐变成一波人维护几套代码,这样一来,Bug增多,效率下降,抱怨也随之变多,再加上甲方挖人,最后人员离职,团队土崩瓦解,Game Over……
在这种情况下,一般公司会采取三种应对措施:
1. 一对一服务 - 项目制:多个团队,多套代码,多套标准,服务多家客户,但这样一来成本又难以承受,时间一长,肯定资不抵债。
2. 一对多服务 - 标准化:一个团队,一套代码,一套标准,服务多家客户,但客户不买账,客户说我的需求都是个性化的,你别来某某标准来引导我,叫你咋做,你就咋做,不愿意?那您走,我找别人家做。
3. 一对多服务 - 产品化:一个团队,一套代码,多套标准,服务多家客户,通过技术与配置化的手段,利用SOA思想,打造自己的产品化平台,但对技术投入要求较高,尤其是核心人才的依赖较大,中小型企业一般都很难留住这些人,只要他们一走,公司基本完蛋。
相信以上这类场景是绝大多数尝试做自己产品的中小型软件公司的痛点。
之所以在一篇探讨代码规范必要性的文章里会聊到这些,因此我们必须要有一个引子 —— 我们需要改变这种被动挨打的局面。
另外,虽然本文标题是讨论代码规范的重要性,但笔者接下来会从自身视角尝试缓解上文中介绍的困境。不过在最终依然会回到标题,介绍下个人理解的在这整个解决方案中代码规范的地位。
破局
直接列举笔者自认为的几个重要破局点:
关键点 | 现状 | 破局 |
---|---|---|
整包更新 | 1. 单主线开发,造成一段时间之后地方上的版本远远落后于主版本。 2. 相应功能增加和BUG修复只能通过文件替换来完成。(而且一般情况下是反编译项目上的文件进行相应更改替换) |
1. 借助Git强大的分支功能实现。 2. 定义master为主分支,各个客户为新开的一个分支,通过分支来解决各个客户的不同需求。 |
DevOps | 1. 集成、编译、测试、打包、发布、部署、通知等都是全人工操作。 2. 以上操作重复、枯燥、乏味,且出错概率高。 |
1. 通过引入DevOps流程实现CI/CD解放人力。 2. 让人工只做必须介入的事情。 |
代码质量管理 | 1. 代码规范形同虚设。没有相应的检查,落实保障机制。 2. 缺乏常态化CR,代码业务逻辑实现因人而异。 |
1. 引入代码静态检查工具进行强制校验,先解决经典的八成问题。 2. 逐步常态化CR,确保业务逻辑实现理解的一致性。 |
以上三者相辅相成,犹如彼此咬合的齿轮。
- Git强大的分支管理使得"以分支实现地区代码管理, 专码专用"成为可能,进而实现任何更新和迭代的整包部署,这极大减轻了研发组进行新需求实现和BUG修复时候的后顾之忧,以及节省宝贵的人力用来作系统优化以及界面的人性化等等必须人工介入的事情。
- DevOps的自动化特性加快了部署,测试频率(频繁测试才是软件品质保证的最大依凭),给所有人以信心:
a. 新的变更引入的错误一定是编码阶段引入的,而不会是部署阶段。这就去掉了问题排查时候一块非常大的干扰源,方便研发人员快速定位问题。
b. 我们的程序是经过千百万次测试的。DevOps的自动化特性决定了其能够实现一天二十四小时不打任何折扣的不间断部署。研发端和测试端不会再出现互相等待的情况。
c. 随时都有一个可发布,可查看的最新版本。研发团队的工作不再因此而中断,确保团队的持续工作。也确保其它部门工作的顺利开展。
d. 涉及到Git分支操作时,研发人员只需要关心当前问题属于哪个区域并切换到对应分支进行修复。 - 代码质量管控确保代码质量,进而确保功能之间少问题,松耦合,方便迁移。大幅降低地区性功能迁移时候的摩擦成本。
我们总是尝试通过将暂时不着急的事情后移,从而腾出人手来研究当前更紧急的问题,但是被后移的那些事情并没有消失,反而随着时间的流逝会也变得紧急起来, 所以正确的做法应该是改善现有的技术研发流程,解放人力,进而提升研发效能。
强调
我们还要清楚地认识到:即使以上几个关键点100%落地,依然可能失败。目前能够想到的一个关键性问题就是"对于需求和BUG的全流程追踪以及回溯是否能跟上?"。
分支机制建立起来之后,如果任其发展,必然出现"同一个需求或BUG在多个分支中重复性地从零开始实现或修复"的问题,这个问题在研发团队比较庞大或者团队成员流动性较大的时候会表现得尤为突出。
对此笔者目前能够想到的办法是:"强有力且持之以恒的规范技术/项目管理流程"。
- 每个需求和BUG修复都需要进行相应的审查。
a. "是否需要纳入到master分支,还是仅仅作为区域特性?"。
b. "是否在过往庞大的需求和BUG池中已经有过类似的问题?"。这一点是极其考验产品经理和技术负责人能力的,因为它需要将问题抽象的能力(诚如《暗时间》里介绍的]) 。 - 对于出现的每一个新需求和BUG修复都要有完整的生命周期记录。并且存档入库,确保当类似的需求和BUG出现的时候能够被检索到,并被快速应用。
以上每一步都注定是一个需要长期坚持,永远不能松懈的过程。而且也不难看出以上问题已经超出了研发部门的范围,至少涉及到研发流程的上游。
而且这个问题的解决才是重中之重。上面列举的破局点只能算是起步阶段,确保它们发挥出预想中的作用还得依仗后面持续不断的高效管理。
最后
最后让我们回归本文的标题,介绍下以上的解决方案中代码规则的地位。
软件工程发展到现在,借鉴了不少建筑学的概念和知识,很多时候我们也将软件的构建比喻成建筑的搭建过程,那么类比之下软件中被称为"砖块"应该就是每位研发人员写下的代码了,而由代码堆砌起来的每个功能模块则可以类比为建筑中的单个房间。那么请问:
- 如果你对眼前建筑里砖块的粗制乱造,搭建过程中砖块的随意堆砌都不甚关心,放任自流,试问这栋建筑物阁下敢走进去吗?
- 在上一步的基础上,每次新功能的加入和问题修复还不能对建筑的任何部分进行改造以更加适应当前的业务情况(或因新业务的加入或大家对既有业务有了更深入的理解),也就是基本等同于你的每次决定都在给自己增加一副镣铐,这导致随着时间的迁移,系统的可腾挪空间越来越小。
这里需要专门强调一下的是:我们并不是贬低新功能和新技术加入,以及界面美化(这个是领导重点关注的)的重要性。只是在试图将全部注意力集中到类似界面美化,新功能和新技术的引入的时候,我们是否应该回头审视一下研发部门目前真正的痛点是什么 —— 每个人都喊忙,但大量宝贵的人力被浪费在一些枯燥的重复性事情上,加上越来越大的业务压力,导致所有人士气低落,每个人只顾自己眼前的事情,绝不多迈出一步(毕竟眼前的都忙不完)。
以上问题在一个运转多年的软件部门或多或少都存在,而为了能够改善这种情况,我们需要一些方法。当然大刀阔斧干掉眼前这帮人,从外面招聘大量高水平的技术和管理人才是一种方法,但这种只能在脑子里痛快一下的想法注定不会实现,我们只能在面对这一大团乱糟糟的"困难"绒线团时不断尝试,寻找突破口。而幸运的是,我们似乎终于到找到了其中一个线头:
- 借助机器的强制检查,我们可以100%确信代码库是满足基本要求的。而且这个过程无需投入额外的人力。
- 有了上一部作为基础,我们可以确保每个功能的松耦合, 进而保证"每块砖"的可迁移性,这让整包部署成为可能性(因为功能迁移的摩擦成本大大降低)。
- 建立大家对于地基的信心,只有对所处的代码环境有信心了,你才能放心地专注于你眼前的问题。
世界是复杂的,展现出来的问题也是,我们经常被问题的表现所迷惑。但只有深入问题本源,才能找到这团乱糟糟的绒线团的线头,最终将它捋顺,否则只会在一次次地冲锋失败后陷入绝望。更有甚者因此而觉得理所当然——这个问题就应该这么让人痛苦,我们是无法解决的,我们只能忍受这种痛苦抑或是换个行业。