代码整洁之道

单一权责原则SPR,开放闭合原则OCP,DRY(不要重复你自己)原则, 倒置依赖原则DIP

领域特定语言DSL

简单设计的四条规则(重要性从高到低),运行所有测试,不可重复,表达程序员意图,尽可能减少类和方法的数量

《代码整洁之道》

表达力,少重复,小规模抽象

<有意义的命名>

长名称胜于短名称

避免加类型编码,即使是实现也最好用impl

类名为名词,方法名为动词

同概念用同词,如不要同时使用controller和manager

插入用insert而不要用add这种双关语

添加合适的前缀和提供语境或者提供一个单独的类如address

</有意义的命名>

<函数>

只做一件事:看是否能再拆出一个函数,且不止是重新诠释

每个函数一个抽象集:使相同范围内的函数调用处在同一个抽象集

</函数>

<函数参数>

尽量减少参数数量

使用单参数的理由:询问参数的问题,操作该参数,事件

不使用标识参数(boolean),而是分为两个函数

二元函数:最好为单个值的有序组成,如Point(0,0),否则尽量将函数作为其中一个参数的成员如outputSteam.write(fileName)

如果需要多个参数,其中一些就需要被封装成类。

函数名为配合参数的动词,如writeFiled(name)

确认函数是否可以作为参数的成员方法

指令不应与询问一起使用,将setAndCheckIfExisted分隔为if(exist){set}

不使用错误码,而是抛出异常

错误处理应该是单独一件事

DRY原则

不断改进代码,不需要一开始就按照规则

<函数参数>

<注释>

尽量使用代码来阐述,而非注释。注释随着代码维护中很容易脱离代码。

法律信息版本说明等注释是有意义的

注释可以用来阐释依赖库,提供警告,有时如果未能达成所有目的可以留下TODO信息 (但必须及时删除)。

编写Javadoc来进行良好描述

在有代码控制系统后,不需要日志性注释,也不需要注释掉代码

</注释>

<格式>

源文件顶部应该给出高层次概念和算法,细节向下逐渐展开

精密相关的代码应该靠近,独立概念应该用空白行隔开(如函数)

函数调用者尽量放到被调用者上

团队使用相同的格式规则

</格式>

<对象和数据结构>

隐藏实现不是单纯使用getter和setter,而是关乎抽象

过程式数据结构易于添加函数,面向对象易于添加新类型

得墨忒耳律

数据传送对象DTO只包含公共变量没有函数。bean则多包含了getter和setter

对象暴露行为,而应该隐藏数据。 数据结构暴露数据,没有行为。

</对象和数据结构>

<错误处理>

使用异常而非返回码

使用可控异常会导致底层修改影响到较高层,一般情况下依赖成本大于收益

异常应该给予足够的环境说明,如所做操作,失败类型等

如果对API错误处理太繁琐,可以打包API类进行处理,将繁琐的错误独立出来

尽量避免返回或者传递NULL,而是抛出异常或者返回特例对象如空列表

</错误处理>

<边界>

使用学习型测试来理解第三方代码

使用adapter来封装与API的互动

</边界>

<单元测试>

FIRST

快速,独立,可重复,自足验证,及时

</单元测试>

<类>

JAVA约定顺序,共有静态常量,私有静态变量,私有实体变量,公共函数,私有工具函数

SRP单一权责

增加内聚性

当增加新功能和修改原功能都需要修改同一个类时,违反SRP,如SQL语句可以试着将功能放入派生类中

使用倒置依赖原则,降低耦合性,方便测试.

</类>

<系统>

软件系统启动过程和运行时逻辑应分开

main模块负责构造和设置,应用程序只假设依赖已具备

如果应用程序需要决定对象创建时机,使用工厂

使用DI,IOC进行依赖管理

最佳的系统架构由模块化的关注面领域组成,每个关注面用纯JAVA对象实现,不同领域用最不侵害的切面或类切面工具整合。这样的架构能测试驱动。使用POJO类来无损组合。

设计系统或模块时,使用大概可工作的最简单方案,后不断改进。

</系统>

<跌进>

简单设计的四条规则

模板方法模式移除高层重复

</跌进>

<并发编程>

对象是过程的抽象,线程是调度的抽象

并发会在性能和编写额外代码上产生额外开销,正确的并发是复杂的,并发的缺陷并非总能实现,并发常常需要对设计策略的根本性修改

建议分离并发相关代码和其他代码

严格限制可能被共享数据的访问:synchronized;数据进行复制与只读访问;线程尽量独立而不分享数据

使用类库提供的线程安全群集, 使用executor执行无关任务,尽可能使用非锁定解决方案,注意非现成安全的类。

支持高级并发设计的类:Java.util.concurrent,ReentrantLock,Semaphore, CountDownLatch等。

限定资源,互斥,死锁,活锁,线程饥饿

读者作者模型

警惕同步方法之间的依赖:客户端调用第一个方法前锁定服务端,锁覆盖到最后一个方法;服务端锁定服务端,直到调用完所有方法;执行锁定的中间层,基于服务端来锁定

尽量减少同步区域,尽早考虑关闭问题

测试:将伪失败看作可能的问题,先使非线程代码可用,可插拔的线程代码(单线程与多线程执行时不同的情况;线程代码与实物或测试替身互动;用运行快速;缓慢或有变动的测试替身执行;将测试配置为能运行一定数量的迭代),可调整的线程代码,运行多于处理器数量的线程,在不同平台运行,调整以强迫错误发生(wait,sleep,yield和priority调用的硬编码; 使用Aspect-Oriented Framework、CGLIB或ASM之类的工具来装置代码的自动化策略)

单一权责:分离线程相关代码和线程无关代码的POJO。

并发问题的可能原因:共享数据的多线操作、使用了公共资源池。

TDD三要则

</并发编程>

<逐步改进>

采用测试驱动开发以使得改动不会破坏系统

</逐步改进>

<JUnit内幕>

时序性耦合可以将前者的调用和后者的详情放到一起

</JUnit内幕>

<味道和启发>

尽量做到能单步构建系统,能单个指令执行测试

减少单个文件包含的不同语言

函数或类应该实现名称所描述的明显行为

追索每种边界条件,并编写测试

DRY,尽可能找到并消除重复:检测同一组条件的switch和if链可以用多态替代,类似算法但具体代码行不同的模块可以用方法模式或策略模式。

较高层抽象放基类,较低层抽象放派生类。

基类不依赖于派生类,应对其一无所知。

限制类与模块暴露的接口数量。

删除从不执行的代码

遵循已选约定

不互相依赖的东西不应耦合

把逻辑依赖改为物理依赖,依赖者应该明确询问被依赖者的全部信息。

尽量避免否定性条件

不应遮蔽时序性耦合

封装边界条件,减少四散的+1和-1

函数中的语句应该只在一个抽象层级上

把常量和可配置值放在较高层。

避免传递浏览如a.getB().getC()

使用包中多个类时,用通配符导入

不要继承常量而是使用静态导入

使用enum而不是final static int来实现枚举功能

较大作用范围使用较长名称,如for循环用i即可,不需要rollCount

名称应说明所有信息,如createOrReturn,而不要仅仅说明return

使用测试覆盖率工具

小测试;测试边界条件;

测试应该快速

</味道和启发>

<并发编程>

线程管理代码应该独立出来

线程安全类

通常应选择基于服务端的锁定

用于测试线程代码的工具,如:ConTest

死锁的四个条件:互斥,上锁与等待,无抢先机制,循环等待

</并发编程>

《---代码整洁之道---》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值