《驯服烂代码——代码内在质量的改善之道》写作大纲之二:内容简介

来源:互联网 发布:郑州seo 编辑:程序博客网 时间:2024/05/07 00:04
本人计划在2013年撰写《驯服烂代码——代码内在质量的改善之道》一书,恳请各位关注驯服烂代码的朋友审阅下面的写作大纲,看看如何写才能帮到日夜加班奋战在烂代码之中的人们。望不吝赐教,多谢!
内容简介


第一篇 明道

本篇讨论烂代码的含义和驯服烂代码的概念。


第1章 关于烂代码
本章讨论“烂代码”的含义和代码变烂的原因。
1.1 代码的内在质量
Steve McConnell在其著作《代码大全(第2版)》中指出:“1)软件同时拥有外在的和内在的质量特性。2)外在特性指的是该产品的用户所能够感受到的部分,包括:正确性、可用性、效率、可靠性、完整性、适应性、精确性和健壮性。质量的外在特性是用户关心的唯一软件特性。3)而程序员除了关心软件质量的外在特性之外,还要关心它的内在特性,包括:可维护性、灵活性、可移植性、可重用性、可读性、可测试性和可理解性。其中可读性指在细节语句的层次上理解系统的难易程度,而可理解性指同时在系统组织和细节语句两个层次上理解系统的难易程度。”
本书主要关注以下代码的内在质量特性:1)可理解性、2)可测试性和3)可扩展性。其中可扩展性包括了上面McConnell列出的可维护性和灵活性。
1.2 何谓烂代码
《修改代码的艺术》作者Michael C. Feathers说:“遗留代码(即本书讨论的烂代码)就是那些没有编写相应测试的代码。”
本人认为烂代码就是那些1)难理解、2)难测试和3)难扩展的代码。
1.3 为何代码会变烂
在心态方面,有两点原因:深陷贪嗔痴,未曾戒定慧。
深陷贪嗔痴
贪:贪图完成更多新功能或更早地完成任务,明明看到烂代码, 却总想以后有时间再去处理, 但是总是找不到时间。
嗔:当需要改别人写的代码就嗔怒: 为什么总是我给别人擦屁股?后果:不去读和改别人的代码,而是什么都自己写,造成大量代码冗余。
痴:不知如何提高代码内在质量。不知该如何用英文命名方法名、变量名,不知道方法名可以当作注释使用。没有写单元测试、TDD、结对编程的习惯。不知道单元测试好比地方政府,没有单元测试就好像无政府。不了解重复代码好比机构臃肿人员冗余的行政机构, 大大降低修改代码的效率, 而重构就是消除重复代码的利器。不了解重构需要有单元测试保护。不了解自动化单元测试与自动化集成测试的区别。不知道如何通过解耦合来写单元测试。不了解面向对象设计的SOLID(单一职责、 开闭、里氏替换、接口隔离、依赖倒置)原则。不了解代码腐臭的危害和克服方法。误认为只有写代码才算真正的工作,理解代码似乎不算真正的工作。
未曾戒定慧
程序员不安心编程序,期望转型:项目经理、产品经理、团队经理。业内有一种古怪的风气,使那些有一定行业经验的程序员, 纷纷转向,立志去做管理方面、设计方面的事情。 这是整个行业病态的表现。
在技术方面,有下面三个忽视:
忽视问题领域中概念的中英文名称的对应性和一致性,造成难理解;
忽视单元测试,软件设计时很少考虑为测试提供便利(如单例和final的使用),造成难测试;
忽视重构,代码重复增多,造成难扩展。


