zeus00456

导航

研发编码的 4 个维度

@

引言

在实际项目开发中,有相当数量的研发同学在处理一个需求的研发工作时,仅仅实现功能,进行简单的自测(有时也省了),就认为研发工作已经完成了。
造成这种工作模式的原因多种多样,可能是研发同学本身品质的原因,可能是因为没有经历过相关的培训,可能单纯是因为没有找到更好的方法而导致的混乱,当然也很有可能是因为任务重工期紧……等等
这种研发模式当然是不可取的,某种意义上罪大恶极。不能保证生成环境项目运行状况,不能快速定位问题,不能快速迭代需求,不能快速理解现有业务,不能保证某一次修改不会影响现有逻辑,容易导致人肉运维制度……
因此,为了针对这种模式/现象/风气,梳理出研发的4个维度。这四个维度从不同的角度帮助团队衡量代码中需要干什么,以及研发工作是否都完成了。若项目研发团队足够成熟(当然要确定足够成熟,而不是自认为足够成熟),(抱拳拱手)请忽略此贴内容。当然,个人建议各项目团队,萌新入职后,团队首次开工前参考此贴,全队统一确认几个维度的落实目标、落实粒度,并划分短暂的时间(比如一周或者更短)进行试研发,以保证全队成员可以接受这种研发意识。

研发维度

实现功能的维度

这是研发最基本的维度,不可能出现不实现此维度的研发工作(否则客户也不干啊)
但要注意实现功能包含两个方面

  • 需求要求的功能要实现
  • 需求明确地或言外之意中禁止的功能不能实现

阅读理解的维度

对于服务器和生成环境来说,程序是用来run的,但对于作为人类的研发人员,代码基本就是用来看的,笔者很喜欢这个论调。
开发不是一锤子买卖,一个功能的初版和稳定版之间可能需要若干次修改、扩展、重构,而这个过程中需要研发人员可以看懂现有的代码、业务、设计。只有在充分了解的前提下,才能恰当的进行这些工作,因此需要研发人员让自己的代码处于可以被理解的状态。
什么是可以理解,笔者凭感觉给出一个下限:研发人员两个月后看自己的代码实现细节、或者另外的研发在大略了解业务和相关背景的情况下可以较轻松地看懂代码的业务、实现思路和设计,则可以认为代码是可以被理解的。

可以通过下列方式增加代码可读性

  • 优化代码结构
  • 使用通用表达,即统一写法
  • 望文生义的标识符命名
  • 恰当的注释

容易起反效果的坑

  • 通用表达最好做全队明确约定,严禁项目中按"党派"出现多套表达风格
  • 标识符的用法应该做好约定,应明确定义常规动词和介词的使用场景。比如,selectById 必然是通过主键(主键必然是id)查询一条数据的mapper接口;比如 searchXXX4Ids 比如是通过给定的id列表获取对应数据并按id - 数据整理成map返回的业务接口
  • 注释,推荐类说明注释、接口(此接口不是指的没有实现的 interface)注释、本地变量注释、复杂业务实现思路注释几种使用套路。严禁使用散弹式(逐行)注释,因为散弹式注释不方便随时调整,影响代码连贯性影响阅读,且散弹注释很难讲实现思路之类的内容表达清楚。翻译型散弹式注释建议就地处决(这种注释的效率实在是太低了),典型的为赋新词强说愁,下面给个例子,有耐心的同学把它想象成一个比较复杂的业务体会下(伪代码)
public void doSth(XxxBean bean){
	//获取xxx的code
	String code = bean.getCode();
	//用xxx的code获取其下xx信息
	List<XxBean> xxBeans = xxService.loadXxInfosByXxxCode(code);
	//遍历
	for(XxBean xxBean: xxBeans){
		//若xx的类型不是某某,跳过
		if(xxBean.getType()!=1) continue;
		//根据缓存填充某字段
		xxBean.setSomeField(cache.get(xxBean.getId()));
	}
	//对xxx下的xx数据进行什么什么业务处理
	doSth(xxBeans);
}

扩展的维度

