java清洁之道_断舍离 ——《代码整洁之道》读书笔记

注1:只看了书的前十章

注2:原书使用的语言为 Java,我改成了 JavaScript

第一章 为什么要整洁代码

1、代码永不消失

代码就是衔接人脑理解需求的含糊性和机器指令的精确性的桥梁。哪怕未来会有对现在高级编程语言的再一次抽象——但这个抽象规范自身仍旧是代码。

所以既然代码会一直存在下去,且自己都干了程序员这一行了,就好好的对待它吧。

2、读远比写多

当你录下你平时的编码的过程,回放时,你会发现读代码所花的时间远比写的多,甚至超过 10:1。所以整洁的代码会增加可读性。

3、对抗拖延症——稍后等于永不

糟糕的代码会导致项目的难以维护。而当你正在写糟糕的代码的时候,心里却圣洁的想:“有朝一日再回来整理”。但现实是残酷的,正如勒布朗(LeBlanc)法则:稍后等于永不(Later equals never)

4、精益求精

写代码就跟写文章一样,先自由发挥,再细节打磨。追求完美。

大师级程序员把系统当作故事来讲,而不是当作程序来写。

第二章 命名

1、名副其实

(×)图表:mapTable

(√)图表:chart

2、避免误导

(1)不要用专有名词

const var = 0;

(2)避免细微之处有不同

XYZControllerForEfficientKeepingOfStrings

XYZControllerForEfficientHoldingOfStrings

7e61c4c8bcd83f19045e09517fa2d49a.png

(3)避免废话

如果是一个数组类型,就没必要叫 ProductArray

如果返回值就是数据,就没必要叫 ProductData

(4)便于搜索

(×)

if ( team.length === 3 )

(√)

const MAX_NUM_OF_TEAM = 3 ;

……

if ( team.length === MAX_NUM_OF_TEAM )

MAX_NUM_OF_TEAM 比 3 好检索

早期流行一种匈牙利语标记法:

如 arru8NumberList 的前缀 "arru8" 表示变量是一个无符号8位整型数组;

3、避免思维映射

类名、参数名用名词:

member

leader

方法名用动词:

getTeam

根据 Javabean 的标准,方法名可以加上 get set is 前缀

4、每个概念用一个词

get fetch 选一个,不要混着用

5、添加有意义的语境

如果你要记录 member 的详细住址,会设置了如下几个变量:

(×)

addrStreet addrHouseNumber addrCity addrState

(√)

new Address {

street,

houseNumber,

city,

state

}

第三章 函数

尽量短小

函数的缩进层级尽量控制在 1-3 层

例如要依次读取 A、B、C 三个文件:

(×)

function test() {

readFileA(function (err, data) {

// todo

readFileB(function (err, data) {

// todo

readFileC(function (err, data) {

// todo

//……

});

});

});

}

(√)

function test() {

try {

let re_a = await readFileA();

let re_b = await readFileB();

let re_c = await readFileC();

} catch (err) {

}

}

只做一件事

判断标准:是否可以再拆出一个函数

(×)

function test() {

//......

Session.save();

//......

}

(√)

function test() {

//......

saveSession();

//......

}

function saveSession(){

Session.save();

}

每个函数即是一个抽象层,如上面的例子,Session 跟 test 函数不是一个抽象层,所以抽离出来。

函数名代替注释

长且具有描述性的名字比描述性的长注释好

(×)

//取出所有满员的团

getSpecialGroup()

(√)

getGroupOfFullMember()

参数顺序太多记不住怎么办?

方法一:体现在函数名上

(×)assertEqual(expected, actual)

(√)assertExpectedEqualsActual(expected, actual)

现代 IDE 已经具有鼠标移在调用函数名上可以浮窗显示形参列表了。

方法二:让参数可以打乱传

function getMember({isNew = false,isActivate = false}){

console.log("isNew:"+isNew,", isActivate:"+isActivate)

}

getMember({isNew:true,isActivate:false}) //isNew:true , isActivate:false

//不会因为传参的顺序记错而出错

getMember({isActivate:false,isNew:true}) //isNew:true , isActivate:false

//也支持默认参数

getMember({}) //isNew:false , isActivate:false

这里用到了 ES6 的新特性:解构赋值

