本文算是两部分,一部分是对《编写可读代码的艺术》一书的总结,一部分算是自己这一年来对代码书写的心得体会。
虽然项目的整体构架和设计模式很重要,但程序员日常工作的大部分时间,还是会花在一些“基本”的事上,所以写的一手“好代码”,也十分重要。
这些代码洁癖包括:
命名,注释以及审美-可以用于代码库每一行的小提示。
简化循环和逻辑。
在程序中定义循环,逻辑和变量,从而使得代码更容易理解。
重新组织你的代码。
在更高层次上组织大的代码块以及在功能层次上解决问题的方法。
而代码洁癖,本身就是为了使代码更容易理解,你会发现,如果一个人的代码写的很干净,那么他的编程思路也绝对是清晰的。相反代码写的乱的人,他们的编程思路,甚至做事态度都是含糊不清的。
关键思想: 代码的写法应当使别人理解它所需的时间最小化。
表面层次的改进
命名
关键是要把信息装入名字中,这其中包括:
选择专业的词汇
避免泛泛的名字
用具体的名字代替抽象的名字
使用前缀或后缀来给名字附带更多信息
决定名字的长度
利用名字的格式来表达含义
使用比较专业的词
不要使用Get,Size,Tmp这样的命名,因为它们非常含糊,比如有一个函数要获取一个页面,使用getPage
就不够好,而使用FetchPage
,DownloadPage
就好很多。
而相比于Size,Height(),NumberNodes(),MemoryBytes()这样的专业词汇就要好很多。
还有类似Kill,Pause,Resume这样的动词,也要比Stop要好很多。
书中对专业词汇进行了总结:
单词 更多选择
send deliver, dispatch, announce, distribute, route
find search, extract, locate, recover
start launch, create, begin, open
make create, set up, build, generate, compose, add, new
不要使用很随便很泛泛的名字
永远不要使用tmp,it,retval,这样的命名,更不用说,foo,aa,bb了。
在交换两个值的代码中常常会用到tmp这个变量名,因为tmp这个名字只应用于短期存在且临时性为其主要存在因素的变量。
关于临时变量
关于临时变量,之前写过一篇博客:临时变量应该叫啥?
值得一提的是,最近使用的语言基本就是c#,python,所以再也没有使用过all_images
和all-images
这样的下划线命名方式了。
还有我认为尽量使用全拼,不要使用简写和缩写来命名变量。
开闭区间
《编写可读代码的艺术》书中提到,如果要操作[1,2,3,4,5]
这样的闭区间,使用first
和last
来命名。
而如果是操作[1,2,3,4,5)
这样的半开半闭区间,则使用begin
和end
这样的关键字。
注释
人们常常会说,好的代码是不需要注释的。
如果你的逻辑,你的类,你的函数命名,都是“可读的”,那么真是没有必要再去写一些“浪费精力”的注释了。
也就是说: 好代码 > 坏代码 + 好注释
而且注释也不仅仅是解释代码而已,还可以写一些记录你思想的注释,比如这样:
// TODO 此处代码会有取消后的bug,应该在保存的那一刻,才生成新的对象。
// TODO 是直接绑定到一个对象上,还是从表单获取数据?在后台再去创建这些对象。
有几种标记在程序员中很流行:
TODO: 我还没有处理的事情
FIXME: 已知的无法运行的代码
HACK: 对一个问题不得不采用比较粗糙的解决方案
XXX: 危险,这里有重要的问题
排版审美
好的代码绝对给人很清爽的感觉,就算是从IDE中粘贴出到普通的文本编辑器,没有高亮,代码依旧会显得很整齐。
这里有三条原则:
- 使用一致的布局
- 让相似的代码看上去相似
- 把相关的代码行分组形成代码块
再比如每行代码不要超过80个字符,也是必须要遵守的排版风格。(在我的编辑器中如果代码超过80行,会对此行代码进行高亮)
对于一系列的赋值语句,将=
进行对齐,也是个排版的好习惯,而且单词与操作符之间要保留一个空格的距离。
坏排版:
apple =5
orange =9
banana =19
pear =2
好排版:
apple = 5
orange = 9
banana = 19
pear = 2
逻辑与循环
逻辑判断
关于逻辑代码应该如何书写,我之前写过一篇博客,关于if的几种写法
for和while
现在基本能使用函数式编程和Linq的地方,我是不会再去写for语句了。其实在大学的时候,我就开始区分for
和while
,那些口口声声说什么for
和while
可以相互替代的根本什么都不懂。
其实for
语句就是常用于遍历一个容器,python的for
和c#的foreach
,应该算是操作迭代器的语法糖。而while
才算是重复执行某些动作。在c语言中,我们常常使用for
语句来操作数组。
代码风格
特别要注意一点的是,一致的风格比正确的风格更重要。
如果你积累了一定的代码量,就需要不断的总结自己的编码风格。
这其中不仅仅是代码风格,还包括自己掌握的编程范式,包括可读性和健壮性。比如这里应该用try..catch
,这里应该将创建的对象释放。
熟练之后,你都不用去想,就能马上写下这个问题应该如何去解决。
比如现在,我会在一段代码的开头,就检验要操作的对象是否为空。而且为了简化代码,我还会使用短路求值,而不是一个一个的判断。
1 | if(employee != null && employee.Department != null) |
或者一开始就将它们return
1 | if(employee == null || employee.Department == null) |
永不停息
慢慢的去做
一个人的钱包里是怎样的,那么他的房间就是怎样的。
而且如果不是每天花一点时间去整理,而是长时间后的突击式整理,变乱又是早晚的事。
所以一开始就急着去将学到的东西全部用出是不可能的,这需要你将这些技能,方法和技巧慢慢的融入到自己的coding中。
边际效益
其实我还是想说,如果你的程序构架不够好,设计模式做的不够好,那么代码本身写的再好,也不会有更大的突破,你只在在勤奋的走弯路,本身还是要抓清主次。与其过于抠编程细节,不如学学构架设计。