读书笔记之《The Art of Readable Code》Part 2

如何写好流程控制语句(if-else/switch/while/for)使得代码更可读些?(chap 7)

* 提高条件语句的可读性(if语句, 或者bool型summary变量)

if (length >= 10)    // Good
if (10 <= length)    // Badwhile (bytes_received < bytes_expected)  // Good
while (bytes_expected < bytes_received)  // Badif (NULL == obj) ...  // Not suggested now
if (obj == NULL) ...  // Good

分析:
    left-hand side放我们需要检查的, 经常变化的变量
    right-hand side放常量或者不容易变化的值,这样更容易阅读和理解

* 考虑if/else语句块的顺序
    注意:
    - prefer positive case first instead of negative
    - prefer simple case first to get it out of the way
    - prefer more interesting or conspicuous case first

    e.g.例外
    if not file:
       # log the error ...
    else:
       # ...
* 条件运算符(conditional expression, ?:)

time_str += (hour >= 12) ? "pm" :"am";  // Badif (hour >= 12) {       // Good: more cleartime_str += "pm";
} else {time_str += "am";
}

key idea: 与其减少代码的行数,不如减少别人理解代码所花的时间.

return exponent >= 0 ? mantissa * (1 << exponent) : mantissa / (1 << -exponent);  // Badif (exponent >= 0) {     // Goodreturn mantissa * (1 << exponent);
} else {return mantissa / (1 << -exponent);
}

* 避免do/while循环,避免goto语句
* 让函数提前退出
* 减少折叠的层数
    理由: 层数越深,别人阅读代码就越复杂,每深入/退出一层,别人需要在脑中进行入栈/出栈的操作
    方法: 当你在已有的代码上做修改时,请试图从全新的角度审视这段代码. 往回看, 把之前修改和
    现在需要做的修改当成一个整体考虑.
    技巧:
       1. 及时返回以减少嵌套的层数.
       2. 循环中用continue减少嵌套       

if (results[i] != NULL) {            // Bad
    ....
}
if (results[i] == NULL) continue;    // Good

* 其他能导致代码很难读的流程控制,需要特别注意
     1. 线程/进程/异常处理/信号量
     2. 函数指针/匿名函数/虚函数



如何将长而大的表达式化小?(chap 8)

* 解释型变量(Explaining variables)

// Bad : too long, hard to grasp meaning
if line.split(':')[0].strip() == "root":...
// Good : clear enough, understand by the variable name
username = line.split(':')[0].strip()
if username == "root":...

 * 总结型变量(summary variables)

// Bad : five variables in a line
if (request.user.id == document.owner_id) {// user can edit this document...
}
...
if (request.user.id != document.owner_id) {// document is read-only...
}// Good : easy to catch the meaning by variable name
final boolean user_owns_document = (request.user.id == document.owner_id);
if (user_owns_document) {// user can edit this document...
}
...
if (!user_owns_document) {// document is read-only...
}

* 善用德摩根定律提高条件表达式的可读性 (De morgan's Laws)
1) !(a || b || c) <==> (!a) && (!b) && (!c)
2) !(a && b && c) <==> (!a) || (!b) || (!c)

// Bad
if (!(file_exists && !is_protected)) Error("Sorry, could not read file.");// Good : clear logic
if (!file_exists || is_protected) Error("Sorry, could not read file.");

 * 不要滥用短路逻辑(short-circuit logic)

// Bad : not clear
assert((!(bucket = FindBucket(key))) || !bucket->IsOccupied());// Good : clear enough
bucket = FindBucket(key);
if (bucket != NULL) assert(!bucket->IsOccupied());// except: 可以使用下面这种风格
if (object && object->method()) ...
x = a || b || c;

 * 简化复杂的逻辑 (方法: 反过来思考)

//集合覆盖
struct Range {int begin;int end;// For example, [0,5) overlaps with [3,8)bool OverlapsWith(Range other);
};// Bad: hard to check , with bug
bool Range::OverlapsWith(Range other) {// Check if 'begin' or 'end' falls inside 'other'.return (begin >= other.begin && begin <= other.end) ||(end >= other.begin && end <= other.end);
}// Good: clear logic , easy to check , bug free
bool Range::OverlapsWith(Range other) {if (other.end <= begin) return false;    // They end before we beginif (other.begin >= end) return false;    // They begin after we endreturn true;     // Only possibility left: they overlap
}

 * 将大的表达式分解
