代码整洁之道--阅读

简单代码依其重要顺序

1、能通过所有测试

2、没有重复代码

3、体现系统中的全部设计理念

4、包括尽量少的实体,比如类、方法、函数等。

有意义的命名

1、名副其实

2、避免误导

避免留下掩藏代码被一的错误线索,避免使用与本意相悖的词

避免使用某些平台的专有名称(hp,aix,sco,accountList等注意使用)

提防使用不同之处较小的名称(XYZControllerForEfficientHandlingOfStrings 和 XYZControllerForEfficientStorageOfStrings)

o和0的区别使用

3、做有意义的区分

不要使用数字系列命名(a1,a2,.........aN)

可以使用source和destination,函数会更可读

不要在命名中添加废话(NameString->Name,string就是废话)

4、使用读的出来的名称

5、使用可搜索的名称

搜索数字4十分困难,命名后便于查询

6、避免使用编码

避免把类型或作用域编进名称里面

6.1匈牙利语标记法(不用了)

6.2成员前缀(就代码的标志 m_dec)

6.3接口和实现(ShapeFactory->ShapeFactoryImp和CShapeFactory 比对接口名称编码好)

7、避免思维映射

不应当让读者在脑中把你的名称翻译为他们熟知的名称

8、类名

类名和对象名应该是名词或名词短语,如Customer、WikiPage、Account和AddressParser。避免使用Manager、Processor、Data或Info这样的类名。类名不应当是动词。

9、方法名

方法名应当是动词或动词短语。如postPayment、deletePage或save。属性访问器、修改器和断言应该根据其值命名。并依Javabean标准(标准的类JavaBean - _Anke - 博客园),加上get,set和is前缀。

10、别扮可爱,做到言到意到,意到言到

11、每个概念对应一个词

给每个抽象概念选一个词,并且一以贯之。

如:controller、manager、driver可以选择其中一个只用

12、别用双关语

避免将同一单词用于不同目的。同一术语用于不同概念,基本上就是双关语了。如果遵循“一词一意”规则,可能在好多个类里面都会有add方法。只要这些add方法的参数裂变和返回值在意义上等价。

13、使用解决方案领域名称

14、使用源自所涉问题领域的名称

15、添加有意义的语境

16、不要添加没用的语境

函数

1、短小

函数的第一规则是要短小。第二条规则是还要更短小。

2、只做一件事

函数应该做一件事。做好这件事。只做这一件事。

3、每个函数一个抽象层级

自顶向下读代码:向下规则。

4、switch语句

5、使用描述性的名称

6、函数参数

最理想的参数数量是0。

7、无副作用

注释

注释是一种失败,因为注释存在的时间越久,就离其所描述的代码越远,越来越变得全然错误。因为程序员没有一直维护注释

1、注释不能美化糟糕的代码

2、用代码来阐述

3、好注释

法律信息:版权及著作权声明就是必须和有理由在每个源文件开头注释处放置的内容。

提供信息的注释:用注释来提供基本信息。

对意图的解释:注释不仅提供了有关实现的游泳信息,还提供了某个决定后面的意图。

阐释:注释把某些晦涩难明的参数和返回值的意义翻译为某些可读形式。

警示:用于警示其他程序员会出现某种后果的注释。

TODO注释:把TODO形式在源代码中放置要做的工作列表。

放大:注释可以用来放大某种看来不合理之物的重要性。

4、坏注释

1、喃喃自语:如果只是因为你自己觉得应该添加注释,那就是无畏之举。

2、多余注释:代码已经可以解释的没必要注释。

3、误导性注释:程序员会写出不够精确的注释。

4、循环式注释:每个变量都要有注释的规矩全然是愚蠢可笑的。

5、日志式注释:类似git提交日志,现在很少了。

6、废话注释

7、可怕的废话:

8、能用函数或变量时就别用注释。

9、位置标记:

10、括号后面的注释

11、归属与署名

12、注释掉的代码

13、HTML注释

14、非本地信息:代码和注释要就近。

15、信息过多:别再注释中添加有趣的历史性话题或者无关的细节描述。

16、不明显的联系:注释及其描述的代码之间的联系应该显而易见。

17、函数头:选个好的函数名比写函数头注释要好。

18、范例

格式

目的:代码格式关乎沟通。

垂直格式

实体变量应该在类的顶部声明。

相关函数:若某个函数调用了另一个函数,就应该把她们放在一起,而且调用者应该尽可能放在被调用者上面。

概念相关:概念相关的代码应该放在一起。相关性越强,彼此之间的距离就该越短。

横向格式(80个字符)

左边和右边,空格字符加强了分隔效果。

不必完全遵循水平对其,尽量突出重点。

进行缩紧处理。

尽量不要使用空范围。

遵循团队规则

对象和数据结构

数据抽象

数据、对象的反对称性

过程式代码便于在不该动既有数据结构的前提下添加新函数。

面向对象代码便于在不该动既有函数的前提下添加新类。

