Code Complete PART2
PART2: 创建高质量的代码
chapter 5: Design in Construction 软件构建中的设计
1. Design Challenges
Design --> wicked: 只有通过解决或部分解决才能明确的问题 现实<-->理论
Sloppy process --> tide result
方法论;优劣的差异;good enough?
Tradeoffs & priorities
Restrictions
Nondeterministic
Heuristic process
Emergent 自然而然
2. Key Design Concepts
Primary Technical Imperative: Managing Complexity
Accidental and Essential difficulties
失控的复杂度 --> 失败 --尽量减少在任一时间需要考虑的程序量
Desirable characteristics of a design
Minimal complexity --避免“聪明”
Ease of maintenance --self-explanatory
loose coupling
extensibility
reusablity
high fan-in --good use of utility classes
low fan-out --7
portability
leanness --完成->不能删除任何东西:伏尔泰
stratification
standard techniques
Level of design
System --> subsystem 子系统:业务规则、GUI、DB、对象依赖性
--> classed --> routines --> internal routine
3. Design Buildng Blocks: Heuristics
find real-world objects
辨识对象及属性 --> 确定自身操作 --> 对其他对象的操作 --> 可见性 --> 公开接口
Form consistent abstractions
抽象是一种让你关注某一概念的时候可以同时放心地忽视其中一些细节的能力--在不同的层次处理不同的细节。
Encapsulate Implementation details
房屋建造
Inherit -- when inheritance simplifies the design
Hide secrets (Information Hiding)
封装,模块化 冰山
隐藏复杂度、隐藏变化源
障碍:信息分散 循环依赖 类内数据->全局数据 性能损耗
价值:修改 设计
Identify areas likely to change
寻找 分离 预防
易变化的区域:业务规则 输入输出 非标准语言特性 困难的设计和构建 状态变量
anticipating different degrees of change
让变化的影响范围和发生变化的可能性成反比
有用的最小子集 --> 扩充
keep coupling loose
criteria: 规模(连接数) 可见性 灵活性
kinds of coupling:
simple data parameter coupling
simple object coupling
object-parameter coupling
syntictic coupling: 控制标志 假设。。。
Look for common design patterns
现成抽象 --> 减少复杂度
细节制度化 --> 减少出错
多种方案 --> 启发
高层次 --> 简化交流
4. Design Practices
Iterate Divide and conquer Top-down and botton-up design approaches
top-down: 易上手,但易受底层复杂度影响
botton-up: 复杂,但可早期鉴别出系统的复杂度,设计出更好的高层类
experimental prototyping collaborative design How much design is enough
最大的设计失误在于自我认为做的很充分,事后却发现做得不够。
最大的悲哀莫过于大厦快要完工时地基出了问题。 ——罗素
Capturing your work
doc in source, wiki, mail, DC, picture, CRC(类、职责、合作者), UML
5. Comments on popular methodologies
Big design up front --> little design up front or enough design up front
Design in General
Couceptul Blockbusting: A Guide to Better Ideas
How to Solve it: A New Aspect of Mathematical Method
How to Solve it: Modern Heuristics
chapter 6: Working Classes 可以工作的类
1. Class Foundations: Abstract Data Types(ADTs)
Benefits: 隐藏实现细节 支持改动 接口提供更多信息 易提高性能 正确性验证 自说明性 数据传递 实体操作
ADT + 继承、多态 --> 类
2. Good Class Interfaces
Good Abstraction
抽象是一种以简化的形式看待复杂操作的能力 混杂-->一致
类接口应展现一致的抽象层次
理解类所实现的抽象 精确!
提供成对的服务
转移不相关信息 --> 模块内聚
让接口可编程,而不是表达定义
谨防破坏接口的抽象
抽象性 and 内聚性
Good Encapsulation
限制类和成员的可访问性(accessibility)
不公开暴露成员数据
避免把私有的实现细节放入类的接口
不要对类的使用者做出任何假设
避免使用友元类(friend class)
让阅读代码比编写代码更方便
警惕在语义上破坏封装性:针对接口编程 --> 透过接口针对内部实现编程×
3. Design and Implementation Issues
Containment("has a" relationships)
使用包含 万不得已使用private继承 警惕超过七个数据成员的类
Inheritance("is a" relationships)
更精简的代码
成员函数:对派生类可见?有默认实现?能被覆盖?
数据成员:对派生类可见?
要么对继承做详细的说明,要么不使用继承
Liskov替换原则:派生类必须能通过基类的接口被使用,且使用者无需了解两者之间的差异
确保只继承需要继承的部分
注意:继承接口 --> 继承实现 继承实现 --> 继承接口
只想要实现 继承?包含!
不要“覆盖”(语法角度)一个不可覆盖(语义角度)的成员函数!
把共用的接口反正继承树尽可能高的地方
只有一个实例:新的对象?新的类?
只有一个派生类:提前设计?
覆盖但没做任何操作:怀疑!
类型检查?多态!
让所有数据都是private
对继承持有歧视的态度!
Member functions and data
子程序的数量 类调用子程序的数量 对其它类的子程序的间接调用: 尽可能少!
尽量减少类与类间相互合作的范围。
Constructors
尽可能在构造函数中初始化所以数据成员
private constructors --> singleton property
deep copies >> shallow copies
4. Reasons to Create a Class
建模 降低复杂度 隔离复杂度 隐藏实现细节 限制变动的影响范围 隐藏全局数据 让参数传递更通畅 建立中心控制点 易于重用 为程序族做计划 包装相关操作 实现特定重构
Classes to avoid
god class; 无关紧要的类; 用动词命名的类
chapter 7: High-quality Routines 高质量的子程序
small intimate viaible flexible
1. Valid reasons to create a routines
降低复杂度 引入中间、易懂的抽象 避免代码重复 支持子类化 隐藏顺序 隐藏指针操作 提高可移植性 简化逻辑判断 改善性能
创建类的理由也是创建子程序的理由。
2. Design at the Routine Level
functional cohesion: 只执行一项操作
sequential cohesion: 步骤 共享数据 完成完整功能
communicational cohesion: 同样的数据,无其它联系
temporal cohesion: 需要同时执行
procedural cohesion: 子程序的操作按特定顺序
logical cohesion: 控制或“逻辑”是子程序组织的原因
coincidental cohesion
3. Good Routine Names
描述子程序所做的所有事情
避免使用无意义、含糊、表意不明的动词
不使用数字形成不同的子程序名
函数命名时对返回值有所描述
过程命名时使用语气强烈的动宾形式
准确使用对账词
为常用操作确定命名规则
4. How long can a routine be
适中最好 一屏 打印1到2页
5. How to use routine parameters
按输入-修改-输出组织
一致的排列顺序
使用所有的参数
状态或出错变量放最后
不要把子程序的参数用于工作变量
在接口中对参数的假设做出说明:I or M or O? unit? scope?
个数限制在大约7个以内
IN Modify OUT的命名规则
子程序的接口要达到何种抽象?
6. Special considerations in the use of functions
函数 vs 过程
如果一个子程序的用途是返回由其名字所指明的返回值,那么就应该使用函数,否则使用过程
检查所有可能的返回路径
不要返回指向局部数据的指针
7. Macro routines and Inline routines
把宏表达式整个包含在括号内
把含有多条语句的宏用{}包围
节制使用inline: 暴露细节
chapter 8: Defensive Programming 防御式编程
1. Protecting your program from invalid inputs
garbage in, garbage out
in: 检查源于外部的数据 检查数据输入 决定如何处理错误的输入数据
2. Assertions
开发时使用的让程序在运行时进行自检的代码
assert a != 0 : "a is unexpectedly equal to 0"
IN and OUT, state, value of variable, pointer check, container
Guidelines for using assertions
错误处理代码:预期会发生 断言:绝对不应该发生
避免把需要执行的代码放在断言中
用断言来验证前条件(运行前确保为真)和后条件(运行后确保为真)
先使用断言后使用错误处理代码
3. Error-Handling Techniques
返回中立值 下一个正确的数据 与前次相同的数据 最接近的合法值 log error-code
Robustness vs. correctness
correctness: 永远不返回不准确的结果
robustness: 尝试采用。。继续运转
4. Exceptions
通知机制
只有在真正例外的情况下才抛出异常:由于调用子程序的代码需要了解被调用代码可能发生的异常,因而弱化的封装
不能用异常来推卸责任
避免在构造和析构函数中使用异常,除非在同一地方捕获
在恰当的层次抛出异常:抛出的异常也是程序接口的一部分
在异常消息中加入导致异常发生的全部信息
避免使用空的catch语句
集中的异常报告机制 异常使用标准化 考虑异常的替代方案
5. Barricade your program to cotain the damage coused by errors
让软件的一部分处理“不干净”的数据,另一部分处理“干净”的数据,大部分代码就无需承担错误检查的任务
outside error-handling | assertions inside
6. Debugging Aids
Use offensive programming
对待异常:开发时--显现,运行时--自我修复
chapter 9: the Pseudocode Programming Process (PPP) 伪代码编写过程
1. Summary of steps in building classes and routines
steps in creating a class
类的总体设计 类中的子程序 复审并测试整个类
steps in building a routine
设计 检查 编写 检查
2. Pseduocode for Pros
类似英语,精确描述
避免使用目标语言的语法元素
在意图的层次编写伪代码
在足够低的层次上写伪码
3. Constructing routines by Using the PPP
Design the Routine
检查先决条件
定义问题:要隐藏的信息,输入输出,前条件后条件
子程序命名
决定如何测试
在标准库中寻找可用的功能
考虑错误处理
考虑效率问题
研究算法和数据结构
编写伪代码:头部注释+目的
考虑数据
检查伪码
Code the routine
写出子程序的声明
将伪码转为高层次的注释
在注释下填充代码
检查代码:重构?递归应用routine编写方法
收尾
check the code
脑海中检查:
桌面检查(desk checking)
同行评审(peer review)
走查(walk-through)
详查(inspection)
编译子程序
hacking and compiling 拼凑加检查×
将编译器的警告级别调到最高
使用验证工具(validators),C: lint
消除错误消息和警告的所有根源
在调试器中逐行执行代码 测试代码: 测试用例 消除程序中的错误
clean up leftovers
检查接口 检查整体设计质量 检查变量 检查语句和逻辑 检查布局文档及注释
4. Alternatives to the PPP
Test-first development
refactoring
design by contract
hacking×
0 comments:
Post a Comment