方法: 重复的较长的变量或语句重新定义变量表示

* 另一种新颖方法简化表达式(善用C/C++宏,不可滥用宏)

// Bad : too many, hard to check
void AddStats(const Stats& add_from, Stats* add_to) {add_to->set_total_memory(add_from.total_memory() + add_to->total_memory());add_to->set_free_memory(add_from.free_memory() + add_to->free_memory());add_to->set_swap_memory(add_from.swap_memory() + add_to->swap_memory());add_to->set_status_string(add_from.status_string() + add_to->status_string());add_to->set_num_processes(add_from.num_processes() + add_to->num_processes());...
}// Good : easy to check/read
void AddStats(const Stats& add_from, Stats* add_to) {#define ADD_FIELD(field) add_to->set_##field(add_from.field() + add_to->field())ADD_FIELD(total_memory);ADD_FIELD(free_memory);ADD_FIELD(swap_memory);ADD_FIELD(status_string);ADD_FIELD(num_processes);...#undef ADD_FIELD
}

 如何善用变量提高代码的可读性?(chap 9)

* 变量带来的问题
1. 变量越多,越难跟踪它们
2. 变量的作用域越大, 需要跟踪越久
3. 变量的值改变越多, 越难跟踪他的当前值

* 减少变量(与之前的explaining/summary变量不矛盾,这里减少不必要的变量)
* 省去无用的临时变量

// Bad
now = datetime.datetime.now()
root_message.last_view_time = now// Good
root_message.last_view_time = datetime.datetime.now()

 理由:
  1. now的引入并没有分解一个复杂的表达式
  2. datetime.datetime.now()本身已经很清楚
  3. now只用了一次, 并没有解决冗余代码  
key: 这种类型的变量("leftovers"),往往保存一个临时结果,可以通过立即处理临时结果来省掉它们.
 (complete the task as quickly as possible)

// Bad
var remove_one = function (array, value_to_remove) {var index_to_remove = null;for (var i = 0; i < array.length; i += 1) {if (array[i] === value_to_remove) {index_to_remove = i;break;}}if (index_to_remove !== null) {array.splice(index_to_remove, 1);}
};// Good
var remove_one = function (array, value_to_remove) {for (var i = 0; i < array.length; i += 1) {if (array[i] === value_to_remove) {array.splice(i, 1);  // process immediatelyreturn;}}
};

* 省去流程控制变量(Control flow variable)

// Bad : 不必要的变量
boolean done = false;
while (/* condition */ && !done) {...
}
if (...) {done = true;continue;
}// Good : 这类流程控制变量都可以通过if-break/continue来做到
while (/* condition */) {...if (...) {break;}
}

 * 缩短变量的作用域
key: 减少变量的可见范围,越少越好.
原因: 通过减少变量的可见范围,读者阅读代码时需要记住的变量就越少.

* C++中的if-语句的作用域

// Bad
PaymentInfo* info = database.ReadPaymentInfo();
if (info) {cout << "User paid: " << info->amount() << endl;
}
// Many more lines of code below ...// Good : 用户看完之后就不需要关心info了
if (PaymentInfo* info = database.ReadPaymentInfo()) {cout << "User paid: " << info->amount() << endl;
}

 * 在js中使用"私有"变量
* 在js中使用var来定义局部变量

* 将声明下移(移到使用变量的附近)

// Bad
def ViewFilteredReplies(original_id):filtered_replies = []root_message = Messages.objects.get(original_id)all_replies = Messages.objects.select(root_id=original_id)root_message.view_count += 1root_message.last_view_time = datetime.datetime.now()root_message.save()for reply in all_replies:if reply.spam_votes <= MAX_SPAM_VOTES:filtered_replies.append(reply)return filtered_replies// Good : 变量的声明以及使用都聚集在一块了
def ViewFilteredReplies(original_id):root_message = Messages.objects.get(original_id)root_message.view_count += 1root_message.last_view_time = datetime.datetime.now()root_message.save()all_replies = Messages.objects.select(root_id=original_id)filtered_replies = []for reply in all_replies:if reply.spam_votes <= MAX_SPAM_VOTES:filtered_replies.append(reply)return filtered_replies

 * 倾向于一次写入的变量(常量,Write-once variable)
C++中的const, java中的final. 常量不容易带来问题

static const int NUM_THREADS = 10;







 

 




转载于:https://www.cnblogs.com/xianzhon/p/6291322.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/253543.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

chisel快速入门(三)

前一篇见此&#xff1a; chisel快速入门&#xff08;二&#xff09;_沧海一升的博客-CSDN博客简单介绍了chisel&#xff0c;使硬件开发者能快速上手chisel。https://blog.csdn.net/qq_21842097/article/details/121418806 十四、模块的功能创建 制造用于模块构造的功能接口也…

Redis作者摊上事了:多人要求修改Redis主从复制术语master/slave

作者 | ANTIREZ、小智近日&#xff0c;Redis 作者在 GitHub 上发起了一个“用其他词汇代替 Redis 的主从复制术语”的 issue。有人认为 Redis 中的术语 master/slave &#xff08;主人 / 奴隶&#xff09;冒犯到了别人&#xff0c;要求 Redis 作者 ANTIREZ 修改这个术语&#x…

CMOS图像传感器——2021产品选谈

据Yole统计,2020年全球CMOS图像传感器(CIS)市场规模为207亿美元,出货量为70.08亿颗。跟其它半导体器件一样,CIS也因为疫情和生产周期长,以及各种市场因素,而导致采购和供应链紧张。Yole预计2021年将趋于平稳,销售额相比2020年略有增长(3.2%),将达到214亿美元,出货量…

C++匿名对象

匿名对象&#xff1a; string("hello")就是匿名对象&#xff1b; 匿名对象当做参数引用时必须加const; 转载于:https://www.cnblogs.com/achao123456/p/9634810.html

MVC源码分析 - Action查找和过滤器的执行时机

接着上一篇, 在创建好Controller之后, 有一个 this.ExecuteCore()方法, 这部分是执行的. 那么里面具体做了些什么呢? //ControllerBaseprotected virtual void Execute(RequestContext requestContext) {if (requestContext null){throw new ArgumentNullException("req…

CCIE-MPLS基础篇-实验手册

又一部前期JUSTECH&#xff08;南京捷式泰&#xff09;工程师职业发展系列丛书完整拷贝。 MPLS&#xff08;Multi-Protocol Label Switching&#xff09; 目录 1&#xff1a;MPLS 基础实验.... 3 1.1实验拓扑... 3 1.2实验需求&#xff1a;... 3 1.3实验步骤... 3 1.4校验…

RCA/BNC接口

RCA接口&#xff08;消费类市场&#xff09; RCA 是Radio Corporation of American的缩写词&#xff0c;因为RCA接头由这家公司发明的。RCA俗称莲花插座&#xff0c;又叫AV端子&#xff0c;也称AV 接口&#xff0c;几乎所有的电视机、影碟机类产品都有这个接口。它并不是专门为…

2021手机CIS技术趋势总结

手机摄像头CIS&#xff08;CMOS图像传感器&#xff09;自从突破1亿像素以后&#xff0c;再谈像素数量增大&#xff0c;似乎已经很难让市场产生激烈反应了。这两年电子工程专辑对于手机摄像头CIS&#xff0c;以及更多领域不同类型的图像/视觉传感器&#xff08;如ToF、基于事件的…

关于Unity中NGUI的背包实现之Scrollview(基于Camera)

基于UIPanel的scrollview实现方式在移动设备上的性能不如基于camera的方式。因为UIPanel的scrollview实现方式要渲染很多的道具图&#xff0c;性能自然就降低了。如果是用第二个摄像机camera的方式&#xff0c;物体并没有动&#xff0c;只是拖动第二个摄像机摄像机&#xff0c;…

YUV422/420 format

(在本文中&#xff0c;U 一词相当于 Cb&#xff0c;V 一词相当于 Cr。) YUV422 format as shown below 4:2:2 表示 2:1 的水平取样&#xff0c;没有垂直下采样 YUV420 format as shown below4:2:0 表示 2:1 的水平取样&#xff0c;2:1 的垂直下采样. YUV4:2:0并不是说只有U&…

数字后端——ECO

目录 一、概述 二、ECO分类 1、按时间节点 1&#xff09;流片前的ECO 2&#xff09;流片过程的ECO 3&#xff09;流片后的ECO 2、按网表是否改变 1&#xff09;功能ECO 2&#xff09;时序ECO 三、ECO处理内容 1、设计规则违例 1&#xff09;提升标准单元驱动力 2…

电视百科常识 九大视频接口全接触

1 射频 天线和模拟闭路连接电视机就是采用射频&#xff08;RF&#xff09;接口。作为最常见的视频连接方式&#xff0c;它可同时传输模拟视频以及音频信号。RF接口传输的是视频和音频混合编码后的信号&#xff0c;显示设备的电路将混合编码信号进行一系列分离、解码在输出成像。…

数字后端——物理单元介绍

物理单元&#xff08; physical cell&#xff09;指没有逻辑功能但是具有物理实现功能的标准单元&#xff0c; 用于抑制芯片生产过程中的各类物理效应&#xff0c; 保证芯片生产后能够正常工作 。硬核位置确 定后&#xff0c;需要插入物理单元消除影响芯片工作的物 效应&#x…

深入Java内存模型

你可以在网上找到一大堆资料让你了解JMM是什么东西&#xff0c;但大多在你看完后仍然会有很多疑问。happen-before是怎么工作的呢&#xff1f;用volatile会导致缓存的丢弃吗&#xff1f;为什么我们从一开始就需要内存模型&#xff1f; 通过这篇文章&#xff0c;读者可以学习到足…

Matlab 使用GPU加速 转载

在matlab中使用GPU加速&#xff0c;来加速矩阵运算。 首先如前面所说&#xff0c;并不是所有GPU都能在maltab中进行加速的&#xff0c;貌似只有NVDIA的显卡可以吧。 硬件&#xff1a;GeForce GTX 980 软件&#xff1a;Matlab 2015a &#xff08;Matlab 2012以后的版本才带有GP…

数字后端——可制造性设计

随着集成电路制造工艺技术的迅速发展&#xff0c;集成电路集成度迅速攀升&#xff0c;制造流程及工艺步骤日趋复杂&#xff0c;工艺尺寸也在不断缩小。集成电路可制造性设计&#xff08;Design For Manufacturability,DFM&#xff09; 以直接提升集成电路芯片的良品率及降低芯片…

Cloudstack安装(二)

Cloudstack安装 官方文档参考&#xff1a; http://docs.cloudstack.apache.org/projects/cloudstack-installation/en/4.9/qig.html#environment Cloudstack主要分Management和Agent两部分。 系统版本&#xff1a;CentOS 6.8 Management&#xff1a; cpu1&#xff0c;ram 2048M…

Pycharm 输出中文或打印中文乱码现象的解决办法

转载地址&#xff1a;https://www.cnblogs.com/Bro-Young/p/5920884.html 1. 确保文件开头加上以下代码&#xff1a; 1 # -*- coding:utf-8 -*- 还可以加上 1 import sys 2 reload(sys) 3 sys.setdefaultencoding(utf-8) 确保以下。 如果还是没有解决中文乱码&#xff0c;那么进…

计算机系统结构——概述

计算机的实现包括两个方面&#xff1a;组成和硬件。组成一词包含了计算机设计的高阶内容&#xff0c;例如存储器系统&#xff0c;存储器互连&#xff0c;设计内部处理器 CPU &#xff08;中央处理器——算术、逻辑、分支和数据传送功能都在内部实现&#xff09;。有时也用微体系…

全景图像拼接——基本流程

图像拼接技术是数字图像处理技术一个重要的研究方向,它即是将两幅或多幅相互有部分重叠的场景照片拼接成具有超宽视角、与原始图像接近且失真小、没有明显缝合线的高分辨率图像。可以很好地解决广角镜、鱼眼镜头等全景图获取设备的不足。如下图: 图像拼接产生的图像不…