第四章 关键的“构建”决策 (key Construction Decision)
Checklist: 主要的构建实践 (Major Construction Practices)
编码
- 你有没有确定,多少设计工作将要预先进行,多少设计工作在键盘上进行(在编写代码的同时)?
- 你有没有规定诸如名称、注释、代码格式等“编码约定”?
- 你有没有规定特定的由软件架构确定的编码实践,比如如何处理错误条件、如何处理安全性事项、对于类接口有哪些约定、可冲用的代码遵循那些标准、在编码时考虑多少性能因素等?
- 你有没有找到自己在技术浪潮中的位置,并相应调整自己的措施?如果必要,你是否知道如何“深入一种语言编程”,而不受限于语言(仅仅“在一种语言上编程”)?
团队工作
- 你有没有定义一套集成工序——即,你有没有定义一套特定的步骤,规定程序员在把代码check in到主源码(代码库)中之前,必须履行这些步骤?
- 程序员是结队编程、还是独自编程,或者这两者的某种结合?
质量保证
- 程序员在编写代码之前,是否先为之编写测试用例?
- 程序员会为自己的代码写单元测试吗(无论先写还是后写)?
- 程序员在check in代码之前,会用调试器单步跟踪整个代码流程吗?
- 程序员在check in代码之前,是否进行集成测试?
- 程序员会复审(review)或检查别人的代码吗?
工具
- 你是否选用了某种版本控制工具?
- 你是否选定了一种语言,以及语言的版本或编译器版本?
- 你是否选择了某个编程框架(framework, 如J2EE或Microsoft.NET),或者明确地决定不使用编程框架?
- 你是否决定允许使用非标准的语言特性?
- 你是否选定并拥有了其他将要用到的工具——编辑器、重构工具、调试器、测试框架、语法检查器等?
Key Points
- 每种编程语言都有其优点和弱点。要知道你使用的语言的明确优点很弱点。
- 在开始编程之前,做好一些约定(convention)。如“改变代码使之符合这些约定”是近乎不可能的。
- “构建的实践方法”的种类比任何单个项目能用到的要多。有意识地选择最适合你的项目的实践方法。
- 问问你自己,你采用的编程实践是对你所用的编程语言的正确响应,还是受它的控制?请记得“深入一种语言去编程”,不要仅“在一种语言上编程”。
- 你在技术浪潮中的位置决定了哪种方法是有效的——甚至是可能用到的。确定你在技术浪潮中的位置,并相应调整计划和预期目标。
第五章 软件构建中的设计 (Design in Construction)
Checklist: 软件构造中的设计
设计实践
- 你已经作过多次迭代,并且从众多尝试结果中选择最佳的一种,而不是简单选择第一次尝试的结果吗?
- 你尝试用多种方案来分解系统,以确定最佳方案吗?
- 你同时用自下而上和自上而下的方法来解决设计问题吗?
- 为了解决某些特定的问题,你对系统中的风险部分或者不熟悉的部分创建过原型、写出数量最少的可抛弃的代码吗?
- 你的设计方案被其他人检查了吗(无论正式与否)?
- 你一直在展开设计,直到实施细节跃然纸上吗?
- 你用某种适当的技术——比如说Wiki、电子邮件、挂图、数码照片、UML、CRC卡或者在代码写注释——来保留设计成果吗?
设计目标
- 你的设计是否充分地处理了由系统架构层定义出并且推迟确定的事项?
- 你的设计被划分为层次吗?
- 你对把这一程序分解成为子程序、包和类方式感到满意吗?
- 类与类之间的交互关系是否已设计为最小化了?
- 类和子程序是否被设计为能够在其他的系统中重用?
- 程序是不是易于维护?
- 设计是否精简?设计出来的每一部分都绝对必要吗?
- 设计中是否采用了标准的技术?是否避免使用怪异且难以理解的元素?
- 整体而言,你的设计是否有助于最小化偶然性的和本质性的复杂度吗?
key points
- 软件的首要技术使命就是管理复杂度。以简单性作为努力目标的设计方案对此最有帮助。
- 简单性可以通过两种方式来获取:一是减少在同一时间所关注的本质性复杂度的量;二是避免生成不必要的偶然的复杂度。
- 设计是一种启发式的过程。固执于某一种单一方法会损害创新能力,从而损害你的程序。
- 好的设计都是迭代的。你尝试设计的可能性越多,你的最终设计方案就会变得越好。
- 信息隐藏是个非常有价值的概念。通过询问“我应该隐藏什么?”能够解决很多困难的设计问题。
第六章 可以工作的类 (Working Classes)
Checklist: 类的质量 (Class Quality)
抽象数据类型
- 你是否把程序中的类都看作是抽象数据类型了?是否从这个角度评估它们的接口?
抽象
- 类是否有一个中心目的?
- 类的命名是否恰当?其名字是否表达了其中心目的?
- 类的接口是否展现了一致的抽象?
- 类的接口是否能让人清楚明白地知道该如何用它?
- 类的接口是否足够抽象,使你能不必顾虑它是如何实现其服务的?你能把类看作黑盒子吗?
- 类提供的服务是否足够完整,能让其他类无须动用其内部数据?
- 是否已从类中除去无关信息?
- 是否考虑过把类进一步分解为组件类?是否已尽可能将其分解?
- 在修改类时是否维持了其接口的完整性?
封装
- 是否把类的成员的可访问性降到了最小?
- 是否避免暴露类中的数据成员?
- 在编程语言所许可的范围内,类是否已尽可能地对其他的类隐藏了自己的实现细节?
- 类是否避免对其使用者,包括派生类会如何使用它做了假设?
- 类是否不依赖于其他类?它是松散耦合的吗?
继承
- 继承是否只用来建立“是一个/is a“的关系?也就是说,派生类是否遵循了LSP(Liskov替换原则)?
- 类的文档中是否记述了其继承策略?
- 派生类是否避免了“覆盖”不可覆盖的方法?
- 是否把公用的接口、数据和行为都放到尽可能高的继承层次中了?
- 继承层次是否很浅?
- 基类中所有的数据成员是否都被定义为private而非protected的了?
跟实现相关的其他问题
- 类中是否只有大约七个或更少的数据成员?
- 是否把类直接或间接调用其他类的子程序的数量减少到最少了?
- 类是否只在绝对必要时才与其他类相互协作?
- 是否在构造函数中初始化了所有的数据成员?
- 除非拥有经过测量的、创建浅层复本的理由,类是否都被设计为当作深层复本使用?
与语言相关的问题
- 你是否研究过所用编程语言里和类相关的各种特有问题?
key Points
- 类的接口应提供一致的抽象。很多问题都是由于违背该原则而引起的。
- 类的接口应该隐藏一些信息——如某个系统接口、某项设计决策、或一些实现细节。
- 包含往往比继承更为可取——除非你要对“是一个/is a“ 的关系建模。
- 继承是一种有用的工具,但却会增加复杂度,这有违于软件首要技术使命——管理复杂度。
- 类是管理复杂度的首选工具。要在设计类时给予足够的关注,才能实现之一目标。
posted @
2008-12-01 20:58
lemonade
阅读(
226)
评论()
编辑
收藏
举报