阅读本书有两种原因:第一,你是个程序员;第二,你想成为更好的程序员。很好。我们需要更好的程序员。
如何在一袋吗
要有代码
永远抛不掉代码,因为代码呈现了需求的细节。在某些层面上,这些细节无法被忽略或抽象,必须明确之。将需求明确到机器可以执行的细节程度,就是编程要做的事。
糟糕的代码
沼泽(wading)
混乱的代码
代码整洁的艺术:
缺乏“代码感”的程序员,看混乱是混乱,无处着手。有“代码感”的程序员能从混乱中看出其他的可能与变化。“代码感”帮助程序员选出最好的方案,并指导程序员制订修改行动计划,按图索
骥
什么是整洁代码
Bjarne Stroustrup,C++语言发明者:
优雅 高效
- 代码逻辑应当直截了当,叫缺陷难以隐藏;
- 尽量减少依赖关系,使之便于维护;
- 依据某种分层战略完善错误处理代码;
敷衍了事的错误处理代码只是程序员忽视细节的一种表现。此外还有内存泄漏,还有竞态条件代码。还有前后不一致的命
名方式 - 性能调至最优,省得引诱别人做没规矩的优化,搞出一堆混乱来。
- 整洁的代码只做好一件事。
整洁的代码力求集中。每个函数、每个类和每个模块都全神贯注于一事,完全不受四周细节的干扰和污染。
Dave Thomas,OTI 公司创始人,Eclipse 战略教父:
- 整洁的代码应可由作者之外的开发者阅读和增补。
- 它应当有单元测试和验收测试。
- 它使用有意义的命名。
- 它只提供一种而非多种做一件事的途径。
- 它只有尽量少的依赖关系,而且要明确地定义和提供清晰、尽量少的 API。
- 代码应通过其字面表达含义,因为不同的语言导致并非所有必需信息均可通过代码自身清晰表达。
有一条是根本性的。整洁的代码总是看起来
像是某位特别在意它的人写的。几乎没有改进的余地。
作者总结
简单代码,依其重要顺序:
— 能通过所有测试;
— 没有重复代码;
— 体现系统中的全部设计理念;
— 包括尽量少的实体,比如类、方法、函数等。
消除重复和提高表达力,提早构建简单抽象
名称要求
-
名副其实
-
避免误导
-
做有意义的区分(废话都是冗余)
-
使用读的出来的名称(选择恰当的英语词)
-
使用可搜索的名称
为单字母名称仅用于短方法中的本地变量。名称长短应与其作用域大小相对应 。若变量或常量可能在代码中多处使用,则应赋其以便于搜索的名称 -
避免使用编码
- 把类型或作用域编进名称里面,徒然增加了解码的负担
- 也不必用 m_前缀来标明成员变量。应当把类和函数做得足够小,消除对成员前缀的需要。
- 接口和实现(选择实现)
-
避免思维映射
选择是使用问题领域术语还是解决方案领域术语时。使用解决方案领域名称,只有程序员才会读你的代码。所以,尽管用那些计算机科学术语、算法名、模式名、数学术语吧。如果不能用程序员熟悉的术语来给手头的工作命名,就采用从所涉问题领域而来的名称吧。 传统上惯用单字母名称做循环计数器。然而,在多数其他情况下,单字母名称不是个好选择;读者必须在脑中将它映射为真实概念 -
类名,类名和对象名应该是名词或名词短语,如 Customer、WikiPage、Account 和 AddressParser。避免使用 Manager、Processor、Data 或 Info 这样的类名。类名不应当是动词
-
方法名。方法名应当是动词或动词短语,如 postPayment、deletePage 或 save。属性访问器、修改器
和断言应该根据其值命名,并依 Javabean 标准[18]加上 get、set 和 is 前缀。 -
不使用俚语
-
命名一以贯之、同个名称语义一致
-
添加有意义语境,不要添加没用的语境
函数
- 短小
- 只做一件事
- 每个函数一个抽象层级
- 自顶向下
- 使用描述性的名称
- 函数参数
最理想的参数数量是零(零参数函数),其次是一(单参数函数),再次是二(双参数函数),应尽量避免三(三参数函数)。有足够特殊的理由才能用三个以上参数(多参数函数)—所以无论如何也不要这么做- 一元函数的普遍形式(问参数问题、是操作该参数,将其转换为其他什么东西)
- 标识参数
标识参数丑陋不堪。向函数传入布尔值简直就是骇人听闻的做法。这样做,方法签名立刻变得复杂起来,大声宣布本函数不止做一件事。如果标识为 true 将会这样做,标识为 false 则会那
样做! - 二元函数
循序容易搞错,利用一些机制将其转换成一元函数 - 三元函数 (排序、琢磨、忽略的问题都会加倍体现,写前想清楚)
- 参数对象
如果函数看来需要两个、三个或三个以上参数,就说明其中一些参数应该封装为类了
- 参数列表
- 动词与关键字
给函数取个好名字,能较好地解释函数的意图,以及参数的顺序和意图。例如,write(name)就相当令人认同。不管这个“name”是什么,都要被“write”。更好的名称大概是 writeField(name),它告诉我们,“name”是一个“field”。 - 无副作用
- 输出参数
- 分隔指令与询问
函数要么做什么事,要么回答什么事,但二者不可得兼。函数应该修改某对象的状态,或是返回该对象的有关信息。两样都干常会导致混乱。 - 使用异常替代返回错误码
- 抽离 Try/Catch 代码块。Try/catch 代码块丑陋不堪。它们搞乱了代码结构,把错误处理与正常流程混为一谈。最好把 try 和 catch 代码块的主体部分抽离出来,另外形成函数
- 错误处理就是一件事。因此,处理错误的函数不该做其他事。
- 别重复自己
- 结构化编程
- 如何写出这样的函数
打磨代码,分解函数、修改名称、消除重复
总结:
每个系统都是使用某种领域特定语言搭建,而这种语言是程序员设计来描述那个系统的。函
数是语言的动词,类是名词。这并非是退回到那种认为需求文档中的名词和动词就是系统中类和
函数的最初设想的可怕的旧观念。其实这是个历史更久的真理。编程艺术是且一直就是语言设计
的艺术。
**大师级程序员把系统当作故事来讲,而不是当作程序来写。**他们使用选定编程语言提供的工
具构建一种更为丰富且更具表达力的语言,用来讲那个故事。那种领域特定语言的一个部分,就
是描述在系统中发生的各种行为的函数层级。在一种狡猾的递归操作中,这些行为使用它们定义
的与领域紧密相关的语言讲述自己那个小故事