整洁代码的必要性
代码整洁非常必要,将童子军军规运用到开发
代码非常容易随着时间流逝而变的混乱和腐坏,越混乱的代码就越难维护,将直接影响生产力的下降,所以必须时时保持代码整洁,积极的阻止腐坏的发生。将童子军军规运用到我们的专业领域:
让营地比你来时更干净!
如果每次修改后的代码都比修改前更干净,则代码会一直保持整洁,保持易读和易维护。
有意义的命名
名副其实,无歧义
选择能正确体现其作用的变量、函数、类名称,并在后续的开发中,一旦发现更合适的名字,则立马修改;不要出现魔法数;在选择单词时注意该词是否会引发歧义,如果会则慎用,避免单独使用字母l(小写L)或者O(大写o)。
长优于短,名称易读,详细且匹配,易于搜索
作为名称描述作用时,短句会比单个单词的描述更清晰,则可以直接使用短句来做命名,另外不要使用对短句的缩写(比如采用每个单词的首字母),这样易读性极差,失去了他的意义。而详细的长名称又极易辨识和搜索,在查找时,会很便捷。
类名为名词,方法为动词
用名词做类名,动词做方法名更能体现其意义或要做的事情
关于函数
函数应短小,只做一件事
函数应该短小,冗长的函数通常在内部做了很多事,其特点是行数多,逻辑复杂混乱,对后续的维护者非常不友好,应该避免写这种函数,如果写出了,应该在写完后,区分功能块区,然后拆分函数,这是做这件事的最佳时期。
函数参数越少越好,不要超过三个
对于使用者来说,通过函数名可以明白该函数的作用,而参数越多,则需要考虑的情况也就越多,因为需要明确每个参数的作用,以及不同的参数值会产生的情况。当参数数量到达3个或者更多时,则意味着其中某些参数可以封装成一个对象,或者一同存入某种数据结构了,这样不光可以减少参数数量,也会明确出参数间的联系,易读性也大大增加。
按思路写好函数后,仔细打磨,抽象拆分,合理命名。
写代码应该和写别文章一样,在写的时候是想到什么就写什么,然后再打磨它,直到它变得整洁。当写出了冗长而复杂的函数后,分解函数,修改名称,消除重复代码,遵循规则,组装好最后的函数,则能获得一份整洁的代码。
关于注释
尽量不要使用注释,用属性名或者方法名表达出意思,删除注释的代码
一句话,有注释的功夫,不如提取出一个合适的名字用来给属性或者方法命名了。注释后的代码不要保留,立马删除,因为后续的维护人员不知道这份代码是否还有用而不敢轻举妄动,而这份注释后的代码只会随着时间的流逝永远住在了这份代码中。不要害怕删除后的代码丢失,代码管理系统(Git)会帮你记住。
关于格式
概览在顶部,合理设置间距,区分代码块
垂直方向,向报纸学习,通过标题可以了解内容大概,一页内容中由多个短小的故事组成。代码中,名称应该一目了然,顶部为高层次概念和算法,细节依次往下展开。属性与方法之间,方法与方法之间,应该有合适的间距,属性和方法应该有各自的代码区域,合理区分代码块。
有联系的代码放一起,变量声明在顶部;
相关的函数,比如引用与被引用,比如意义相关,get和set,比如方法重载,放在一起将大大提高该代码模块的可读性。变量应该声明在使用到他的代码块的顶部,比如函数的顶部,循环的顶部,全局变量声明在类的顶部。
运算符处应该有合适的间隔和靠近,水平上限不易过长
使用到运算符的地方,将具有强关联关系的部分靠近在一起,而不具有强关联,需要突出运算符的地方,添加适当的空格做间隔,比如:(2*a) + c。水平上的代码长度不要过长,不要超过120字符。
关于错误处理
不在catch中处理逻辑,不返回或传递null值
将业务逻辑和错误处理分隔开,不要在catch中添加逻辑处理代码。
不要返回或者传递null值,只要有null值存在,就要添加一处或多处的判空操作,增加代码量且容易出纰漏导致出现空指针异常。
关于单元测试
遵循TDD三定律
定律一 在编写不能通过的单元测试前,不可编写生产代码
定律二 只可编写刚好无法通过的单元测试,不能编译也算不通过
定律三 只可编写刚好足以通过当前失败测试的生产代码
保持测试代码的整洁
测试如果不够整洁的话,随着代码量的上升,维护成本也要上升,最终成为开发者的主要抱怨对象,从而对测试代码失望,而放弃测试。
整洁的测试代码需要有极强的可读性,需要跟其他代码一样:明确,简洁,还有足够的表达力。
每个测试中断言的数量应该最小化,只测试一个概念,F.I.R.S.T.原则
每个测试中,避免测试多个概念,会非常混乱,减少断言的数量,单次只测试一个概念,清晰明确且不会有遗漏。
遵循F.I.R.S.T.原则
快速(Fast)测试应该快速运行
独立(Independent)测试应该相互独立。
可重复(Repeatable)测试应当可在任何环境中重复通过
自足验证(Self-Validating)测试应该有布尔值输出
及时(TImely)测试及时编写,单元测试应该恰好在使其通过的生产代码之前编写
关于类
java类的组织
类应该从一组变量列表开始,以公共静态变量—私有静态变量—私有实体变量的顺序出现,很少会有公共变量,公共函数跟在变量列表之后,然后私有工具函数。测试最大,需要测试某一私有函数时,可以适当放开函数访问权限。
类应该短小,单一权责和提高内聚性
单一权责原则认为,类或者模块应有且只有一条加以修改的理由。即一个类只负责处理一种类型的事情,如果能抽象出其他类,则拆分开。
应提高类的内聚性,即类中应该拥有少量实体变量,该变量被类中多个方法操作,越多方法操作的变量,则越粘聚在类上。如果每个变量都被每个方法使用,则凝聚性最高。保持高凝聚性则可以获得多个短小的类,如果一个类中出现了引用数量非常少的变量,则说明它所负责的模块具有独立性,需要考虑拆分出新的小类。
为了修改而组织
对于多数系统,修改将一直持续,而每次打开类进行内部代码的修改,都有可能导致其他功能无法使用。为了避免这种情况,在进行类的组织时,应该尽可能将类拆开,独立负责独立的功能,需要修改或者添加代码时,则不会影响到其他功能。
关于迭进
通过迭代设计的方式达到整洁的目的
遵循以下准则,迭进优化代码,可以达到整洁的目的
运行所有测试
不可重复
表达程序员的意图
尽可能减少类和方法的数量
运行测试可以保证系统能够一直如预期一样工作。对代码进行重构,提升内聚性,降低耦合度,模块化系统性关注面,缩小函数和类的尺寸,选用更好的名称等等,这样可以消除重复,保证表达力,减少类和方法的数量。
关于并发编程
多方面防御并发代码问题
将并发代码和其他代码分离,各自有各自的的开发、修改和调优生命周期。
限制共享数据的访问,共享数据越多,则可能忘记加锁,多耗费精力加锁,很难找到错误源。
使用数据复本。多线程访问数据的复本,最后在单个线程中合并最终数据,减少出错的可能性。
线程尽可能独立,不与其他线程共享数据。线程独立,则不会出现与其他线程纠缠的问题,会轻松许多。
了解使用java线程安全类库,了解线程的执行模式及解决方案
涉及到多线程访问的数据,可以使用线程安全的类库存储数据。
了解生产者-消费者模型
,读者-作者模型
,宴席哲学家模型
,学习其优质解决方案,运用到开发中,减少问题的产生,提升编码效率。
缩小同步区域
尽可能减小同步区域。加锁的同步区域会带来延迟和额外开销,如果将同步延展到最小临街区范围之外,会增加资源征用、降低执行效率。
全面地测试线程代码
保证其他代码能够正常运行,在此基础上,多方面进行测试,比如运行多于处理器数量的线程,再不同平台上运行。装置试错代码,使用自动化技术,增加对线程代码的测试。