CleanCode学习笔记(1)

本文中的观点都是摘自《Clean Code》
书中有对观点更加详细的解释和说明

命名

有意义的命名

  • 变量、函数、类的命名应当表明意义、作用以及使用方式

命名避免误导

  • 不要将account的组合命名为accountList,除非它真的是List
  • 避免使用区别非常小的命名,比如XYZControllerForEfficientHandlingOfStringsXYZControllerForEfficientStorageOfStrings
  • 同样的概念使用相同命名,命名前后不一致也是问题

有意义的区分

  • 不要对不同的东西使用相同的命名,即便是用数字下标区分也不合适
  • 噪音词是无意义的区分。例如,命名为ProductInfoProduceData基本没区别,DateInfo就是噪音词
  • 噪音词是冗余的。例如,variable永远不应该成为一个变量的名称, table也永远不应该成为一个表的名称
  • 能使阅读代码的人区分出差别的命名才是有意义的命名

读得出的命名

  • 编程本身也是一个社会活动,如果命名无法读出来,那就无法进行讨论

可搜索的命名

  • 单字母命名和数字常量最大的问题就是没法在一篇文字中搜索出来
  • 单字母命名仅可被用于本地变量
  • 命名的长短与其作用域的大小对应
  • 如果一个变量或常量在多个地方使用,则应赋予其可搜索的命名

避免使用前缀

  • 不要使用前缀来标记成员变量
  • 类和函数都应足够小,以此来避免使用前缀

类名

  • 类名和对象名通常是名词或者名词短语,但是需要避免使用类似于DataInfo这样的词汇

方法名

  • 方法名通常是动词或者动词短语

其他

  • 每一个概念对应一个词,例如,使用getfetch来给多个类中同样的方法命名
  • 不要使用双关语,避免将同一个单词用于不同的目的,即遵循一词一义的原则
  • 添加有意义的语境,不要添加不必要的语境

函数

短小

  • 函数最重要的原则就是短小
  • 每个函数封顶20行是比较好的

代码块和缩进

  • if-else语句和while语句中的代码块都应只有一行,这行大多是函数调用
  • 这样不仅可以保持函数短小,同时代码块中调用的具有说明性命名的函数也增加了文档价值
  • 函数的缩进层级不能超过一层或两层,易于阅读和理解

只做一件事

  • FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL. THEY SHOULD DO IT ONLY.
  • 如果函数只是做了该函数名下同一抽象层级的几个步骤,它仍是只做了一件事情
  • 判断函数是否只做了一件事情的另一方法是: 判断是否能再拆出来一个函数
  • 只做一件事的函数无法被拆分为多个区段

每个函数一个抽象层级

  • 为了确保函数只做一件事,我们需要确保函数中的语句都在一个抽象层级
  • 一个函数中混合不同抽象层级容易产生困惑
自顶向下阅读代码
  • 代码需要拥有自顶向下的顺序,这样做,在阅读代码时,就可根据抽象层级向下阅读

Switch语句

  • Switch语句不可能只做一件事,不过仍可以确保每个Case都在较低的抽象层级
  • 可以将Switch语句隐藏在抽象工厂方法的下面,不被任何使用的人看到

使用描述性名称

  • You know you are working on clean code when each routine turns out to be pretty much what you expected.
  • 函数越小,做的事情越集中,那么为函数取一个具有描述性的名字就越容易
  • 不要担心使用长名字。使用长的具有描述性的名字比使用短的费解的名字更好
  • 不要害怕花费时间去起名字,好的名字也更有利代码重构

函数参数

  • 最理想的函数参数个数是0个,其次是1个,再次是2个,避免使用3个参数,无论如何都不要使用3个以上的参数
  • 确保函数执行结果是以返回值的形式出现,而不是更新到输入参数中
  • 不要向函数中传递布尔值的参数,那是在表明你的函数不止做了一件事
  • 如果可以的话,尽量减少函数参数的个数
  • 如果函数需要大量的参数,是否考虑将其中一些参数封装为类

无副作用

  • 避免函数承诺了只做一件事,但它却做了其他的事情
  • 一定要避免将输入参数用作函数输出

分割指令和询问

  • 函数应该执行操作或者进行判断,但是不应该都做

