读整理优先:小改进,大回报,整洁代码设计指南(下)
1. 管理
1.1. 整理是软件设计的一部分,它涉及你、你与代码的关系,以及你与自己的关系
1.2. 即使在重构变得可行的今天,编程环境仍然缺乏重构的自动化支持
1.3. 单独整理
-
1.3.1. 整理工作总得有个去处,不然还不如不整理
-
1.3.2. 理工作放在单独的PR里,每个PR包含的整理工作越少越好
-
1.3.3. 学习整理的人总是要经历一些必然的阶段
-
1.3.3.1. 在第一个阶段,我们就是做修改,大量的修改,不会差别对待这些修改
-
1.3.3.2. 把语句分成小段,就会容易形成解释型辅助函数(explaining helper),从而使修改行为也变得容易了
-
-
1.3.4. 审查的延迟时间是另一种动机
-
1.3.4.1. 如果代码很快就能完成审查,就应当鼓励创建更多更小的PR
-
1.3.4.2. 更有针对性的PR又会加快审查的速度
-
-
1.3.5. 掌握了整理、小步快跑和绝对安全的工作之后,建议不要审查整理工作的PR
- 1.3.5.1. 可以进一步减少审查的延迟时间,让整理工作的PR越来越小
1.4. 整理链
-
1.4.1. 抑制整理的冲动也是一项关键的整理技巧
-
1.4.2. 设置好卫述句,判断条件就可以转化为“解释型辅助函数”,或者提取成“解释型变量”
-
1.4.3. 清除杂乱无章的无用代码,就可以按“阅读顺序”或“内聚顺序”排列剩下的代码了
-
1.4.4. 如果把功能相同的代码写成一样,把功能不同的代码写成不一样,就可以精确地把相似的代码按“阅读顺序”分组
-
1.4.5. 有了全新接口,就忍不住想用
-
1.4.6. 阅读顺序确定之后,“对称归一”的机会可能就会出现
- 1.4.6.1. 调整顺序之前,代码元素的间隔很远,不太容易发现其相似性
-
1.4.7. 按照内聚顺序把元素放在一起,它们就会成为“提取子元素”的候选
-
1.4.8. 每一条给解释型变量赋值的语句,右半部分都可以作为一个“解释型辅助函数”
-
1.4.9. 提取解释型常量会让代码呈现出“内聚顺序”
- 1.4.9.1. 把一起修改的常量放在一起,未来改起来也更简单一些
-
1.4.10. 将参数显式化之后,一些参数就可以组合成一个对象,而一些代码也可以移动到这个对象里
-
1.4.11. 每个语句块之前都可以加上“解释型注释”
- 1.4.11.1. 一个语句块可以提取成一个“解释型辅助函数”
-
1.4.12. 提取出一个辅助函数之后,就可以引入“卫述句”、提取“解释型常量”和“解释型变量”,或者“删除多余注释”
-
1.4.13. 把零碎的代码集中成混乱的代码块之后,我们希望通过“语句分块”、添加“解释型注释”,以及“提取辅助函数”来进行整理
-
1.4.14. 通过引入“解释型变量”“解释型常量”或“解释型辅助函数”,尽可能把注释当中的信息移到代码里
-
1.4.15. 消除冗余注释的噪声有助于更好地发现“阅读顺序”,或者发现“显式化参数”的机会
-
1.4.16. 软件开发的主要成本消耗在变更上,而变更带来的成本主要是理解代码,因此,沟通代码的结构和意图是你可以锻炼的有价值的技能之一
-
1.4.17. 注释是沟通的一种形式,但整理可以让你探索通过其他编程元素进行沟通的极限
- 1.4.17.1. 只有绝对、完全多余的注释才应该删除
-
1.4.18. 整理工作开始被整合到一起,实现对代码结构更大的更改
-
1.4.18.1. 要警惕改得过多、过快
-
1.4.18.2. 与一系列成功的代码整理相比,一次失败就要付出高昂的代价
-
1.5. 批大小
-
1.5.1. 冲突
-
1.5.1.1. 放在一批的整理工作越多,集成的延迟时间就越长,这样整理工作与别人正在做的工作发生冲突的概率也就越大
-
1.5.1.2. 一旦遇到合并冲突,合并工作的成本就会上升一个数量级
-
-
1.5.2. 交互
-
1.5.2.1. 放在一批的整理工作越多,意外改变行为的可能性也会越高
-
1.5.2.2. 当整理工作和行为修改发生交互时,合并成本也会大幅上升
-
-
1.5.3. 投机
-
1.5.3.1. 整理工作只要刚好能够支持下一次行为修改就可以
-
1.5.3.2. 每一批的整理工作越多,就越容易只为了整理而整理,从而产生额外的成本
-
-
1.5.4. 你和团队需要弄清楚,究竟如何才能降低审查成本
-
1.5.4.1. 在信任和文化氛围浓厚的团队中,整理工作不需要审查
-
1.5.4.2. 交互的风险已经大大降低,整理工作不经过审查也不会破坏软件的稳定性
-
1.5.4.3. 要达到这种可以不用审查整理工作的安全和信任程度,需要几个月的时间
-
1.6. 节奏
-
1.6.1. 整理是为了让未来对系统的行为修改变得更容易,这件事值得去做
-
1.6.2. 管理整理工作的节奏也是一种管理整理工作的艺术
-
1.6.3. 软件设计是分形的,可以层层分解,因此时间比例也可以任意缩放
-
1.6.4. 行为修改往往会在代码里集中出现
-
1.6.4.1. 据帕累托法则,80%的修改会发生在20%的文件中
-
1.6.4.2. 优先整理的好处之一是整理也会集中出现,而且出现的地方正好就是在那些需要修改行为的地方
-
1.6.4.3. 即使一开始你整理过了头,也没有关系
1.6.4.3.1. 很快你就会发现自己想修改行为的代码已经整理好了
1.6.4.3.2. 继续整理,大多数修改就发生在整理过的代码区域里
1.6.4.3.3. 整理工作只需要几分钟到一小时
-
1.7. 解开乱麻
-
1.7.1. 你正在修改某些代码的行为,然后发现做某项整理能让修改变得更容易
-
1.7.2. 先要发现乱麻才能解开乱麻
- 1.7.2.1. 乱麻发现得越早,解开的工作量就越少
1.8. 整理工作能让未来对系统行为的修改变得更容易
-
1.8.1. 整理全部调用点并不是毫无意义的瞎折腾
-
1.8.2. 一旦所有修改全部迁移完,总会有某种修改的成本降低
-
1.8.3. 整理代码是一种很好的方法,能够让你意识到设计带来的详细结果
-
1.8.4. 同一区域的行为还会被修改,而且很快就会修改
-
1.8.5. 现在整理成本更低
-
1.8.6. 整理的成本和修改行为的成本大致相当
1.9. 从不整理
-
1.9.1. 这些代码再也不用修改了
-
1.9.2. 改进设计也没什么好处,学不到东西
1.10. 以后整理
-
1.10.1. 有一大堆整理工作等着要做,却没有立竿见影的效果
-
1.10.2. 完成整理工作终会有回报
-
1.10.3. 完成整理工作终会有回报
1.11. 事后整理
-
1.11.1. 等到下次再整理,成本会更高
-
1.11.2. 如果不整理,修改就好像没做完
1.12. 优先整理
-
1.12.1. 马上可以见效,要么是理解更清楚了,要么是修改更容易了
-
1.12.2. 你知道什么该整理,该怎么整理
-
1.12.3. 优先整理是更好的选择,但不要为了整理而整理
2. 理论
2.1. 元素有边界,所以你知道元素从哪里开始到哪里结束
- 2.1.1. 元素包含子元素
2.2. 软件设计中的关联
-
2.2.1. 调用
-
2.2.2. 发布
-
2.2.3. 监听
-
2.2.4. 引用
2.3. 进行软件设计时,是在机器指令和整个程序之间创建中间元素,这些中间元素就会互相作用带来收益
2.4. 软件有两种创造价值的方式
-
2.4.1. 软件现在能做的事
-
2.4.2. 未来可以让软件做新的事情
2.5. 期权性(optionality)
-
2.5.1. 环境越不稳定,期权就越有价值,这是期权最大的优势之一
-
2.5.2. 导致软件中的期权价值下降的情况
-
2.5.2.1. 关键员工离职
-
2.5.2.2. 和客户疏远
-
2.5.2.3. 修改成本飙升
-
2.6. 系统结构对系统行为没什么影响
2.7. 软件设计是一种兼顾“赚得早花得晚”和“创造期权而非物品”的方式
2.8. 软件设计是为改变(行为)而做的准备
-
2.8.1. 从期权性的角度思考软件设计
-
2.8.1.1. 潜在的行为修改价值波动越大越好
-
2.8.1.2. 开发的时间越长越好
-
2.8.1.3. 未来的开发成本越低越好
-
2.8.1.4. 创造期权的设计工作越少越好
-
2.9. 知道什么时候设计、怎么设计,以及什么时候不该设计
2.10. 结构修改通常是可逆的
-
2.10.1. 不可逆决策的审查、双重检查、三重检查是非常重要的
-
2.10.2. 代码审查流程没有区分可逆修改和不可逆修改
-
2.10.3. 可逆的设计决策变为不可逆的另一种情况是,设计决策会在整个代码库中传播
2.11. 耦合
-
2.11.1. 分析耦合并不能仅仅通过查看程序的源代码
-
2.11.2. 更大的问题是级联变化
-
2.11.2.1. 变化的成本遵循幂律分布,这种分布是由级联变化的成本造成的
-
2.11.2.2. 幂律分布的一个特点是少数几个大的“离群事件”非常重要
-
-
2.11.3. 要降低软件成本,必须减少耦合
- 2.11.3.1. 解耦并不是免费的,需要权衡利弊
-
2.11.4. 耦合就像黑夜里的乐高积木,只有踩到才能感觉到
-
2.11.5. 为了更早获得收入就会导致耦合
-
2.11.6. 基本的决策空间依然存在
- 2.11.6.1. 可以承担耦合的成本,也可以承担解耦的成本
2.12. 内聚
-
2.12.1. 耦合的元素应该是拥有共同包含元素的子元素
-
2.12.2. 将耦合的元素捆绑到它们自己的子元素中
-
2.12.3. 将不耦合的元素放到其他地方
-
2.12.3.1. 耦合的元素应该是拥有共同包含元素的子元素
-
2.12.3.2. 将耦合的元素捆绑到它们自己的子元素中
-
-
2.12.4. 不要大幅度地重新排列所有元素
2.13. 对于所有人来说,不要过于超前规划,但你正在学习的这种精妙绝伦的技术,其最终回报是与他人能更好地相处