高级农民
- 积分
- 2532
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2018-12-20
- 最后登录
- 1970-1-1
|
本楼: |
👍
100% (23)
|
|
0% (0)
👎
|
全局: |
👍 89% (2318) |
|
10% (283) 👎 |
注册一亩三分地论坛,查看更多干货!
您需要 登录 才可以下载或查看附件。没有帐号?注册账号
x
强烈推荐此书《The Art of Readable Code》的读书笔记,花个把小时就可以显著提升你的代码质量
https://pegasuswang.readthedocs. ... 8%89%BA%E6%9C%AF/#4
最好就是写更少的代码,而最易懂的代码就是没有代码!下面摘抄简单入门的
"Code should be written to minimize the time it would take for someone else to understand it."
如何命名
使用含义明确的词,比如用`download`而不是`get`,参考以下替换方案:
send -> deliver, dispatch, announce, distribute, route
find -> search, extract, locate, recover
start -> lanuch, create, begin, open
make -> create,set up, build, generate, compose, add, new
使用具体的名字
`CanListenOnPort`就比`ServerCanStart`好,can start比较含糊,而listen on port确切的说明了这个方法将要做什么。
`--run_locally`就不如`--extra_logging`来的明确。
增加重要的细节,比如变量的单位`_ms`,对原始字符串加`_raw`
password -> plaintext_password
comment -> unescaped_comment
html -> html_utf8
data -> data_urlenc
使用`min`、`max`代替`limit`
CART_TOO_BIG_LIMIT = 10
if shopping_cart.num_items() >= CART_TOO_BIG_LIMIT:
Error("Too many items in cart.")
MAX_ITEMS_IN_CART = 10
if shopping_cart.num_items() > MAX_ITEMS_IN_CART:
Error("Too many items in cart.")
对比上例中`CART_TOO_BIG_LIMIT`和`MAX_ITEMS_IN_CART`,想想哪个更好呢?
Boolean型变量命名
bool read_password = true;
这是一个很危险的命名,到底是需要读取密码呢,还是密码已经被读取呢,不知道,所以这个变量可以使用`user_is_authenticated`代替。通常,给Boolean型变量添加`is`、`has`、`can`、`should`可以让含义更清晰,比如:
SpaceLeft() --> hasSpaceLeft()
bool disable_ssl = false --> bool use_ssl = true
public double getMean() {
// Iterate through all samples and return total / num_samples
}
在这个例子中,`getMean`方法遍历了所有的样本,返回总额,所以并不是普通意义上轻量的`get`方法,所以应该取名`computeMean`比较合适。
怎么写注释
// Calls an external service to deliver email. (Times out after 1 minute.)
void SendEmail(string to, string subject, string body);
有时候为了更清楚说明,需要给整个文件加注释,让读者有个总体的概念:
// This file contains helper functions that provide a more convenient interface to our
// file system. It handles file permissions and other nitty-gritty details.
按照函数的节奏,写一些注释:
def GenerateUserReport():
# Acquire a lock for this user
...
# Read user's info from the database
...
# Write info to a file
...
# Release the lock for this user
精简注释
// The int is the CategoryType.
// The first float in the inner pair is the 'score',
// the second is the 'weight'.
typedef hash_map<int, pair<float, float> > ScoreMap;
这样写太罗嗦了,尽量精简压缩成这样:
// CategoryType -> (score, weight)
typedef hash_map<int, pair<float, float> > ScoreMap;
条件语句中参数的位置
对比下面两种条件的写法:
if (length >= 10)
while (bytes_received < bytes_expected)
if (10 <= length)
while (bytes_expected > bytes_received)
到底是应该按照大于小于的顺序来呢,还是有其他的准则?是的,应该按照参数的意义来
<li>运算符左边:通常是需要被检查的变量,也就是会经常变化的</li>
<li>运算符右边:通常是被比对的样本,一定程度上的常量</li>
`bytes_received < bytes_expected`比反过来更好理解。
三目运算符(?:)
time_str += (hour >= 12) ? "pm" : "am";
Avoiding the ternary operator, you might write:
if (hour >= 12) {
time_str += "pm";
} else {
time_str += "am";
}
尽早return
public boolean Contains(String str, String substr) {
if (str == null || substr == null) return false;
if (substr.equals("")) return true;
...
}
函数里面尽早的return,可以让逻辑更加清晰。
逻辑替换
- 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)
所以,就可以这样写:
if (!(file_exists && !is_protected)) Error("Sorry, could not read file.");
//替换
if (!file_exists || is_protected) Error("Sorry, could not read file.");
####不要滥用逻辑表达式
assert((!(bucket = FindBucket(key))) || !bucket->IsOccupied());
这样的代码完全可以用下面这个替换,虽然有两行,但是更易懂:
bucket = FindBucket(key);
if (bucket != NULL) assert(!bucket->IsOccupied());
消除条件控制变量
boolean done = false;
while (/* condition */ && !done) {
...
if (...) {
done = true;
continue;
}
}
这里的`done`可以用别的方式更好的完成:
while (/* condition */) {
...
if (...) {
break;
}
}
不要使用嵌套的作用域
# No use of example_value up to this point.
if request:
for value in request.values:
if value > 0:
example_value = value
break
for logger in debug.loggers:
logger.log("Example:", example_value)
这个例子在运行时候会报`example_value is undefined`的错,修改起来不算难:
example_value = None
if request:
for value in request.values:
if value > 0: example_value = value
break
if example_value:
for logger in debug.loggers:
logger.log("Example:", example_value)
但是参考前面的**消除中间变量**准则,还有更好的办法:
def LogExample(value):
for logger in debug.loggers:
logger.log("Example:", value)
if request:
for value in request.values:
if value > 0:
LogExample(value) # deal with 'value' immediately
break
用到了再声明
在C语言中,要求将所有的变量事先声明,这样当用到变量较多时候,读者处理这些信息就会有难度,所以一开始没用到的变量,就暂缓声明
业务相关的函数
那些与目标不相关函数,抽离出来可以复用,与业务相关的也可以抽出来,保持代码的易读性,例如:
business = Business()
business.name = request.POST["name"]
url_path_name = business.name.lower()
url_path_name = re.sub(r"['\.]", "", url_path_name)
url_path_name = re.sub(r"[^a-z0-9]+", "-", url_path_name)
url_path_name = url_path_name.strip("-")
business.url = "/biz/" + url_path_name
business.date_created = datetime.datetime.utcnow()
business.save_to_database()
抽离出来,就好看很多:
CHARS_TO_REMOVE = re.compile(r"['\.']+")
CHARS_TO_DASH = re.compile(r"[^a-z0-9]+")
def make_url_friendly(text):
text = text.lower()
text = CHARS_TO_REMOVE.sub('', text)
text = CHARS_TO_DASH.sub('-', text)
return text.strip("-")
business = Business()
business.name = request.POST["name"]
business.url = "/biz/" + make_url_friendly(business.name)
business.date_created = datetime.datetime.utcnow()
business.save_to_database()
把想法转换成代码
要把一个复杂的东西解释给别人,一些细节很容易就让人产生迷惑,所以想象把你的代码用平实的语言解释给别人听,别人是否能懂,有一些准则可以帮助你让代码更清晰:
- 用最平实的语言描述代码的目的,就像给读者讲述一样
- 注意描述中关键的字词
- 让你的代码符合你的描述
下面这段代码用来校验用户的权限:
$is_admin = is_admin_request();
if ($document) {
if (!$is_admin && ($document['username'] != $_SESSION['username'])) {
return not_authorized();
}
} else {
if (!$is_admin) {
return not_authorized();
}
}
// continue rendering the page ...
这一段代码不长,里面的逻辑嵌套倒是复杂,参考前面章节所述,嵌套太多非常影响阅读理解,将这个逻辑用语言描述就是:
有两种情况有权限:
1、你是管理员(admin)
2、你拥有这个文档
否则就没有权限
根据描述来写代码:
if (is_admin_request()) {
// authorized
} elseif ($document && ($document['username'] == $_SESSION['username'])) {
// authorized
} else {
return not_authorized();
}
// continue rendering the page ...
|
评分
-
查看全部评分
上一篇: 算法面试必刷100题下一篇: 分享一个notion记录刷题的模板
|