得墨忒尔律

模块不应了解他所操作对象的内部情形。

1、避免火车失事代码(回调调用函数)

2、混杂:混淆有时会不幸导致混合结构,一半是对象,一半是数据结构。

3、隐藏结构

数据传送对象

错误处理

错误处理很重要,但如果它搞乱了代码逻辑,就是错误的做法。

使用异常而非返回码

先写Try-Catch-Finally语句

异常的妙处之一事,他们在程序中定义了一个范围。

try代码块就像是事物。catch代码块将程序维持在一种持续状态。

使用不可控异常

不使用抛出异常,成本太高,会导致抛出异常链。

给出异常发生的环境说明

抛出的异常需要提供足够的环境说明,以判断错误的来源和处所。

依调用者需要定义异常类

来源分类:来自组建还是其他地方。

类型分类:设备错误、网络错误、编程错误

别返回null值

别传递null值(如非必要,尽量避免)

单元测试

TDD三定律

1、在编写不能通过的单元测试前,不可编写生产代码。

2、只可编写刚好无法通过的单元测试,不能编译也算不通过。

3、只可编写刚好足以通过当前失败调试的生产代码。

保持测试整洁

整洁的测试

要素:可读性

面向特定领域的测试语言

整洁的测试遵循的5条规则

快速(Fast)测试应该够快。

独立(Independent)测试应该相互独立。

可重复性(Repeatable)测试应当可在任何环境中重复通过。

自足验证(Self-Validating)测试应该有布尔值输出。

及时(Timely)测试应及时编写。

类应该短小

单一权责原则

类或模块应该有且只有一条加以修改的理由。

内聚

类应该只有少量实体变量。类中的每个方法都应该操作一个或多个这种变量。

为了修改而组织

对于多数系统,修改将一直持续。

隔离修改。

系统

将系统的构造与使用分开

软件系统应将启始过程和启始过程之后的运行时逻辑分离开,在启始过程中构建应用对象,也会存在互相缠结的依赖关系。

分解main

将构造与使用分开的方法之一是将全部构造过程搬迁到main或被称之为main的模块中,设计系统的其余部分时,假设所有对象都以正确构造和设置。

工厂

依赖注入:有一种强大的机制可以实现分离构造与使用,那就是依赖注入,控制反转在依赖管理中的一种应用手段。

扩容

软件系统与物理系统可以类比。他们的架构都可以递增式的增长,只要我们持续将关注恰当的切分。

跌进

通过跌进设计达到整洁目的

简单设计的四条规则

1、运行所有测试

2、不可重复

3、表达了程序员的意图

4、尽可能减少类和方法的数量

以上规则按其重要程度排列

简单设计规则1:运行所有测试

简单设计规则2~4:重构

测试消除了对清理代码就会破坏代码的恐惧。

在重构过程中,提升内聚性,降低耦合度,切分关注面,模块化系统性关注面,缩小函数和类的尺寸,选用更好的名称等。

不可重复

重复是拥有良好设计系统的大敌。

“小规模复用”可大量降低系统复杂性

表达力

1、可以通过选用好名称来表达。

2、也可以通过保持函数和类尺寸短小来表达。

3、还可以通过保持函数和类尺寸缩小来表达。

4、编写良好的单元测试也具有表达性。

做到有表达力的最重要的方式是尝试。

尽可能少的类和方法

优先度最低的一条。

并发编程

为什么要并发

并发是一种解耦策略。它帮助我们把做什么和何时做分解开。

并发防御原则

1、单一权责原则。

方法/类/组建应当只有一个修改的理由。

并发相关代码有自己的开发、修改和调优生命周期。

开发相关代码有自己要对付的挑战,和非并发相关代码不同,往往更为困难。

即便没有周边应用程序增加的负担,写的不好的并发代码可能的出错方式数量也已经足具挑战性。

建议:分离并大相关代码与其他代码。

2、推论:限制数据作用域

会忘记保护一个或多个临界区--破坏了修改共享数据的代码;

得多花力气保证一切都受到有效保护;

很难找到错误源,也很难判断错误源。

建议:数据封装:严格限制对可能破坏共享的数据的访问。

3、推论:使用数据复本

避免共享数据的好方法之一就是一开始避免共享数据。

4、推论:线程应尽可能的独立

让每个线程在自己的世界中存在,不与其他线程共享数据。

建议:尝试将数据分解到可被独立线程操作的独立子集。

注释

1、不恰当的信息

通常,作者、最后修改时间、SPR数等元数据不该在注释中出现。

注释只应该描述有关代码和设计的技术型信息

2、废弃的注释

过时、无关或不正确的注释就是废弃的注释。发现尽快删除,不要在废弃的基础上修改。

3、冗余注释

注释应该谈及代码自身没提到的东西

4、糟糕的注释

保持简洁,别闲扯,别画蛇添足。

5、注释掉的代码

看到注释掉的代码删除掉。

环境

1、需要多步才能实现的构建

