04 注重实效的偏执
21 按合约设计(简称 DBC)
- 客与供应者必须就权利与责任达成共识。
- 死程序不撒谎
- 断言程序,沿途校验你的代码
没有什么比常识和坦率更让人感到惊讶。
——爱默生《散文集》
- 你以为与计算机打交道难,但是与人打交道更困难。
- 接受的东西要严格,允诺返回的东西要尽可能少。
注释与业务流程
实现 DBC
- 循环不变项(条件是什么?)
- 语义不变项
- 动态合约与代理
- DBC难用么?
22 死程序不说谎
- 尽早检测问题 (RuntimeException)
23 断言编程
在自责中有一种满足感。当完美责备自己时,会决定再也没有人有权责备我们。
-- 奥斯卡*王尔德
这绝对不会发生。。。
- 使用代码检查。
- 让断言开着。(避免bug产生)
- 断言与副作用(影响业务)
24 何时使用异常
- 知道何时使用它们。
- 取决于实际。(什么异常)
- 错误处理器(怎么处理)
25 怎么配平资源
“我把你带进这个世界,”我的父亲会说:
“我也可以把你赶出去。那没有我影响。我要再造另外一个你。”
管理什么?
内存、事务、线程、定时器。
无论是谁分配的资源,它都应该负责接触该资源的分配
- 构造器,给予你特定的对象。
- 析构器,移除资源
问题
- 异常与解除资源的难点。
- java语言多了finally。
- 当你无法配平衡的时候。(明确选择)
- 检查配平
提示
- 30 你不可写出完美的软
- 31 通过合约进行设计
- 32 早崩溃
- 33 完美不要这样自我欺骗,特别是在编码时。
- 34 将异常用于异常的问题。
- 35 要有始有终
05 弯曲,或折断
26 解偶与得墨忒尔法则
好篱笆促成好邻居。
- 把你的代码组织成最小的单元模块,并限制它们之间的交互。
- 使耦合尽量地减少。
- 函数的墨忒尔法则
问题
- 对某个模块的“简单”改动会传遍系统的一些无关模块。
- 开发者害怕改动代码,因为它们不清楚哪些代码可能会受影响。
缩小响应集的规模,错误传播少。
27 元程序设计
再多的天才也无法胜过对细节的专注。
- 如何适应变化?
- 细节为什么会弄乱完美的整洁的代码?
动态配置
什么是元数据?
描述数据的数据。
schema 含有名称、存储长度,属性,字段。
元数据驱动的应用
好处
- 解除你设计的耦合,从而带更灵活、可适应性更好的程序。
- 推迟细节处理,创建更健壮、更抽象的设计——完全推迟程序之外。
- 无需重新编译应用,你就可以对其进行定制。
- 与通用的编程语言相比,可以通过一种大为接近问题的领域方式表示元数据。
- 你甚至可以泳道相同的应用引起,但是不同的元数据,不同的目的。「能做得这样就不错了」
商业逻辑
- 以一种非常灵活的格式维护它们是很有意义的。
- 规则系统,专家系统。(纯文本的力量?)
例子:EJB
配置元数据,降低代码耦合度。
跨越事务+线程。
不要编写渡渡鸟代码
没有适应性和灵活性,就会死亡。
28 时间耦合
吸引我们的时间知识进度表上的时间,我们现在要谈论的是——
并发和次序。
思考:总是先做A再做B,这样思考带来时间耦合。
==>工作流,架构,设计,部署
工作流
- 画出UML活动图。(某一时刻会发生什么,以及必须以严格的次序发生。)
架构
组件化。
数据库,例子嘘iaji(生产者与消费者)
- 数据库操作需要长时间
- 每个事务,在数据库事务处理的通过同时,我们不能阻塞阻碍通许点
- 多个事务在每条数据显示能够并发又
为并发进行设计
面对多线程化如此有益。
被调用时,对象必须总是处于有效的状态中,而且它们可能会在最尴尬的时候被调用。
更简洁的接口
StringTokenizer 简洁可维护。
29 它知识视图
那人依然只听到,
他想要听到的东西,
而不顾其他,
啦-啦-啦。
分而治之
- 划分模块,单一,责任明确。
- 怎么互相交谈,怎么管理依赖?怎么状态同步?
- ==>事件(event)
发布/订阅
推送哪些事件呢?需要密切关注么?耦合高?
方法
- 发布/订阅
- 总线
超越GUI
mvc 表面,实质可以协调机制。
设计方式——查看器网络,灵活性。
可能还有耦合
30 黑板
字迹在墙上...
特性
- 看了黑板可以获取新的信息,并且加上他们的发现。
- 经验不同,负责的内容也不同。
- 多人协助,时空可以不同
- 可以放各种信息。
实现
前期,语音识别,基于知识的推理。
如何组织你的黑板?(接口)
- 有点类似mq(异步,时序)
- 封装一些规则
- 独立与隔离
提示
- 36 使模块之间耦合减至最少
- 37 要配置不要集成
- 38 将抽象放进代码,细节放进元数据
- 39 分析工作流,以改善并发性。
- 40 用服务进行设计
- 41 总是为并发进行设计
- 42 使视图与模型分离
- 43 用黑被协调工作流
第六章 当你编码时
不要机械地转换设计为可执行语句。
丑陋,抵消,糟糕,不可维护和完全错误。
==> 批判,思考(高效的程序员)
31 靠巧合编程
士兵探测地雷,侥幸就会炸死。
开发者不能靠运气和偶然的成功——而要深思熟虑。
考虑
- 它也许不是真的能工作
- 你依靠的边界条件也许只是一个偶然。
- 没有计入文档的行为,可能会随着库的下一次发布而变化。
- 多余的和不必要的调用会使你的代码编码。
- 多余的调用还会增加引入它们自己的新bug
巧合
- 实现的偶然
- 语境的偶然
- 隐含的假定
怎么深思熟虑地编程?
- 总是意识到你在做什么?
- 不要盲目地编程。
- 按照计划行事。
- 依靠可靠的事物。
- 为你的假定建立文档。
- 不要只是测试你的代码,还要测试你的假定。
- 为你的工作划分优先等级。
- 不要做历史的奴隶,不要让已有的代码支配将来的代码。
32 算法速率
你知道1000条记录运行多久,但如果增加到100000条记录呢?
哪里需要优化?
O()表示法
近似计算,是线性相关还是。。。?
表示使用多少资源。
常识估算
- 简单循环
- 嵌套循环
- 二分法
- 分而治之
- 组合
最好的并非总是最好的
33 重构
周遭所见,皆是易与衰退。
你应该何时进行重构
- 遇到绊脚石
- 遇到合并或“错误”的东西。
Martin Fowler 建议
- 不要视图在重构的同时增加功能。
- 在开始重构之前,确保你拥有良好的测试。尽可能经常运行这些测试。
- 采取短小、深思熟虑的步骤。
软件的熵(破窗原理)
要管理痛苦:如果它现在有损害,但以后的损害会更大,你也许最好一劳永逸地去修正。
34 易于测试的代码
软件组件应该就像集成电路芯片一样进行组合,也要保证组件的可靠性。
单元测试(已知情况,人工环境)
在隔离状态下对每个模块进行测试,目的是检验其行为。
- 例子,可以说明你模块的所有功能。
- 用以构建回归测试、以验证未来对代码的任何改动是否正确的一种手段。
针对合约进行测试
确保:一、代码是否符合合约。
二、合约的含义是否与我所认为的一样。
流程
先检验子模,再测试模块自身。
仔细思考边界条件。
避免“下游的灾难”
使用测试装备
功能
- 用以指定设置和清理的标准途径。
- 用以选择个别或所有可用测试的方法。
- 分析输出是否预期(或意外)结果的手段
- 标准化的故障报告形式。
使用JUnit
测试文化(测试是技术,但更是文化)
都要进行测试,无论是团队还是最终用户。
35 邪恶的向导
现代软件越来越难维护了。
使用“向导”自动为你生成骨架代码。(需要理解和学习)
有人认为这是极端的,向导代码逐渐变成了程序员的代码。
提示
- 44 不要靠巧合编程
- 45 估算你的算法的阶
- 46 测试你的估算
- 47 早重构,常重构。
- 48 为测试而设计
- 49 测试你的软件,否则你的用户就得测试