伴着2018年收官的鹅毛大雪,依旧在路上欢(Ku)快(B)驰骋,IT菜鸟分享今天的收获--《代码整洁之道》
1有意义的命名:
- 名副其实(见名知意),add/insert/append
- 避免使用与本意相悖的词、专有名词(hp,aix,sco等)。
例子:别用accountList来指称一组账号,除非它真是List类型。可用accountGroup或bunchOfAccounts,甚至直接用accounts都会好一些。
3) 提防使用不同之处较小的名称。如:XYZControllerForAStrings和XYZControllerForBStrings
4) 做有意义的区分: sourceData和destinationData/targetData
5) 使用读得出来的名称:whs==woHenShuai
6) 使用可搜索的名称: 名称长短应与其作用域大小相对应。
7) 类名和对象应该是名词或名词短语,方法名应是动词或动词短语。
8) 每个概念对应一个词,别用双关语,使用解决方案领域名称,使用源自所涉及问题领域的名称,添加有意义的语境(state)
2函数
短小更短小,只做一件事(单一职责SRP、开放闭合OCP), 见名知意(setAndCheckIfExists), 使用异常替代返回错误码,抽离try/catch代码块。
3注释:注释简单明了刚刚好,不多也不少。
4格式:缩进、水平对齐。一个开发团队尽量保持一种格式规则。
5对象和数据结构
对象曝露(pu lu)行为--操作数据的函数,隐藏数据。便于添加新对象类型而无需修改既有行为,同时也难以在既有对象中添加新行为;数据结构曝露其数据,没有明显行为。便于向既有数据结构添加新行为,同时也难以向既有函数添加新数据结构。
DTO(Data Transfer Objects-数据传送对象),是一个只有公共变量、没有函数的类。常用于数据库通信、解析套接字传递的消息之类场景中。
6 错误处理:
使用异常而非返回码,先写try-catch-finally语句可以用TDD(测试驱动方法)构建其他代码逻辑。
使用不可控异常(可控异常违反了开放/闭合原则),避免别返回null值和别传递null值。这一块可以查看Java的可控异常(checked exception) 和 unchecked exception
7 边界:边界上的代码需要清晰的分割和定义了期望的测试。应该避免我们的代码过多的了解第三方代码中的特定信息。
8 单元测试:测试嗲吗和生产代码一样重要。
TDD三定律:
- 在编写不能通过的单元测试前,不可编写生产代码。
- 只可编写刚好无法通过的单元测试,不能编译也算不通过
- 只可编写刚好足以通过当前失败测试的生产嗲吗。
每个测试都清晰地分为三个环节:构造-操作-检验(Build-Operate-Check)。一是环节构造测试数据,二是操作测试数据,三个是不跟检验操作是否得到期望的结果。
9 类
类的名称应当描述其权责。实际上,命名正是帮助判断类的长度的第一个手段。自顶向下原则:如果有公共静态常量,应该先出现,然后是私有静态变量,以及私有实体变量。很少会有公共变量,公共函数应该跟在变量列表后面。
单一职责原则:类或模块应有且有只有一条加以修改的理由。类只应有一个权责—只有一条修改的理由。系统应该由许多短小的类而不是少量巨大的类组成。每个小类封装一个权责,只有一个修改的原因,并与少数其他类一起协同达成期望的系统行为。
内聚:类应该只有少量实体变量。类中的每个方法都应操作一个或多个这种变量。通常而言,方法操作的变量越多,就越粘聚到类上。
依赖倒置原则(DIP-Dependency Inversion Principle):类应该依赖于抽象(接口或抽象类)而不是依赖于具体细节。
- 系统---这部分可以关注一下springboot
将系统的构造和使用分开
软件系统应将起始过程和起始过程后之后的运行时逻辑分离开,在起始过程中构建应用对象,也会存在相互缠结的依赖关系。
- 分解main:将全部构造过程搬迁到main或被称之为main的模块中,设计系统的其余部分时,假设所有对象都已正确构造和设置。
- 工厂:可以使用抽象工厂模式让应用自行控制何时创建应用对象,但构造的细节却隔离于应用程序代码之外。
- 依赖注入(DI – Dependency Injection/IOC-Inversion of Control):控制反转将第二权责从对象中拿出来,转移到另一个专注于此的对象中,从而遵循了单一职责原则。在依赖管理中,对象不应负责实体化对自身的依赖。反之,它应当将这份权责移交给其他“有权力”的机制,从而实现控制的反转。
真正的依赖注入还要更进一步。类并不直接分解其依赖,而是完全被动的。它提供可用于注入依赖的赋值器方法或构造器参数(或二者皆有)。在构造过程中,DI容器实体化需要的对象(通常按需创建),并使用构造器参数或赋值器方法将依赖链接到一起。至于哪个依赖对象真正得到使用,是通过配置文件或在一个有特殊目的构造模块中编程决定。
- 并发编程:
并发防御原则:
- 单一权责原则SRP
- 限制数据作用域:
- 使用数据复本:
- 线程应尽可能地独立
Java相关:
字节码分析:第5行的是原子操作,Java内存模型中32位值的赋值操作是不可中断的。
getNextId()方法中第09行的的++value 和 value ++ 的区别(初值为42)如下:
前递增和后递增并不是原子的,什么地方有共享对象/值,哪些代码会导致并发读/写问题,如何防止这种并发问题发生。
非锁定方案:CAS(比较并交换)AtomicBoolean/AtomicInteger/AtomicReference
非线程安全类:数据库连接、Java.util中的容器、Servlet
方法之间的依赖可能破坏并发代码: