Comments (3)
第二部分:简化循环和逻辑
原则五:把控制流变得易读
关键**就是,把条件、循环以及其他对控制流的改变做得越“自然”越好,运用一种方式使读者不用停下来重读你的代码。
条件语句中参数的顺序
指导原则
比较的左侧 | 比较的右侧 |
---|---|
"被询问的”表达式,它的值更倾向于不断变化 | 用来作比较的值,它的值更倾向于常量 |
举例,下面的例子中第一段比第二段更易读,
if (length >= 10)
// 而不是
if (10 <= length)
if/else语句块的顺序,有些情况下有理由相信一种顺序比另一种顺序更好:
- 优先处理正逻辑,而不是负逻辑;即用if(debug)而不是if(!debug)
- 优先处理简单情况;
- 优先处理有趣的或者可疑的情况,即先处理边界情况
三目运算符最好只在最简单的情况下使用,相对于追求最小化代码行数,一个更好的度量方法是最小化人们理解它所需的时间。
避免do/while循环,因为do/while的奇怪之处是一个代码是否会执行是由其后一个条件决定。
从函数中提前返回,用保护语句来实现更自然。
大多数时候都应该避免使用goto。
嵌套很深的代码是难以理解的。每个嵌套层次都在读者的”思维栈“上有增加了一个条件。举例:
if (user_result == SUCCESS) {
if (permission_result != SUCCESS) {
reply.WriteErrors("error reading permission");
reply.Done();
return;
}
reply.WriteErrors("");
} else {
reply.WriteErrors(user_result);
}
reply.Done();
// 其中permission相关的代码是很可能后来加上去的,尽管想加入的代码很整洁,也很明确
// 但是,以后当其他人遇到这段代码时,所有的上下文早已经不在了,所以在你第一次读这段代码的时候不得不一下子全盘接受它
// 通过提前返回来减少嵌套,优化后
if (user_result != SUCCESS) {
reply.WriteErrors(user_result);
reply.Done();
return;
}
if (permission != SUCCESS) {
reply.WriteErrors(permission_result);
reply.Done();
return;
}
reply.WriteErrors("");
reply.Done();
return;
减少循环内的嵌套,举例:
for (int i = 0; i < result.size(); i++ {
if (result[i] != NULL) {
non_null_count++
if (result[i]->name != "") {
cout << "Considering candidate..." << endl;
}
}
}
// 在循环中提早返回的技术是continue,优化后
for (int i = 0; i < result.size(); i++ {
if (result[i] == NULL) continue;
non_null_count++;
if (result[i].name == "") continue;
cout << "Considering candidate..." << endl;
}
与if(...)return;在函数中所扮演的保护语句一样,这些if(...)continue;语句是循环中的保护语句。
原则六:拆分超长的表达式
关键**,把你的超长表达式拆分成更容易理解的小块。
用作解释的变量
拆分表达式最简单的方法就是引入一个额外的变量,让它来表示一个小一点的子表达式。举例:
if line.split(':')[0].strip() == "root":
...
// 优化后
username = line.split(':')[0].strip()
if username == "root":
...
总结变量,即使一个表达式不需要解释,把它装入一个新变量中仍然有用,它的目的只有一个,就是用一个短很多的名字来代替一大块代码,这个名字会更容易管理和思考。举例:
if (request.user_id == document.owner_id) {
// user can edit this document...
}
if (request.user_id != document.owner_id) {
// document is read-only...
}
// 用总结变量优化后
final boolean user_own_document = (request.user_id == documnet.owner_id)
if (user_own_document) {
// user can edit this document
}
if (!user_own_document) {
// document is read-only
}
使用德摩根定理,关于布尔表达式的两种等价写法:
1)not (a or b or c) <=> (not a) and (not b) and (not c)
2)not (a and b and c) <=> (not a) or (not b) or (not c)
即”分别取反,转换与/或“。
需要注意的是,很多编程语言中,布尔操作会做短路计算,即x = a | b | c|
是用来找出a,b,c中第一个为“真”的值。
与复杂的逻辑做战斗,如果一段逻辑很复杂,可以适时停下来思考找到更优雅的方式,一种技术就是看看能否从”反方向“找到问题。
原则七:变量与可读性
关于变量和可读性,我们需要讨论三个问题:
1)变量越多,就越难以全部跟踪它们的动向;
2)变量的作用域越大,就越需要跟踪它们的动向越久;
3)变量改动得越频繁,就越难以跟踪它的当前值。
要避免没有价值的变量,举例:
now = datetime.datetime.now()
root_message.last_view_time = now
// 下面的更简洁
root_message.last_view_time = datetime.datetime.now()
减少中间结果,对于只是用来保存临时的结果,我们有必要通过得到它后立即处理它而消除。举例:
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);
}
}
// 优化后
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);
break;
}
}
}
缩小变量的作用域,其关键**就是让你的变量对尽量少的代码可见。有时候可以通过”闭包“来实现”私有“变量,举例:
submitted = false
var submit_form = function(form_name) {
if (submitted) {
return; // don't double-submit the form
}
...
submitted = true
};
// 优化后
var submit_form = (function () {
var submitted = false;
return function ( form_name) {
if (submitted) {
return;
}
...
submitted = true;
};
}());
关于变量和可续性的总结就是**减少变量**,**减小每个变量的作用域**,**只写一次的变量更好**。
from yusubond.github.io.
第三部分:重新组织你的代码
原则八:抽取不相关的子问题
所谓工程学就是把大问题拆解成小问题再把这些问题的解决方案放回在一起。
积极地发现并抽取出不相关的子逻辑,我们是指:
1)看到某个函数或代码块,问问自己:这段代码高层次的目标是什么?
2)对于每一行代码,问一下:它是直接为高层次目标而工作吗?这行代码高层次的目标是什么?
3)如果足够的行数在解决不相关的子问题,抽取代码到独立的函数中。
自顶向下或自底向上式编程?
自顶向下编程是一种风格,先设计高层次模块和函数,然后根据支持它们的需要来实现低层次的函数。
自底向上编程尝试首先预料和解决所有的子问题,然后用这些代码段来建立更高层次的组件。
创建更加通用的代码,简化已有的接口,永远不要安于使用不理解的接口。
关键**,就是把一般代码和项目专有的代码分开。
原则九:一次只做一件事
关键**,应该把代码组织得一次只做一件事。
同时在做几件事的代码很难理解。一个代码块可能初始化对象,清楚数据,解析输入,然后应用业务逻辑,所有这些都同时进行。如果所有的代码都纠缠在一起,对于每个”任务“都很难靠其自身来帮你理解它从哪里开始,到哪里结束。
关于一次只做一件事的具体建议和流程:
1)列出代码所做的所有”任务“。这里的”任务“没有很严格的定义——它可以小得如”确保这个对象有效“,或者含糊得如”遍历树中所有的结点”。
2)尽量把这件任务拆分到不同的函数中,或者至少是代码中不同的段落。
任务可以很小,举例:
var vote_value = function (vote) {
if (vote === "up") {
return +1;
}
if (vote === "down") {
return -1;
}
return 0;
}
原则十:把想法变成代码
如果你不能把一件事解释给你祖母听的话说明你还没有真正理解它。——爱因斯坦
把一个想法用“自然语言”解释是个很有价值的能力,这需要把一个想法精炼成最重要的概念,这样做不仅可以帮助他人理解,而且也帮助你自己把这个想法想得更加清晰。
清楚地描述逻辑,用自然语言描述解决方案。
先用自然语言把逻辑,过程描述清楚,然后在写代码很有帮助。
通过复述,人们更容易找到问题的所在。
如果你不能把问题说明白或用词语来做设计,估计是缺少了什么东西或什么缺少定义。把一个问题(想法)变成语言真的可以让它更具体。
原则十一:少写代码
知道什么时候不写代码可能对于一个程序员来讲是他所要学习的最重要的技巧。
- 从项目中消除不必要的功能,不要过度设计;
- 重新考虑需求,解决版本最简单的问题,只要能完成工作就行;
- 经常性地通读标准库的整个API,保持对它们的熟悉程度。
from yusubond.github.io.
本读书笔记已搬移至wiki https://github.com/yusubond/yusubond.github.io/wiki
from yusubond.github.io.
Related Issues (4)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from yusubond.github.io.