不知道为什么,在读完神书(菜场)之后看其他书,总会有一种“这东西看了有毛用”的感觉。但是生活还是要继续。
命名:
如果名称需要注释来补充,那命名其实就不算完美。
长名称要优胜于短名称,并且名称的长短与其作用域大小相对应。但是与此同时,把类型和作用域编进名称里,突然增加了解码的负担。没理由要求每位新人都在弄清楚代码之前去搞懂另一套编码“语言”
匈牙利命名法:现在他们增加了修改变量,函数货类的名称、类型的难度,他们增加了阅读代码的难度,制造了让编码系统误导读者的可能性。
也不必使用前缀来表名成员变量。应当把类和函数做的足够小,消除对成员前缀的需要。
老实说,这一章很受教。因为我一直以来都在探索最佳的命名方案。尝试过好多。
入行时,用的是下面这种极简命名,在写的时候痛快,review的时候一脸懵逼,为了缓解懵逼,只能用注释去解释。
class A{
var b, //XXXXX
function c(){} //XXXX
}
在做了无数次的注释翻译代码之后又成了另一个极端,极端长命名。
class Generate{
var Generate_type;
function Generate_begin(){}
}
如书上所说,第一种会让人不知所云,第二种长命名又让人看得又臭又长。
函数:
- 代码的第一规则是短小,第二条规则还是短小。
- 逻辑判断中的代码块只应该有1行。这一样大抵应该是函数的调用语句。而且块内调用的函数拥有较具说明性的名称。从而增加了文档上的价值。
- 函数应该做一件事,做好这件事,只做这件事。
不好的函数:
- 过多的参数
- 输出参数
- 标示参数
- 死函数
一如既往地贴代码
刚入行:面条代码
for{
head1.html = 'xxx';
head1.offsetleft = x+122+'px'
head1.background = host+path+'.png'
foot.html = 'xxx';
foot.offsetleft = x+122+'px'
foot.borderImg = host+path+'.png'
}else{
}
现在作为老司机的话写法:--------------------------------------------------------
for{
generateHead();
generateFoot();
}else{}
----------上为调用,下为声明------------------
generateHead(){
head1.html = 'xxx';
head1.offsetleft = x+122+'px'
head1.background = host+path+'.png
}
generateFoot(){}
- 最理想的参数数量是0,越少越好。
重复可能是软件中一切邪恶的根源。许多原则和实践规则都是为控制与消除重复而创建。软件开发领域所有的创新都是在不断尝试从源码中消灭重复。 (感觉无比正确啊)
注释:
注释的恰当用法是弥补我们在用代码表达意图时而遭遇的失败。极端地说,拥有注释的代码,其实就算得上是失败。
我一开始接受到这个理论的时候 前一句是很赞同的,后一句一直都理解不了。也听过前辈们说“代码即文档”的观点。注释给了coder更加自由的发挥空间,可为什么会遭到如此的鄙视,终于在书里找到了答案。
- 注释会撒谎。注释存在的时间越久,就离其所描述的代码越远,注释的描述也就越加偏差。
- 代码在变动,在演化。只有代码能最准确地描述当前的意图,而注释不行。
- 不准确的代码比没注释的代码危害要大得多。因为有可能注释的预期是永远无法实现的。
—
真真有感触,刚入行的时候用的短命名。为了能在review中知道代码意图,源码中的注释永远都比代码写的还多。随着代码的演化,在修改注释的时候就会瞻前顾后,甚至直接偷懒直接改了代码而忽略的注释。深受其害。
好的注释:
- 版权
- 提供信息的注释。(返回值类型、穿参类型等)
- 对意图的解释(复杂逻辑的说明)
- 警示
- TODO
- 强调(放大)某个代码段的重要性
坏的注释:
- 喃喃自语
- 多余的注释
- 误导性注释
- 循规式注释
- 日志性注释
- 废话注释
- 能用函数或者变量的时候就不要用注释。
- author(因为版本管理会帮忙做这个事情)
- 注释掉的代码
格式
好的代码如同读报纸一样。名称简单并且一目了然。名称本身就应该足够告诉我们是否在正确的模块中。源文件顶部最应该给出高层次的概念和算法,细节应该往下中间展开。
错误处理
- 在业务逻辑和错误处理之间要有良好的区隔
- 代码异常不要反悔null值。返回null值,不光给自己增加了工作量,也给调用者添乱。只要有1处没检查null值,程序就有可能失控。
--
最近在跟刚入门的后台同学合作,上面第二条无比感同身受。。
类
- 保持内聚性就会得到许多短小的类
- 系统应由许多短小的类而不是少量巨大的类组成。每个小类封装一个权责,只有一个修改的原因,并与少数其他类一起协同达到期望的系统行为
其他
- 毁坏程序最好的办法之一就是以改进之名大动其结构,有些程序永远不能从这种所谓的“改进”中恢复回来。
这个观点也很同意。 很多时候在开发时候图方便,给日后留了包袱,总想着日后会优化。怎想真正到了优化的时候,无数的代码已经高度耦合,动一发则牵全身,同时分配出来的优化时间比开发时间要短,但实际上优化要消耗更大的精力。同时优化没有新开发功能那么效果显著,所以有种“吃力不讨好”的样子。
于是乎,留着日后优化就成了空话。要么会甩给接盘侠,要么只能花更大的代价重写。。都得不偿失。。
其他不好的代码实践:
- 一个源文件中存在多种语言。
无法避免,但是应该尽量减少
- 明显的行为未被实现。
- 不正确的边界行为
- 忽视安全
- 重复
- 在错误的抽象层级上的代码
- 基类依赖于派生类
- 信息过多
- 死代码
- 垂直分隔
- 前后不一致
- 混淆视听
- 人为耦合
- 特性依恋
- 选择算子参数(参数为bool)
- 晦涩的意图
- 位置错误的权责
- 不恰当的静态方法
好的代码实践
- 用解释性变量
- 函数名称应该表达其行为
- 理解算法
- 把逻辑依赖改成物理依赖
- 用多态代替if/else switch/case
- 遵循标准约定
- 用命名常量来代替魔术数
- 准确
- 结构甚于约定
- 封装条件
- 避免否决性条件
- 函数只做一件事
- 掩蔽时序耦合
- 别随意
- 封装边界条件
- 函数只应该在一个抽象层级上
- 在较高层级上放值可配置数据
- 避免传递浏览
- 采用描述性名称
- 名称应与抽象层级相符合
- 尽可能使用标准命名法
- 无歧义命名
- 为较大作用范围选用较长名称
- 避免编码
- 名称应该说明副作用