本文共 3541 字,大约阅读时间需要 11 分钟。
上篇文章中我们介绍了《》。本文让我们回到业务层上来具体看一下如何提升研发效率。
说到研发效率还真不仅仅就是如何写代码这么简单,读过《人月神话》一书的人都知道,要开发一个产品,并不是人越多越好,而是涉及人与人之间的信息传递成本,有时候人与人的沟通成本甚至大于写代码的成本。另外,当系统变复杂了以后,代码应该写在哪里,也就是人要去理解这个原有的系统也变得很困难。有一个冷笑话:评估一个业务需求,先要找各个系统的产品经理花上2 周评估时间,然后开发同学再用2 周时间评估怎么实现,最后真正写代码只需要1 天时间。由此可见,大部分时间并没有真正花在实现业务需求上,这样的研发效率肯定是不合理的。
所以要考虑如何解决人写代码的效率问题、人与人沟通的问题,这是解决业务研发效率的关键所在。
1.沟通效率问题
有合作必然就有沟通,提升沟通效率最好的办法就是形成默契,要形成默契就要通过规范和约定等手段把大家圈在同一个语言频道上。
需求阶段的沟通比较多,如统一术语、需求结构化表达、统一业务身份。
(1)统一术语。这在一个公司非常重要,比如在某些公司,“PM”这个词是指产品经理,而在另外一些公司是指项目经理;还有诸如应用、系统、模块这些基本的称谓,如果大家理解不一样的话会很糟糕。
在公司中形成术语也有一些技巧。比如给产品取一个好名字,名字既可成为术语也可以是很好的传播符号,像滴滴的一个服务框架叫DiSF(didi service framework,滴师傅),这个名字有内容、有含义很容易被记住。在公司中与人沟通也是一样,如果很难一句话向别人说清楚某个产品或者项目,那么推广起来就会比较费劲,因此,把自己的产品、项目或任何需要向别人表达的事情术语化可以减少沟通的成本。
(2)结构化表达需求。互联网公司中都是需求驱动产品和技术的,提出需求的人大多都是运营和产品经理而非技术人员,这就不可避免地存在不同岗位人员的沟通理解问题。需求的结构化表达就是把需求用一系列的术语、图标、页面等可以更好理解和呈现的方式(一般产出就是PRD)在同一个语境中表达出来,让对方更好的理解。
沟通需求的过程就是把不确定性确定下来的过程,需求越具体沟通越容易。把需求结构化,和把系统中需要经常改动的逻辑配置化要达到的效果是一样的,最终产生的结果就是一个变更记录。
(3)统一业务身份。业务身份是管理一个业务在各个业务域中定义的业务规则索引,是一串平台可识别的编码,该编码由构成业务的要素经过一定组合关系运算生成。在平台的运行域中,各个业务域的系统根据输入的参数条件,进行业务身份判断运算,最终根据识别出的业务身份结果,执行该业务在本系统定义的业务规则。
要实现统一业务身份必须要解决:
- 系统之间同一项业务的联通性问题,让系统自动呈现业务整体视图;
- 业务条件没有生命周期管理、系统长期维护困难的问题,要统一业务条件识别;
- 业务上下线相互影响、回归工作量大和效率较低的问题。这就要对业务逻辑进行能力抽象,建立封闭性,从而隔离业务。
要对业务身份进行统一管理,需要实现:
- 对业务身份标识的统一注册和管理,一般需要构建一个运营平台;
- 有业务规则的配置界面;
- 规则的执行引擎。
所以统一业务身份需要入口的注册管理、规则的配置与变更,以及规则的运行域,缺一不可。
2.开发效率
如何高效地写代码是程序员永恒的话题。这涉及很多因素,如程序员对代码语言本身的掌握程度(比如JDK8 中引入闭包代码可以使代码更简洁),写代码所用的IDE以及快捷键的使用程度,等等。笔者在这里先抛开这些问题,阐述下从开发到测试再到运维的整个效率问题。
开发人员都不希望别人乱碰自己写的代码,对代码有绝对的控制权,所以一般都喜欢掌控(Owner)系统,即这个系统我说了算。在这种情况下,曾有一段时间我们把系统拆得很小,结果诞生了很多同质的系统,越来越多地在做重复的事情;此后又经历了系统合并的阶段。但是,系统合并也会带来新问题,即开放过程中冲突比较厉害,包括打包部署的效率都很低,在这种情况下会有两种解决方案:一是开发态和运行态分离;二是对系统进行分层和抽象建模。
所谓开发态和运行态分离,就是大家线下的开发都是独立进行的,包括打包和部署,接口的调用分开,走远程调用。但是在线上部署时,都是部署在同一个容器中,把远程调用变成本地调用。这种思路我们在“合并部署”一章中有介绍,本质上可以做到开发态和运行态的分离,同时兼顾开发效率和运行效率。
将开发态和运行态分离的另一个方法就是采用Node 技术。Node 被很多前端同学推崇的重要原因也正是它把前、后端的开发解耦了,解决了开发和调试效率低下的问题。但是这里也会出现一些问题(我们在“无线化”一章中已有分析):解决办法也是将开发态和运行态分离,通过jtemplate 模块引擎使前端可以在Node 中开发程序,但是线上仍然可在Java 中运行,兼顾前端和后端的开发效率和线上的维护成本。
第二种对系统进行分层和抽象的解决方案是非常常用的。最典型的是对交易环节进行一次重构,对典型的交易场景进行抽象建模设计,对核心流程进行流程引擎改造,使得交易流程可以增加很多扩展点,不同的业务场景可以根据需要扩展自己的个性逻辑,整个交易环节抽象成一个流程框架和一系列的业务扩展,每个不同的业务之间互不干扰。
3.测试效率
整个软件生命周期涉及很多环节:需求、开发、测试、上线、运维……涉及很多协作。这些环节都会对效果有影响。其中,测试效率非常重要,因为测试花费的时间几乎和开发所花的时间是一样的。关于如何提升测试效率,我们总结了一些实践经验,分述如下。
全链路Beta 测试
继续保持Beta 环境与线上环境的一致性,将核心链路上的应用,Beta 环境HSF打通,减少90%由于环境问题导致的P1、P2 故障。
Beta 发布环境改造之前
Beta 发布环境改造之后
打通之后,可以实现以下效果:
- 测试环境可以做到召之即来,挥之即去;
- 在分批发布前,可以在极短的时间内有针对性地验证核心功能;
- 也可以选择性地屏蔽Cache 的访问;
- 数据轨迹可以实时透出。
4.运维效率
运维包括线上和线下两部分,运维效率会在两个环节表现得最明显,一个是线下的打包编译步骤、代码分发步骤;一个是线上的下线→重启→上线步骤、发布检查步骤和回滚步骤。下面我们分别看看在这些环节有哪些地方可以优化。
(1)打包编译环节
优化流程。环境分配,可以预先分配好代码copy,要主动准备而不用每次编译代码时再做环境方面的准备工作;
预处理。监控代码版本修改,当代码被修改后,自动触发代码合并冲突检查做代码编译和打包操作,不要等到用户点击再触发;每个分支代码更新主动和主干做Merge,发现有冲突要主动通知相应开发人员修改,不要等到打包部署时再临时修改;
代码编译优化。规则检查,业务依赖的包要做依赖规范化管理,通过工具识别依赖;减少应用依赖SNAPSHOT 版本Jar,可以节省Maven 编译时间;Maven打包优化,优化Maven 配置减少不必要的消耗;
增量编译。减少编译时间的办法之一就是只编译变化的部分;比较代码修改时间和编译的代码更新时间可以区分那些修改的类,并针对它们做增量编译,大大减少编译时间。
打包机器硬件升级。提升编译速度的另一个办法是升级机器硬件,使用更多的CPU 或者更多的内存可以明显提升编译速度;多组机器standby 以处理并发修改情况,并始终保持应用处于可用状态,减少开发上厕所的次数。
(2)代码分发步骤
代码分发主要考虑两个问题,一个是代码的下载,最好是支持P2P 下载,这样的下载效率最高(虽然大部分情况是HTTP 下载较多,但真心不建议采用);二是如果代码包比较大且同时下载的机器比较多时,要考虑下载机器的网卡流量是否满足,这一点必须特别留意。
(3)下线、重启、上线步骤
下线环节。下线被动等待15 秒健康检查失败,能否主动通知LVS 下线,而不是被动等待3 次3 秒的检查失败后再下线;
重启。初始化各种服务,去掉不必要的服务初始化,将一些服务改成慢加载,部分服务可以并行初始化。
(4)回滚
回滚等于重新发布,直接利用本机的老war 包快速重启,不需要再走包分发步骤,要有手动回滚脚本。如果回滚时间长则减少回滚批次,采用发布一批机器就下线一批机器的方式:下线的机器保持standby,老代码不提供服务,出现问题后再立即下线新发布的机器,将standby 的机器立即上线。这样可以快速达到回滚的目的,在30 秒内就能完成回滚。
本文选自《大型网站技术架构演进与性能优化》,作者许令波,电子工业出版社7月出版。
转载地址:http://uudxx.baihongyu.com/