第2章 驯服烂代码
本章讨论驯服烂代码的心法、核心概念和基本步骤。
2.1 驯服烂代码的心法
心法指能有效驯服 烂代码的内心观念
2.1.1 专业精神的核心价值
《21世纪商业评论》主编吴伯凡说:“专业精神是无限认同和尊重自己所从事的工作,并全身心地投入它,将专业技能发挥到极致的精神。专业精神的核心价值:超乎眼前功利性价值的价值。”
欧美现代工业文明背后的精神支柱:新教伦理。
日本现代工业文明背后的精神支柱:石门心学。
中国人的专业精神的精神支柱:儒释道。
2.1.2 稻盛和夫之田间的精进
回报看不见或不明显的艰苦努力是“田间的精进”。“精进”本质上不是在尘世的进步,而是“灵魂的质量”的提升。
禅宗牧牛图可以用来比喻驯服烂代码的过程。禅宗很多祖师喜欢用“牧牛”譬喻“修心”,即将牧童比作人,将“牛”比作“心性”,后来许多牧牛公案逐渐形成图卷,并由许多禅师依据图卷作成偈颂,从而成为图文并茂的禅门心法著作。在驯服烂代码的领域里,可以将牧童比作程序员,将牛比作烂代码,烂代码经过调伏,最终达到代码整洁的境界。
2.1.3斩断无明结束苦难
人有三毒:贪嗔痴。痴即无明,是苦难的根源。唯有斩断无明,才能结束苦难。
贪:教育的急功近利和家庭溺爱的造成中国人普遍缺乏专业精神。
嗔:程序员喜欢在网上吵谁比谁牛;程序员喜欢给自己贴负面的标签:码农、苦逼、挨踢;程序员在论坛里出言不逊,比如本人客气的提问换来的是“脑残”的评价……
痴:不领悟南辕北辙的深意(方向错了,马越好,钱越多,车夫越好,就离目的地越远);没有分清因和果(在不主动改善代码内在质量的背景下, 试图通过头疼医头脚疼医脚的权宜之计 来试图改善软件外在质量。)
2.1.4如何洋为中用
一些西方经典中的概念,直译后拿到中国来用,会有水土不服的情况。比如在Martin Fowler的《重构》一书中,熊节先生把Bad Smells in Code译为“代码的坏味道”很贴切。在能主动解决code smells的团队,就直接用“坏味道”就够了;但是一般中国人体味不像老外那样有很浓重的狐臭,所以对于味道并不在乎,这样就导致在一些团队中,对code smells视而不见,此时就可以用“代码腐臭”或“病兆代码”来引起重视。
2.2 驯服烂代码的核心概念
代码的修改和扩展过程是永不停息的。
需要写代码来调整偏差的四个原因:1)新增功能;2)修正bug;3)改善设计;4)优化资源。
为了让代码的修改和扩展过程 更加安全和有秩序, 为一个类写单元测试相当于是 建立地方政府。
软件bug在测试驱动开发TDD下的新定义: Bug只是“维护目标”的副产品。
单元测试是先写还是后补有大不同。
代码有两个运行环境。
代码在自动化单元测试运行环境下,  摆脱依赖问题需要做替换, 有两类替换点:参数和实例方法。
重复代码好比机构臃肿人员冗余的行政机构, 大大降低修改代码的效率。
误区:只有写代码才算真正的工作, 理解代码似乎不算真正的工作。
2.3 驯服烂代码的基本步骤
本节仅简单介绍基本步骤,详细内容见第三篇 优术。
第1步 确定修改点
第2步 找到测试点
第3步 解除紧耦合
第4步 写单元测试
第5步 修改并重构


第二篇 知行
本篇通过实战的方式,讨论如何在AppFuse环境里,使用驯服烂代码的基本步骤和一些常用手法,来驯服一个Java EE电商项目的烂代码。


第3章 使用AppFuse构建可运行平台
本章讨论搭建AppFuse 2.2.1可运行环境的步骤。


第4章 驯服一个Java EE电商项目的烂代码
本章通过实战案例讲述下面5个驯服烂代码的步骤中的主要手法。
第1步 确定修改点
通过标记代码和删除没有调用的代码来读懂几个类的代码。通过讲系统故事和CRC卡片来搞清系统设计。
第2步 找到测试点
通过绘制影响草图,并找到汇点的方式来找到测试点。
第3步 解除紧耦合
用实例来讨论解耦入单测的两大类手法“接口提取”和“子类化并重写方法”中主要的手法。用实例来讨论在使用第三方类库的情况下进行单元测试。用实例来讨论化解难以测试的两种大型方法“流水账式方法”和“锯齿状方法”
第4步 写单元测试
用实例来讨论编写刻画测试理解待修改代码。
第5步 修改并重构
用实例来讨论使用TDD方法来写新特性。用实例来讨论绘制特征草图Feature Sketches,找到成员变量和 使用它们的方法组成的聚集块。用实例来讨论去除已有的重复代码。


第三篇 优术
本篇将第二篇 知行 的各种常用驯服烂代码手法的实践加以总结和归纳, 形成驯服烂代码的策略、基本步骤和手法的参考内容。
驯服烂代码的策略与基本步骤示意图:
 
第5章 上兵伐谋——新项目无烂代码
对于一个新项目,无烂代码。开发团队从始至终 使用TDD、重构、编码规范和 代码整洁之道进行编程。
5.1 测试驱动开发TDD与重构
5.2 代码整洁之道
5.2.1 中国程序员用英文给类名、方法名和变量名时的常见问题与解决方案


第6章 其次伐交——已有烂代码难理解
“其次伐交”本质上是“读代码”。包括驯服烂代码的步骤1“确定修改点”和步骤2“找到测试点”。
6.1第1步:确定修改点
6.1.1 读懂几个类的代码
画草图
打印出代码并标记出:职责、方法块、 待提取的方法及其耦合数(输入及输出变量 的数量)、代码修改影响到的所有变量等。
草稿式重构(不写单元测试、不提交重构结果,重构完即丢弃)
删除没有被调用的代码
6.1.2 搞清系统的设计
系统的设计就是道,但随着项目进展设计总是被人淡忘。 “你若始终坚守道,万物将会自己服从你。” ——《道德经,三十二章》
道恒无名、朴,虽小,天下弗能臣。侯王若能守之,万物将自宾。——三十二章
讲述系统的故事——假设别人不了解系统, 用最简单的几个概念把系统的设计讲清楚。
CRC卡片
6.2 第2步:找到测试点
绘制影响草图Effect Sketches,找到汇点Pinch Points
  绘制影响草图,找到汇点(测试点): 当需改动类的对象创建后, 列出能让该对象的方法的返回值发生变化的所有变量, 并画出产生这些影响的源变量和目的方法。
  影响产生的3种方式
