一、目标
- 认识到整洁代码对于提高代码质量的重要性,有内在意愿去写好整洁的代码
- 思考如何加强、提升外部管理,从整洁代码角度去提高代码质量
- 熟悉掌握一些方法技能,清楚什么是整洁代码,能够写出整洁的代码
二、意义
- 再复杂的系统最终也是由一行行代码构成的。所以,整洁的代码是构建一个良好系统的基石。
- 整洁代码是易读的,可维护性强,有利于节约维护成本,减少维护代价。
- 有利于防止“破窗效应”扩散
- 减少”技术债务”
三、背景介绍
什么是整洁的代码?
四、程序员的自我修养
- 端正态度(勒布朗法则,Later equals never)
- 良好的责任心意识
- 写好的、整洁的代码是与人方便,与己方便,是一件高尚的事,这样的人是一个高尚的人;反之,写烂的,晦涩难度的,给人挖坑的代码,则会给自己和别人带来麻烦,甚至为团队带去负价值。
- 在其意识里降低对代码“坏味道”的容忍程度,提高代码品味,养成“代码洁癖”的习惯
- “让世界在你走时比你来时更美好些”。
五、管理
- 营造崇尚高质量代码的团队氛围
- 加强人员交流,共同提升
- 高质量代码规则制定,遵守
- 自动工具和code review检查机制
六、技能提升
下面将通过一些实例,来提升大家对各种“坏味道”代码的甄别能力,提高写出“整洁代码”的技能,从而达到提高代码质量的目的。
6.1、重视命名
坏味道代码
- 名正才能言顺,一个好的命名往往是做好一件事情的开始
- 像给自己的小孩取名字一样重视程序中的每一次命名,变量,方法,类,包等等。
- 类名一般用名词短语;方法名一般是动宾短语;根据用途、目的起有意义的名字;优先考虑用良好的命名来表达含义而非注释;命名不宜过长;给每个抽象的概念选一个恰当词,并一以贯之;不同概念的命名要做有意义的区分。
- 别害怕长名称,长而具有描述性的名称比短而令人费解的名称号,比描述性的长注释好
6.2、良好的注释
- 注释应该恰到好处
- 注释不应该为了掩饰糟糕的代码而存在
- 误导:过多的注释难以维护,容易在修改代码后忘记修改注释,导致注释与代码含义不一致,产生误导
- 多余:代码表达已经很明确了,没必要在重复的写注释
- 日志类的注释:用来记录一段代码的修改历史,没必要,代码版本管理工具可以做到
- 注释的格式:类,方法,块,行等等
- 无论todo目的如何,都不留下糟糕代码借口
6.3、变量单一用途
坏味道代码
6.4、重复代码
坏味道代码
- 如果同一代码反复出现,就表示某种想法未在代码中得到良好的体现。
- 减少重复代码,提高表达力,提早构件简单对象
模板方法
- 定义一个操作的算法的骨架,而将一些步骤延迟到子类中。模板方法是的子类可以不改变一个算法的结构即可重定义该算法的某些步骤。
- 如果某些步骤逻辑相同,则可以很好的重用。
6.5、性能优化误区
- “过早的优化是一切罪恶的根源”-高纳德(《计算机程序设计艺术》作者,图灵奖获得者)
- 先做对,再做快。
- 先做可靠,再做快。
- 先把代码做整洁,再做快。
- 别为获得“一丁点”性能,就牺牲整洁。
- 让整洁正确的程序更快,要比让快速的程序运行正确容易得多。
- 不要想当然的做调优,请先用工具测试分析。
- 整洁获得性能
- 习惯上,所有的函数调用都增加了不必要的负担。事实上,一流的编译器优化会将短的代码转成内联函数。在现代的计算机上,函数调用代价接近0. – Joseph M.Comer
- 所以,不要为了所谓的性能,把本应拆分成多个函数的代码揉到一个函数里。
你会使用下面哪一种写法?
- 首先现代的java编译器会将第一种优化成第二种,所以性能是一样的
- 我们应该尽量缩小变量的作用域,就意味着:1变量能更早的被回收;2减少错误的概率
- 第一种写法相比起来也更加直观和更佳简单,易于维护
6.6、助手方法
- 提取小的,私有的方法来使计算的主体部分表达得更简明,代码也比较易懂
- 通过隐藏目前不关心的细节,让读者可以通过方法名字来理解意图,从而将复杂度分解到不同层次,使得需要同时关注的复杂度降低。
- 助手方法有助增强复用
- 助手方法利于方法职责单一,降低“误改”风险
6.7、方法的短小规则
- 方法的第一规则是要“短小”
- 方法的第二规则是还要“更短小”
- 我的目标:80%的方法在15行内,19%在15-20行,1%可以超过20行。
- 把方法写长很容易,把方法写短很难。
- “如果我有更长的时间,我会给你写更短的信”—Pascal
- 短小的方法一目了然,只专注做一件事
6.8、圈复杂度
- 圈复杂度是一种软件复杂程度的度量方法,用于计算一个方法中执行路径的数量。
- 圈复杂度大于10的方法存在很大的出错风险。
- 1-4:低复杂度
- 5-7:中复杂
- 8-10:高复杂度
- 11+:非常高复杂度
如何计算圈复杂读:
- 初始值为1,从上到下通过代码
- 遇到关键字if/for/and/while/or,每个加1
- 每个case(包括default)语句,加1
- 遇到一个三元运算符,加1
- 遇到catch语句,加1
6.9、使用卫语句
坏味道代码
使用卫语句优化后的代码
- 如果条件分支的某个分支的很特殊,很罕见,就应该提前检查,如果为真就应及早退出。这样的检查常常称作卫语句。
- 方法中的条件逻辑使人难以看清正常的执行途径。使用卫语句表现所有特殊情况。使用卫语句往往意味着各分支地位不是平等的。
- 卫语句可以减少条件表达式嵌套层次。
6.10、无副作用的方法
坏味道代码
- 方法承诺做一件事,但实际还会做其他隐藏起来的事。(从命令上看是个读方法,实际会有写操作)
- 容易让调用者发生误解,错误的使用该方法。
6.11、写一个方法要思考的东西
- 我写这个方法是做什么的,要完成什么样的目标和任务。确定方法的参数个数。
- 根据要做什么来给方法取个恰当的名字。
- 方法的执行步骤是在同一个抽象层次吗?不是则将低层逻辑提取到低抽象层次的方法中去。
- 一些代码行是不是在解决不同的子问题,如是则抽取到独立的方法。
- 这个方法做了几件事,做了目标外的其他事吗?如是则考虑拆分方法。
- 每个方法是否有副作用?
6.12、一些经典的“坏味道”
- 代码重复
- 方法过长
- 循环体太长
- 嵌套太深
- 抽象层次不一致
- 方法参数过多
- 用注释来掩饰拙劣的代码
- 命名太差
- 逻辑表达式太复杂
- 魔法数
- 一个变量多种用途
- 使用循环控制变量
- 一行代码表达多件事
- 一个循环做了多件事
- 一个方法同时做多件事
- 方法圈复杂度过高
- 方法返回null或者传递null(returning null from methodsis bad,but passing null to methods is worse)
- 简单代码过于复杂(炫技)
- 线上代码里面有很多测试的main函数