抛出异常比返回错误码更好

  • 使用异常代替错误码,错误处理就可以从代码主流程分离,代码结构也会变得简单
  • 抽离try-except代码块
  • 错误处理也是一件事, 错误处理函数不应该做其他事。即try是该函数的第一行, except/finally代码块后也不应有任何内容

不要重复

  • 重复会使代码变得臃肿,而且,增加了修改代码出错的可能

结构化编程

  • 避免使用goto
  • 保持函数短小

如何写出这样的函数

  • 没有人一开始就可以写出满足以上描述的代码
  • 写代码和写论文一样,需要反复打磨,同时在打磨的时候遵守上面提到的规则

注释

  • 注释的主要作用是弥补我们使用代码表达意图时的失败。注意,注释总是在表达失败
  • 任何你想写注释时都应该考虑,是否可以使用更合适的代码来表明意图
  • 不推荐使用注释的一个原因是,注释会撒谎。注释存在的越久,就和描述的代码越远,这也是因为程序员不能坚持维护注释
  • 不准确的注释比没有注释更恐怖,只有代码才可以忠诚地告诉你它做了什么

注释不能美化代码

  • 大部分情况下写注释的动机是,我们想对写的很差的代码进行描述
  • 清晰,表达力强,注释少的代码远胜于混乱且复杂,注释多的代码
  • 比起花费时间对混乱代码进行描述,更好的做法是花费时间去结局混乱

用代码来描述

  • 用代码来解释意图,很多时候创建一个与注释描述的是同一事务的函数即可

好注释

  • 最好的注释就是不写注释
  • 版权等法律信息可作为注释
  • TODO信息

坏注释

  • 大多数的注释属于坏注释

对象和数据结构

  • 面向过程,便于在不改动数据结构的前提下增加函数。面向对象,便于在不改动已有函数的前提下增加数据结构
  • 面向过程难以添加新数据结构,因为必须改动所有函数。面向对象难以改动函数,因为必须改动所有数据结构
  • 数据结构应该最好只拥有简单的共有变量,没有函数
  • 对象拥有私有变量和公共函数

Demeter定律

  • 模块不应了解它操作对象的内部结构。对象隐藏数据结构,暴露实现。对象不应通过存取器暴露它的内部结构
  • 更准确来说,类C的方法f只能调用以下对象的函数:
    • C
    • f创建的对象
    • 作为参数传递给f的对象
    • C的实体变量持有的对象
  • C的方法f不能调用任何由函数返回的对象的方法
  • 以下代码就违反了Demeter定律: 它调用了函数getOptions返回对象的getScratchDir方法, 接着又调用了函数getScratchDir返回对象的getAbsolutePath方法
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath()

数据传递对象

  • 典型的数据结构是一个有公有变量、没有函数的类,它对于数据库和网络访问非常有用

错误处理

  • 如果错误处理搞乱了代码逻辑,那么它就是错误的做法

使用异常而非返回码

  • 使用返回码最大的问题是搞乱了调用者代码,而且容易遗忘错误处理

使用不可控异常

  • 可控异常可能会产生一个从软件最底端贯穿到最高端的异常链

不要返回null

  • 任何时候都不应该返回null

不要传递null

  • 即,不要将null值作为参数传递给函数
  • 返回null很不好,但是传递null就更离谱了
  • 无论任何时候,可能的话都不要传递null

边界

我们不可避免需要第三方软件和程序包,所以我们需要将外来代码整洁地整合到我们自己的代码中
边界代码需要清晰地定义分界和期望测试用例
可以针对第三方包进行封装或者写适配器进行转换, 以便我们获取需要的功能

第三方代码

  • 第三方包和程序框架的提供者为追求普适性,会尽可能让代码在多个环境中工作。但这样会可能导致代码在系统边界出现问题
  • 第三方包可能会缺少很多对你的代码有用的限制,即提供了过多你本来不需要的功能
  • 这时我们可以对第三方包进行封装,隐藏实现细节,并且屏蔽多余的功能

学习和浏览边界

  • 在使用第三方包之前,我们可能需要写一些’学习性测试’来帮助我们理解需要的功能

学习性测试很重要

  • 学习性测试没有任何成本,无论如何我们都要学习这个api,而学习性测试是获取这些知识的简单方法

使用尚不存在的代码

  • 这是另一种类型的边界——分离已知和未知
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值