观点:程序员之间的互相尊重体现在他所写的代码中。他们对工作的尊重也体现在那里。代码最重要的读者不是编译器,解释器或电脑,而是人。写出的代码能让人快速理解、轻松维护、容易扩展的程序员才是专业的程序员。
《编写可读代码的艺术》一书,专注于如何编写可读性更好的代码。
本文概要总结了这本书的第3部分内容。
重新组织代码
3种组织代码的方法
a.抽取出那些与程序主要目的“不相关的子问题”。
b.重新组织代码使它一次只做一件事情。
c.先用自然语言描述代码,然后用这个描述来帮助你找到更整洁的解决方案。
第10章 抽取不相关的子问题
本章的建议是“积极地发现并抽取不相关的自逻辑”,我们是指:
a.看看某个函数或代码块,问问你自己,这段代码高层次的目标是什么?
b.对于每一行代码,问一下:它是直接未来目标而工作吗?这段代码高层次的目标是什么呢?
c.如果足够的行数在解决不相关的子问题,抽象代码到独立的函数中。
介绍性的例子
int[] array = {2,4,1,3}; 求最大值和最小值。 void method(){ //排序函数,这就是1个子问题 //去第1个和最后1个 }
纯工具代码
文件操作,邮件发送等。
创建大量通用代码
通用代码,它完全地从项目的其它部分解耦出来。这样的代码容易开发,容易测试,并且容易理解。SQL数据库、JavaScript库、XML库等。
项目专有的功能
把名字转换成1个URL,这类项目特有的功能,也是可以提取出来的。
其它话题:
简化已有接口;按需重塑接口;过犹不及。
总结
对本章一个简单总结就是:“把一般代码和项目专有的代码分开”。其结果是,大部分代码都是一般代码。通过建立一大组库和辅助函数来解决一般问题,剩下的只是让你的程序与众不同的核心部分。
这个技巧有帮助的原因是,它使程序员关注小而定义好的问题,这些问题已经同项目的其它部分脱离。其结果是,对于这些问题的解决方案倾向于更加完整和正确。你也可以在以后重用它们。
第11章 一次只做一件事情
同时在做几件事的代码很难理解。一个代码块可能初始化对象,清除数据,解析输入,然后应用业务逻辑,所有这些都同时进行。如果所有这些代码都纠缠在一起,对于每个"任务"都很难靠其自身来帮你理解它从哪里开始,到哪里结束。
你也许听说过这个建议:“一个函数只应该做一件事”。我们的建议和这差不多,但不是关于函数边界的。当然,把一个大函数拆分成多个小一些的函数是好的。但是就算你不这样做,你仍然可以在函数内组织代码,使得它感觉像是有分开的逻辑段。
下面是用于使代码“一次只做一件事情”所用到的流程:
a.列出代码所做的所有“任务”。这里的“任务”没有很严格的定义–它可以小得如“确保这个对象有效”,或者含糊得如“遍历树中所有的节点”。
b.尽量把这些任务拆分到不同的函数中,或者至少是代码中不同的段落中。
第12章 把想法变成代码
当你把一件复杂的事向别人解释时,那些小细节很容易就会让他们迷惑。把一个想法用“自然语言”解释是个很有价值的能力,因为这样其它知识没有你这么渊博的人才可以理解它。这需要把一个想法精炼成最重要的概念。这样做,不仅帮助他人理解,而且也帮助你自己把这个想法想得更清楚。
在你把代码“展示”给读者时,也应该使用同样的技巧。我们接受代码难点是你解释程序所做事情。
在本章中,我们会用一个简单的过程来使你编写更清晰的代码:
a.象对着一个同事一样用自然语言描述代码要做什么。
b.注意描述中所用的关键词和短语。
c.写出与描述所匹配的代码。
一个示例:
用户输入网站地址:如“http://FansUnion.cn”;
浏览器解析网址到IP,如42.96.184.84;
浏览器建立和该IP的Socket;
浏览器与该主机通信,取得网页;
显示网页内容。
第13章 少写代码
知道什么时候不写代码可能对于一个程序员来讲是他所要学习的最重要的技巧。你所写的每一行代码都是需要测试和维护的。通过重用库或者减少功能,你可以节省时间并且让你的代码保持精简节约。
最好读的代码就是没有代码。
a.别费神实现那个功能–你不会需要它。
很多功能没有完成,或者没有用,也可能是让程序更复杂。
一个功能,不是只有开发,还有测试,最后还有维护和升级。
b.质疑和拆分你的需求。
不是所有的程序都需要运行的快,100%准确,并且能处理所有的输入。如果你真的仔细检查你的需求,有时你可以把它削减成一个简单的问题。
c.保持小代码库。
创建“工具”代码减少重复代码;减少无用代码或者没有用的功能;让你的项目保持分开的子项目状态;注意“质量”,保持又轻巧又灵活。
d.熟悉你周边的库。
很多时候,程序员就是不知道现有的库可以解决他们的问题。或者有时,他们忘了库可以做什么。知道你的库能做什么,以便让你可以使用它,这一点很重要。
这里有一条比较中肯的建议:每隔一段时间,花15分钟来阅读标准库中的所有函数/模块类型的名字。这包括C++标准函数库(STL)、Java API等。
这样做的目的不是记住整个库。这只是为了了解有什么可以用的,以便下次你写新代码时会想:“等一下,这个听起来和我在API中见到的东西有点像…”我们相信提前做这种准备很快就会得到回报,起码因为你会更倾向于使用库了。
e.为什么重用库有这么大的好处?
在一个成熟的库中,每一行代码都代表大量的设计、调试、重构、文档、优化和调试。
第14章 测试与可读性
a.使测试易于阅读和维护
测试代码的可读性和非测试代码是同样重要的。其他程序员会经常来把测试代码看作非正式的文档,它记录了真实代码如何工作和应该如何使用。因此如果测试很容易阅读,使用者对于真实代码的行为会有更好的理解。
对使用者隐藏不必要的细节,以便更重要的细节会更突出。
b.让错误消息具有可读性。
c.手工构造错误消息。
选择好多测试输入:你应该选择一组最简单的输入,它能完整地使用被测代码。
为测试函数取合适的名字,如testAddUser()。
总结
在测试代码中,可读性仍然很重要。如果测试的可读性很好,其结果是它们也会变得很容易写,因此大家会写更多的测试。并且,如果你把事实代码设计得容易测试,代码的整个设计会变得更好。
以下是如何改进测试的几个具体要点:
a.每个测试的最高一层应该越简明越好。最好每个测试的输入/输出可以用一行代码来描述。
b.如果测试失败了,它所发出的错误信息应该能让你容易跟踪并修正这个bug。
c.使用最简单的并且能够完整运用代码的测试输入。
d.给测试函数一个有完整描述性的名字,以使得每个测试所测试的东西都很明确。不要用Test1(),而用testAddUser这样的名字。
最重要的是,要使它易于改动和增加新的测试。