在大多数场景下,大多数的研发团队没有死扣这一维度的必要,按需决定粒度。实现此维度的开发,需要有高级或技术经理进行比较良好的设计并搭建对应体系(可以理解成实现某个机制或者完成一个小框架)。通常还需要良好的持久层设计和支撑(不限于数据库)
对于需求迭代无穷无尽的项目,或者定制化项目,或者产品/甲方具有“大思想家”属性的项目这一维度尤为重要。笔者以为,能在一定意义和程度上将功能实现在需求出现之前,是一个成熟团队最重要的衡量指标,只用达到这种开发效果,才有可能从无穷无尽的研发工作中解放(至少部分)研发人员的研发能力,进而投入重构、优化、升级改造、组件抽取等有利工作中,这些工作可能需要投入一定的时间和经历,但通常(团队硬实力允许的情况下)最终会回馈到项目以及团队和相关个人上。
在时间、精力、能力允许的情况下,尽量不适用硬编码,尽量不适用翻译需求式的开发模式(太low了),需求综合比较复杂时考虑通过机制实现需求的思路,可以有效避免一次开发后很难扩展的问题。

监控测试的维度

监控指的是功能上线后,总不能处于脱管状态,一旦发生了不在预期内的情况,如何处理;同样的道理研发后提测了,如果功能没有测通,又通过什么手段排查问题。在上面的场景debug是不太现实的,能否在各种场景下快速定位问题(知道发生了什么)、定性问题、解决问题,也是对研发团队/经理/研发人员的一个常见考验。

显而易见的,日志和异常是成本最低廉的也是最可行的达成此维度的方式。但不是什么日志和异常处理都可以。

  • 一个前提,代码必须有至少及格的可读性(怎么算及格前文已经说了),否则定位了又能怎样,照样看不懂。
  • 两个原则。其一,日志异常必须正确。看似废话,实际上对于绝大多数项目而已,细翻代码,总能看到不少无效的日志和异常。比如下面案例,一般是起不到它们应该起的作用的(伪代码):
	logger.error("xxx失败"+e.message);
	logger.error("xxx失败,信息为",aField,anotherField);
	catch(Exception e){
		//这里进行一些操作,比如记录日志,生成错误工单等
		doSth(e);
		//这里想继续抛出
		throw new Exception();
	}

其二,日志异常必须恰当。最要命的场景莫过于生产环境挂了,很多日志,分析一下吧,结果没有一条有用的。这要求研发人员推断哪里是关键步骤、关键数据,是否有必要记录日志,怎么组织日志内容,如何才能方便定位;逻辑执行过程中取得了不期待的结果时什么时候正常返回处理返回值和提示,什么时候抛出日志,抛出的日志在哪里处理,处理到什么程度。按正理,这些内容应该在团队开发之初通过约定达成共识,但因为精力限制和不同项目背景不同业务场景,在测试联调阶段统一调整也算是一种降低成本的可行方案

  • 三种措施。
    首先,必要的约定讨论和约定传达是必要的,规定好日志和异常在当前项目的原则和常规套路是什么。
    其次,有效的反馈机制,(至少在初期)必须建立行之有效的检查机制,以验收约定的执行成果,同时,在问题还没有成规模前进行控制的性价比是最高的(多少项目中多少问题的存在并不是没人知道这是错的,什么样子才是对的,而是即使知道的变动的成本太大才置之不理)。常见反馈机制包括代码评审、上线审核、日常关注项目日志以及绩效。虽然作为一个研发,把绩效作为一种反馈机制很诡异,但确实有一定比例的研发同学善于发扬滚刀肉精神,贯彻非暴力不合作原则。对于绝大多数项目和产品,都无法做到无所谓日志和异常的处理,而此类研发同学输出的代码,很有可能切实的影响项目运行,因此一定程度的强硬措施是有必要的(虽然确实有一些团队将保证团队运转的强硬措施用成了压榨研发人员的手段)。
    最后,限制研发人员的调试手段,这是至关重要的一点。当测试阶段出现问题时,有一部分研发人员宁可通过本地连接测试环境,也要通过debug的方式调试bug,甚至有通过远程调试(笔者相信正常研发应该不知道这玩意)的方式debug生产环境bug的情况,细思极恐。调试手段是研发自测阶段的手段,测试环境和生产环境在正常情况下只能通过日志、数据、消息、分析代码等手段解决问题。如果用一个比喻来形容二者的区别,笔者认为听诊器 vs 解剖是比较形象的。限制调试手段的意义在于强制研发人员通过上述常规手段处理问题,并进一步建立相关意识,进而促进代码质量和项目质量提升。

posted on 2022-07-28 16:49  问仙长何方蓬莱  阅读(87)  评论(0编辑  收藏  举报