构建系统应该是单步的小操作。不应该从源代码控制系统中一小点一小点签出代码。不应该需要一系列神秘指令或环境以来脚本来构建单个元素。

不应该四处寻找额外的小JAR、XML文件和其他系统所需的杂物。

你应当能够用单个命令签出系统,并用单个指令构建他。

2、需要多步才能做到的测试

你应当能够发出单个指令就可以运行全部测试单元。

能够运行全部测试是如此基础和重要,应该快速、轻易和直截了当的做到。

函数

1、过多参数

函数的参数应该尽量少。没有参数最好,3个以上应坚决避免。

2、输出参数

输出参数违反直觉。

3、标识参数

4、死函数

永不被调用的方法应该丢弃。

一般性问题

1、一个源文件中存在多种语言

当今的现代编程环境允许在单个源文件中存在的多种不同语言,但是理想的源文件包括且只包括一种语言。

2、明显的行为未被实现

遵循“最小惊异原则”,函数或类应该实现其他程序员有理由期待的行为

3、不正确的边界行为

代码应该有正确的行为。问题是我们不能明白正确的行为有多复杂。应该追索没中边界条件,并编写测试。

4、忽视安全

忽视安全相当危险。

5、重复

每次看到重复复代码,都代表遗漏了抽象。

6、在错误的抽象层级上的代码

创建分离较高层级一般性概念与较低层级细节概念的抽象模型。

7、基类依赖于派生类

将概念分解到基类和派生类的最普遍的原因是较高层级基类概念可以不依赖于较低层级派生类概念。

8、信息过多

设计良好的模块有着非常小的借口,让你能事半功倍,不提供许多需要依靠的函数,所以耦合度低。类拥有的实体变量越少越好。

9、死代码

死代码就是不执行的代码。及时删除,防止api更新跟不上报错。

10、垂直分隔

变量和函数应该在靠近被使用的地方定义。本地变量应该正好在其首次被使用的位置上面声明,垂直距离咬断。

11、前后不一致

从一而终。

12、混淆视听

无用的变量,从不调用的函数,没有信息量的注释等,都应该是是被移除的废物。

13、人为耦合

不互相依赖的东西不该耦合。

14、特性依恋

累的放大只应对其所属类中的变量和函数感兴趣,不该垂青其他类中的变量和函数。

15、选择算子参数

16、晦涩的意图

代码要尽可能具有表达力。写明白。

17、位置错误的权责

软件开发者作出的最重要的决定之一就是在哪里放代码。

18、不恰当的静态方法

19、使用解释性变量。

解释性变量多比少好。(key, value)

20、函数名称应该表达其行为

21、理解算法

22、把逻辑依赖改为物理依赖

如果某个模块依赖于另一个模块,依赖就该是物理上的而不是逻辑上的。依赖者模块不应对被依赖者模块有假定。

23、用多态代替if\Else或switch/case

24、遵循标准约定

团队规则,以及上述的规则

25、用命名常量替代魔术数

代码中的原始形态数字,应该用良好的命名的常量来隐藏它。

26、准确

27、结构甚于约定

坚守结构甚于约定的设计决策。

28、封装条件

如果没有if或while语句的上下文,布尔逻辑就很难以理解,应该把解释了条件意图的函数抽离出来。

29、避免否定性条件

否定式要比肯定是难明白一些。

30、函数只该做一件事

31、掩蔽时序耦合

函数的执行顺序不应该被掩蔽。

32、别随意

构建代码需要理由,而且理由应与代码结构相契合。

33、封装边界条件

边界条件难以追踪。把处理边界条件的代码集中到一处,不要散落于代码中。

34、函数应该只在一个抽象层级上

函数中的语句应该在同一抽象层级上,该层级应该是函数名所示操作的下一层。

35、在较高层级放置可配置数据

36、避免传递浏览

名称

1、采用描述性名称

确认名称具有描述性。使用描述性信息覆盖了代码。

2、名称应与抽象层级相符

不要取沟通显示的名称:取反应类或函数抽象层级的名称。

3、尽可能使用标准命名法

名称基于既存约定或用法,就比较易于理解。

4、无歧义的名称

选用不会混淆函数或变量意义的名称。

5、为较大作用范围选用较长名称。

名称的长度应与作用范围的广泛度相关。

6、避免编码

不应在名称中包括类型或作用范围信息。

7、名称应该说明副作用。

测试

1、测试不足

2、使用覆盖率工具

覆盖率工具能汇报你测试策略中的缺口。

3、别略过小测试。

4、被忽略的测试就是对不确定事物的疑问

5、测试边界条件

算法的中间部分正确但边界判断错误的情形很常见。

6、全面测试相近的缺陷

缺陷趋向于扎堆。

7、测试失败的模式有启发性

8、测试覆盖率的模式有启发性

查看被或未被已通过的测试执行的代码,往往能发现失败的测试为何失败的线索。

9、测试应该快速

慢速的测试事不会被运行的测试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值