方法的返回值被该方法的调用者所使用
对象A被作为对象B的某些方法的参数, 且对象A被改变且被对象B使用
修改后面会被用到的静态或全局数据
  寻找修改造成的影响时的启发式方法
1. 确定一个将要修改的方法
2. 如果该方法有返回值, 查看它的调用方
3. 看看该方法是否修改了什么值, 若是则查看其他使用了这些值的方法, 以及使用了这些方法的方法
4. 查看父类和子类, 它们也可能使用了这些实例变量和方法
5. 查看这些方法的参数, 看看你要修改的代码是否使用了 某参数对象或该参数对象的方法所返回的对象
6. 找出到目前为止被你所找出的 所有方法所修改的全局变量和静态数据
6.2.1 如何测试一处改动
6.2.2 如何测试多处改动


第7章 其次伐兵——已有烂代码难入单测
“其次伐兵”本质上是“改代码”。包括驯服烂代码的步骤3“解除紧耦合”、步骤4“写单元测试”和步骤5“修改并重构”。
7.1第3步:解除紧耦合
7.1.1 让类库体积更小、数量更多
7.1.2 在单元测试中轻松地创建类
解耦入单测的两大类手法“上下求索”的15中解耦入单测的归纳总结。
* 上:接口提取,用伪对象替换参数;(10种手法)
Extract Interface 接口提取
Adapt Parameter 参数适配
Parameterize Constructor 参数化构造函数
Parameterize Method 参数化方法
Introduce Instance Delegator 引入实例委托
Extract Implementer 实现提取
Break out Method Object 分解出方法对象
Pull up Feature 特性提升
Push down Dependency 依赖下推
Introduce Static Setter 引入静态设置方法
* 下:子类化并重写方法, 用测试子类替换父类的实例方法。(4种手法)
Subclass & Override Method 子类化并重写方法
Extract & Override Factory Method 提取并重写工厂方法
Extract & Override Call 提取并重写调用
Replace Global Reference with Getter 以获取方法替换全局引用
* 一种特殊情况下的手法:(1种手法)
Expose Static Method 暴露静态方法
如何处理当无法轻易创建该类的对象的情况。
如何处理当该类位于单元测试中, 单元测试无法轻易通过编译构建的情况。
如何处理需要用到的构造函数具有副作用的情况。
如何处理构造函数中有重要的工作需要我们感知探测的情况。
7.1.3 让单元测试跑起来
若待测方法没有使用实例变量或其他方法该如何处理。
若待测方法很长且难以对付该如何处理。
若需测试一个私有方法该如何处理。
若待测方法的参数很难构造或子类化该如何处理。
若待测方法有如修改数据库之类的副作用该如何处理。
7.1.4 在使用第三方类库的情况下进行单元测试
尽量避免在代码中出现对第三方类库的直接调用
对于第三方类库中把具体类做成final或sealed使得无法“伪造”它们时该如何处理。
当第三方类库API规模相对较小时时该如何处理。
当第三方类库API较为复杂时时该如何处理。
7.1.5化解难以测试的大型方法
大型的“流水账式方法”(很少有缩进块)该如何化解。
大型的“锯齿状式方法“(大量的缩进块)该如何化解。
7.2第4步:写单元测试
7.2.1 如何针对已有代码写单元测试
编写刻画测试Characterization Test理解待修改代码
7.2.2 如何组织单元测试
类命名约定
7.3 第5步:修改并重构
7.3.1 使用TDD方法来写新特性
7.3.2 分解大类
绘制特征草图Feature Sketches,找到成员变量和 使用它们的方法组成的聚集块(分解块)。
大类的弊病。
分解大类的指导原则:单一职责原则。
职责识别探索式方法。
分解大类的战略。
分解大类的战术。
7.3.2 去除已有的重复代码


第8章 其下攻城——拒绝同流合污
对于一个老项目,若因进度压力,虽然没有时间驯服已有烂代码, 但是保证新写的代码不与原有烂代码同流合污。这是不得已而为之的办法,因为这并没有改善原有烂代码的状况。
8.1 当新代码的职责与现有的烂代码的职责不同时,可以使用外敷类或新生类的手法。
8.2 当新代码的功能与原有的烂代码的功能同等重要时,可以使用外覆方法的手法。
8.3 当新代码的功能没有原有的烂代码的功能重要时,可以使用新生方法的手法。

原创粉丝点击