let obj = {a:1,b:2};

let {a,b} = obj;// a = 1, b = 2

方法三:减少参数

最理想的参数数量 < 3,最好不用输入参数。

A、布尔值参数 一拆二

(×)getMember(isNew)

(√) getNewMember() getOldMember()

这里的前提是获取新、老会员的方法体代码不一样,不然还是共用在一个方法通过布尔值比较好。

B、二元函数变一元

function addSuffix(origin,suffix){

return origin+"+"+suffix;

}

console.log(addSuffix("hello","world"));

console.log("hello".addSuffix("world"));

异常代替返回错误码

抽离 try / catch 块

避免重复

否则得修改多处地方

结构化编程

(1)每个函数都应该有一个入口和一个出口

关于(只能有一个 return 语句,在结尾处 / 尽快 return,即有多个 return 语句)的争论:

《结构化编程》的建议:

function test(is) {

let result;

if(is){

result = true;

}else{

result = false;

}

return result;

}

《重构》的建议:

function test(is) {

if(is){

return true;

}else{

return false;

}

}

(2)循环中尽量避免有 break 或 continue ,而且决不能出现 goto 语句。

第四章 注释

尽量用代码表达,而不是用注释

就像上文提到的用详尽的函数名代替注释,或者:

//代码过于追求简洁而导致这里要加详细的注释

if( smodule.getDependSubsystems().contains(subSysMod.getSubSytem()) )

//还不如这里做拆分,取易懂的变量名方便理解,就可以不用加注释或者少加

ArrayList moduleDependees = smodule.getDependSubsystems();

String ourSubSystem = subSysMod.getSubSystem();

if( moduleDependees.contains(ourSubSystem) )

原因是:注释存在的越久,随着代码的不断迭代,会离代码的距离越来越远,这个时候好的做法是同时维护代码 + 注释,而注释越多越复杂,维护的成本自然就上升了。

注释不能美化糟糕的代码,尽量去优化代码

好注释

(1)法律信息、许可证、版权、著作权、外链文档的 url

(2)对意图的解释

(3)警示

(4)TODO 注释

坏注释

(1)只有自己看得懂

(2)多余的注释

a、不能提供比代码更多的信息

b、读的时间比直接看代码还久

(3)歧义性

(4)循规蹈矩的注释

例如用第三方工具生成的注释,很多都是累赘的废话

(5)日志式、署名式注释

(×)

// write by colin

// fix #201 bug

(√)

交给 git 记录

(6)慎用位置标记

// **********************

及时清理不需要的注释

(1)越堆越多

(2)导致以后因看不懂而不敢删

第五章 格式

向报纸学习

(1)从上往下读,从左往右读

(2)源文件在最顶端给出高层次的概念和算法,细节往下逐次展开,直到最底层的函数和细节。

垂直格式

(1)善用空白行:人会更容易将目光聚焦到空白行之后的那一行

(2)函数:调用者放在被调用者上面

横向格式

(1)缩进

(2)IDE 中不会出现横向滚动条

第六章 对象和数据结构

数据结构和对象的区别

数据结构暴露其数据,没有提供有意义的函数。

对象把数据隐藏在抽象之后,暴露操作数据的函数。

//数据结构

function Point(x,y){

this.x = x;

this.y = y;

}

//对象

class Point {

constructor(x, y) {

this.x = x;

this.y = y;

}

getX() {

return this.x;

}

setX(x) {

this.x = x;

}

}

第七章 错误处理

使用异常而非返回码

(上文有述)

定义异常类

如引用了一个第三方库,它会 throw 自己的几种异常值,但我们可以定义一个异常类,封装好它的几种异常值为一种专门异常,然后再二次 throw 交给上层捕获。

别返回 null 值

null 值会造成很多不必要的 if 判断

function getCurrentMember(){

let a = DB.getCurrentMember();

if (a){

return a;

}else{

return null;

}

}

方法一:抛异常

function getCurrentMember(){

let a = DB.getCurrentMember();

if (a){

return a;

}else{

throw Error("no member")

}

}

方法二:返回特例值

function getCurrentMember(){

let a = DB.getCurrentMember();

if (a){

return a;

}else{

return {};

//return {name : "default"};

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值