从代码优化到团队协作,掌握软件开发的黄金法则

《代码大全2》中的核对表

《代码大全 2》

《代码大全 2》(Code Complete, Second Edition)是软件开发领域的一部经典著作,作者是史蒂夫・迈克康奈尔(Steve McConnell)。
自出版以来,它一直被视为软件开发者的 “圣经”,对编程实践和软件工程的发展产生了深远影响。
《代码大全 2》中的核对表是本书的一大亮点,它为软件开发过程提供了一个清晰、系统的指导框架,具有极高的价值。
提供全面的检查点
核对表涵盖了软件开发的各个环节,从代码设计到编码实现,再到测试和维护。每个环节都有详细的检查点,这些检查点就像是一个个精准的 “导航标”,帮助开发者全面审视自己的工作。例如,在代码设计阶段,核对表会提醒开发者考虑模块的独立性、接口的清晰性等问题;在编码实现阶段,会关注变量命名的规范性、代码注释的完整性等。通过逐一核对这些检查点,开发者可以避免很多常见的错误和疏漏,确保代码的质量。
增强开发的规范性
软件开发是一个复杂的过程,很容易出现不规范的操作。核对表为开发者提供了一套标准化的操作流程,使得开发工作更加规范化。无论是团队协作开发还是个人独立开发,都可以按照核对表的要求进行操作,保证代码的一致性和可读性。这不仅有助于提高开发效率,还方便后续的代码维护和升级。
促进知识传承和经验积累
核对表是作者多年软件开发经验的总结和提炼,它将一些优秀的编程实践和最佳经验以一种直观的方式呈现出来。对于新手开发者来说,核对表是一个很好的学习工具,通过遵循核对表的要求,可以快速掌握软件开发的基本规范和技巧。对于有经验的开发者来说,核对表也可以作为一个回顾和反思的工具,不断完善自己的开发流程和方法。这种知识传承和经验积累的作用,对于整个软件开发行业的发展都具有重要意义。
提高项目的成功率
在软件开发项目中,很多问题往往是由于一些看似不起眼的细节没有处理好而导致的。核对表就像是一个 “质量卫士”,通过对各个环节的细致检查,能够及时发现并解决这些潜在的问题,从而降低项目的风险,提高项目的成功率。它让开发者在项目开发过程中更加自信和从容,能够更好地应对各种挑战。
总之,《代码大全 2》的核对表是一个非常实用的工具,它为软件开发提供了全面、系统、规范的指导,是开发者提高代码质量和项目成功率的得力助手。

本文整理了《代码大全2》中的核对表,以便于查阅。

《代码大全 2》的核对表

需求

这张需求核对表包含了一系列的问题一一问问自己项目的需求工作做得如何。
本书并不会告诉你如何做出好的需求分析,所以列表里面也不会有这样的问题。
在开始构建之前,用这份列表做一次“心智健全”检查,
看看你的地基到底有多坚固一一用“需求里氏震级”来衡量。
并不是核对表中所有的问题都适用千你的项目。
如果你做的是一个非正式项目,那么你会发现有些东西根本就不需要考虑。
你还会发现一些问题你需要考虑,但不需要做出正式的回答。
如果你在做一个大型的、正式的项目,你也许就要逐条考虑了。

需求类型 检查项
功能需求 是否详细定义了系统的全部输入,包括其来源、精度、取值范围、出现频率等?
功能需求 是否详细定义了系统的全部输出,包括目的地、精度、取值范围、出现频率、格式等?
功能需求 是否详细定义了所有输出格式 (Web 页面、报表,等等) ?
功能需求 是否详细定义了所有硬件及软件的外部接口?
功能需求 是否详细定义了全部外部通信接口,包括握手协议、纠错协议、通信协议等?
功能需求 是否列出了用户想要做的全部事情?
功能需求 是否详细定义了每个任务所用的数据,以及每个任务得到的数据?
非功能需求(质量需求) 是否为全部必要的操作,从用户的视角,详细描述了期望响应时间?
非功能需求(质量需求) 是否详细描述了其他与计时有关的考虑,例如处理时间、数据传输率、系统吞吐最?
非功能需求(质量需求) 是否详细定义了安全级别?
非功能需求(质量需求) 是否详细定义了可靠性,包括软件失灵的后果、发生故障时需要保护的至关重要的信息、错误检测与恢复的策略等?
非功能需求(质量需求) 是否详细定义了机器内存和剩余磁盘空间的最小值?
非功能需求(质量需求) 是否详细定义了系统的可维护性,包括适应特定功能的变更、操作环境的变更、与其他软件的接口的变更能力?
非功能需求(质量需求) 是否包含对“成功”的定义?“失败"的定义呢?

架构

以下是一份问题列表,优秀的架构应该关注这些问题。
这张核对表的意图并非用做一份有关如何做架构的完全指南,
而是作为一种实用的评估手段,用来评估软件食物链到了程序员这一头还有多少营养成分。
这张核对表可用做你自己的核对表的出发点。
就像“需求"的核对表一样,如果你从事的是非止式项目,那么你会发现其中某些条款甚至都不用去想。
如果你从事的是更大型的项目,那么大多数条款都会是很有用的。

架构主题分类 检查项
整体组织结构 程序的整体组织结构是否清晰?是否包含一个良好的架构全局观(及其理由) ?
构造块定义 是否明确定义了主要的构造块(包括每个构造块的职责范围及与其他构造块的接口) ?
功能覆盖 是否明显涵盖了“需求“中列出的所有功能(每个功能对应的构造块不太多也不太少) ?
关键类描述 是否描述并论证了那些最关键的类?
数据设计 是否描述并论证了数据设计?
数据库组织 是否详细定义了数据库的组织结构和内容?
业务规则 是否指出了所用关键的业务规则,并描述其对系统的影响?
用户界面设计 是否描述了用户界面设计的策略?
用户界面模块化 是否将用户界面模块化,使界面的变更不会影响程序其余部分?
I/O 处理策略 是否描述并论证了处理 I/O 的策略?
资源管理 是否估算了稀缺资源(如线程、数据库连接、句柄、网络带宽等)的使用量,是否描述并论证了资源管理的策略?
安全需求 是否描述了架构的安全需求?
预算规划 架构是否为每个类、每个子系统、或每个功能域(functionality area)提出空间与时间预算?
可伸缩性 架构是否描述了如何达到可伸缩性?
互操作性 架构是否关注互操作性?
国际化/本地化 是否描述了国际化/本地化的策略?
错误处理 是否提供了一套内聚的错误处理策略?
容错办法 是否规定了容错的办法(如果需要) ?
技术可行性 是否证实了系统各个部分的技术可行性?
过度工程 是否详细描述了过度工程(overengineering)的方法?
“买 vs. 造”决策 是否包含了必要的“买 vs. 造"的决策?
复用代码处理 架构是否描述了如何加工被复用的代码,使之符合其他架构目标?
变更适应性 是否将架构设计得能够适应很可能出现的变更?
架构总体质量 - 需求解决 架构是否解决了全部需求?
架构总体质量 - 架构程度 有没有哪个部分是“过度架构/overarchitected”或“欠架构/underarchitected"?
架构总体质量 - 预期指标 是否明确宣布了在这方面的预期指标?
架构总体质量 - 概念一致性 整个架构是否在概念上协调一致?
架构总体质量 - 独立性 顶层设计是否独立于用作实现它的机器和语言?
架构总体质量 - 决策动机 是否说明了所有主要的决策的动机?
架构总体质量 - 程序员感受 你,作为一名实现该系统的程序员,是否对这个架构感觉良好?

前期准备

检查维度 检查项
开发方法适配 你是否辨明了自己所从事的软件的类型,并对所用的开发方法做出相应的剪裁?
需求定义 是否充分明确地定义了需求?而且需求足够稳定,能开始构建了? (详见需求核对表。)
架构定义 是否充分明确地定义了架构,以便开始构建? (详见架构核对表。)
风险识别 是否已经指出你的(当前)项目中独有的风险(以避免构建活动面临不必要的风险) ?

主要的构建实践

分类 检查项
编码 你有没有确定,多少设计工作将要预先进行,多少设计工作在键盘上进行(在编写代码的同时) ?
编码 你有没有规定诸如名称、注释、代码格式等“编码约定”?
编码 你有没有规定特定的由软件架构确定的编码实践,比如如何处理错误条件、如何处理安全性事项、对千类接口有哪些约定、可重用的代码遵循哪些标准、在编码时考虑多少性能因素等?
编码 你有没有找到自己在技术浪潮中的位置,并相应调整自己的措施?如果必要,你是否知道如何“深入一种语言去编程”,而不受限千语言(仅仅“在一种语言上编程”) ?
团队工作 你有没有定义一套集成工序-即,你有没有定义一套特定的步骤,规定程序员在把代码 check in (签入)到主源码(代码库)中之前,必须履行这些步骤?
团队工作 程序员是结对编程、还是独自编程,或者这二者的某种组合?
质量保证 程序员在编写代码之前,是否先为之编写测试用例?
质量保证 程序员会为自己的代码写单元测试吗(无论先写还是后写) ?
质量保证 程序员在 check in 代码之前,会用调试器单步跟踪整个代码流程吗?
质量保证 程序员在 check in 代码之前,是否进行集成测试 (integration - test) ?
质量保证 程序员会复审 (review) 或检查别人的代码吗?
质量保证 你是否选用了某种版本控制工具?
质量保证 你是否选定了一种语言,以及语言的版本或编译器版本?
质量保证 你是否选择了某个编程框架 (framework, 如 J2EE 或 Microsoft.NET),或者明确地决定不使用编程框架?
质量保证 你是否决定允许使用非标准的语言特性?
质量保证 你是否选定并拥有了其他将要用到的工具一编辑器、重构工具、调试器、测试框架 (test framework) 、语法检查器等?

软件构造中的设计

类别 检查项
设计实践 你已经做过多次迭代,并且从众多尝试结果中选择最佳的一种,而不是简单选择第一次尝试的结果吗?
设计实践 你尝试用多种方案来分解系统,以确定最佳方案吗?
设计实践 你同时用自下而上和自上而下的方法来解决设计问题吗?
设计实践 为了解决某些特定的问题,你对系统中的风险部分或者不熟悉的部分创建过原型、写出数量最少的可抛弃的代码吗?
设计实践 你的设计方案被其他人检查了吗(无论正式与否) ?
设计实践 你一直在展开设计,直到实施细节跃然纸上了吗?
设计实践 你用某种适当的技术一一比如说 Wiki 、电子邮件、挂图、数码照片、 UML 、CRC 卡或者在代码写注释一~来保留设计成果吗?
设计目标 你的设计是否充分地处理了由系统架构层定义出并且推迟确定的事项?
设计目标 你的设计被划分为层次吗?
设计目标 你对把这一程序分解成为子程序、包和类的方式感到满意吗?
设计目标 你把对这个类分解成为子程序的方法感到满意吗?
设计目标 类与类之间的交互关系是否已设计为最小化了?
设计目标 类和子程序是否被设计为能够在其他的系统中重用?
设计目标 程序是不是易千维护?
设计目标 设计是否精简?设计出来的每一部分都绝对必要吗?
设计目标 设计中是否采用了标准的技术?是否避免使用怪异且难以理解的元素?
设计目标 整体而言,你的设计是否有助千最小化偶然性的和本质性的复杂度吗?

类的质量

类别 检查项
抽象数据类型总体考量 你是否把程序中的类都看做是抽象数据类型了?是否从这个角度评估它们的接口了?
抽象 类是否有一个中心目的?
抽象 类的命名是否恰当?其名字是否表达了其中心目的?
抽象 类的接口是否展现了一致的抽象?
抽象 类的接口是否能让人清楚明白地知道该如何用它?
抽象 类的接口是否足够抽象,使你能不必顾虑它是如何实现其服务的?你能把类看做黑盒子吗?
抽象 类提供的服务是否足够完整,能让其他类无须动用其内部数据?
抽象 是否已从类中除去无关信息?
抽象 是否考虑过把类进一步分解为组件类?是否已尽可能将其分解?
抽象 在修改类时是否维持了其接口的完整性?
封装 是否把类的成员的可访问性降到最小?
封装 是否避免暴露类中的数据成员?
封装 在编程语言所许可的范围内,类是否已尽可能地对其他的类隐藏了自己的实现细节?
封装 类是否避免对其使用者,包括其派生类会如何使用它做了假设?
封装 类是否不依赖于其他类?它是松散耦合的吗?
继承 继承是否只用来建立“是一个/is a" 的关系?也就是说,派生类是否遵循了 LSP (Liskov 替换原则) ?
继承 类的文档中是否记述了其继承策略?
继承 派生类是否避免了“覆盖”不可覆盖的方法?
继承 是否把公用的接口、数据和行为都放到尽可能高的继承层次中了?
继承 继承层次是否很浅?
继承 基类中所有的数据成员是否都被定义为 private 而非 protected 的了?
跟实现相关的其他问题 类中是否只有大约七个或更少的数据成员?
跟实现相关的其他问题 是否把类直接或间接调用其他类的子程序的数量减到最少了?
跟实现相关的其他问题 类是否只在绝对必要时才与其他的类相互协作?
跟实现相关的其他问题 是否在构造函数中初始化了所有的数据成员?
跟实现相关的其他问题 除非拥有经过测量的、创建浅层复本的理由,类是否都被设计为当作深层复本使用?
与语言相关的问题 你是否研究过所用编程语言里和类相关的各种特有问题?

高质量的子程序

类别 检查项
大局事项 创建子程序的理由充分吗?
大局事项 一个子程序中所有适合单独提出的部分是不是已经被提出到单独的子程序中了?
大局事项 过程的名字中是否用了强烈、清晰的“动词+宾语”词组?函数的名字是否描述了其返回值?
大局事项 子程序的名字是否描述了它所做的全部事情?
大局事项 是否给常用的操作建立了命名规则?
大局事项 子程序是否具有强烈的功能上的内聚性?即它是否做且只做一件事,并且把它做得很好?
大局事项 子程序之间是否有较松的耦合?子程序与其他子程序之间的连接是否是小的 (small) 、明确的 (intimate) 、可见的 (visible) 和灵活的 (flexible) ?
大局事项 子程序的长度是否是由其功能和逻辑自然确定,而非遵循任何人为的编码标准?
参数传递事宜 整体来看,子程序的参数表是否表现出一种具有整体性且一致的接口抽象?
参数传递事宜 子程序参数的排列顺序是否合理?是否与类似的子程序的参数排列顺序相符?
参数传递事宜 接口假定是否已在文档中说明?
参数传递事宜 子程序的参数个数是否没超过 7 个?
参数传递事宜 是否用到了每一个输入参数?
参数传递事宜 是否用到了每一个输出参数?
参数传递事宜 子程序是否避免了把输入参数用做工作变量?
参数传递事宜 如果子程序是一个函数,那么它是否在所有可能的情况下都能返回一个合法的值?

防御式编程

类别 检查项
一般事宜 子程序是否保护自己免遭有害输入数据的破坏?
一般事宜 你用断言来说明编程假定吗?其中包括了前条件和后条件吗?
一般事宜 断言是否只是用来说明从不应该发生的情况?
一般事宜 你是否在架构或高层设计中规定了一组特定的错误处理技术?
一般事宜 你是否在架构或高层设计中规定了是让错误处理更倾向于健壮性还是正确性?
一般事宜 你是否建立了隔栏来遏制错误可能造成的破坏?是否减少了其他需要关注错误处理的代码的数量?
一般事宜 代码中用到辅助调试的代码了吗?
一般事宜 如果需要启用或禁用添加的辅助助手的话,是否无须大动干戈?
一般事宜 在防御式编程时引入的代码量是否适宜一既不过多,也不过少?
一般事宜 你在开发阶段是否采用了进攻式编程来使错误难以被忽视?
异常 你在项目中定义了一套标准化的异常处理方案吗?
异常 是否考虑过异常之外的其他替代方案?
异常 如果可能的话,是否在局部处理了错误而不是把它当成一个异常抛到外部?
异常 代码中是否避免了在构造函数和析构函数中抛出异常?
异常 所有的异常是否都与抛出它们的子程序处于同一抽象层次上?
异常 每个异常是否都包含了关于异常发生的所有背景信息?
异常 代码中是否没有使用空的 catch 语句? (或者如果使用空的 catch 语句确实很合适,那么明确说明了吗?)
安全事宜 检查有害输入数据的代码是否也检查了故意的缓冲区溢出、 SQL 注入、HTML 注入、整数溢出以及其他恶意输入数据?
安全事宜 是否检查了所有的错误返回码?
安全事宜 是否捕获了所有的异常?
安全事宜 出错消息中是否避免出现有助于攻击者攻入系统所需的信息?

伪代码编程过程

类别 检查项
通用检查 是否检查过已满足所有的先决条件?
类设计 定义好这个类要解决的问题了吗?
设计清晰度 高层次的设计是否足够清晰?能给这个类和其中的每一个子程序起一个好的名字吗?
测试规划 考虑过该如何测试这个类及其中每一个子程序了吗?
效率考量 关于效率的问题,你主要从稳定的接口和可读的实现这两个角度考虑吗?还是主要从满足资源和速度的预期目标的角度考虑过呢?
资源查找 在标准函数库或其他代码库中寻找过可用的子程序或者组件了吗?
算法查找 在参考书籍中查找过有用的算法了吗?
伪代码设计 是否用详尽的伪代码设计好每一个子程序?
伪代码检查 你在脑海里检查过伪代码吗?这些伪代码容易理解吗?
设计警告 关注过那些可能会让你重返设计的警告信息了吗? (比如说关于全局数据的使用、一些看上去更适合放在另一个类或子程序中的操作等。)
代码翻译 是否把伪代码正确地翻译成代码了?
迭代优化 你反复使用伪代码编程过程了吗?有没有根据需要把一些子程序拆分成更小的子程序?
假定说明 在做出假定 (assumptions) 的时候有没有对它们加以说明?
注释清理 已经删除掉那些冗余的注释了吗?
迭代选择 你是否采取了几次迭代中最好的那个结果?还是在第一次迭代之后就停止了?
代码理解 你完全理解你的代码了吗?这些代码是否容易理解?

使用数据的一般事项

类别 检查项
初始化变量 每一个子程序都检查其输入参数的有效性吗?
初始化变量 变量声明位置靠近变量第一次使用的位置吗?
初始化变量 尽可能在声明变量的时候初始化变量吗?
初始化变量 如果无法同时声明和初始化变量,有没有在靠近第一次使用变量的位置声明变量?
初始化变量 计数器和累加器经过了适当的初始化了吗?如果需要再一次使用,之前重新初始化了吗?
初始化变量 适当的重新初始化“需要重复执行的代码里的变量”了吗?
初始化变量 代码在经过编译器编译时是不是没有告警?(你启用了所有的告警选项了吗?)
初始化变量 如果你所使用的语言允许隐式声明,你为此可能引起的问题做好补偿措施了吗?
使用数据的其他事项 如果可能,所有的变量都被定义为具有最小的作用域吗?
使用数据的其他事项 各变量的引用点都尽可能的集中在一起吗?对同一个变量的两次相邻引用,或者整个变量的生命周期都这样做了吗?
使用数据的其他事项 控制结构符合数据类型吗?
使用数据的其他事项 所有声明的变量都用到了吗?
使用数据的其他事项 变量都在合适的时间绑定了吗?——也就是所,你有意识的在晚期绑定所带来的灵活性和增加的复杂度之间做出平衡了吗?
使用数据的其他事项 每个变量有且仅有一项用途吗?
使用数据的其他事项 每个变量的含义都很明确且没有隐含意义吗?

变量命名

类别 检查项
命名的一般注意事项 名字完整并准确地表达了变量所代表的含义吗?
命名的一般注意事项 名字反映了现实世界的问题而不是编程语言方案吗?
命名的一般注意事项 名字足够长,可以让你无须苦苦思索吗?
命名的一般注意事项 如果有计算值限定符,它被放在名字的最后吗?
命名的一般注意事项 名字中用 Count 或者 Index 来代替 Num 了吗?
为特定类型的数据命名 循环下标的名字有意义吗(如果循环的长度超出了一两行代码或者出现了嵌套循环,那么就应该是 i 、 j 或者 K 以外的其他名字) ?
为特定类型的数据命名 所有的“临时“变量都重新命以更有意义的名字了吗?
为特定类型的数据命名 当布尔变量的值为真时,变量名能准确表达其含义吗?
为特定类型的数据命名 枚举类型的名字中含有能够表示其类别的前缀或后缀了吗?例如,把Color_用于 Color_Red, Color_Green, Color_Blue 等了吗?
为特定类型的数据命名 具名常量是根据它所代表的抽象实体而不是它所代表的数字来命名的吗?
命名规则 规则能够区分局部数据、类的数据和全局数据吗?
命名规则 规则能够区分类型名、具名常量、枚举类型和变量名吗?
命名规则 规则能够在编译器不强制检测只读参数的语言里标识出子程序中的输入参数吗?
命名规则 规则尽可能地与语言的标准规则兼容吗?
命名规则 名字为了可读性而加以格式化吗?
短名字 代码用了长名字吗(除非有必要使用短名字) ?
短名字 是否避免只为了省一个字符而缩写名字的情况?
短名字 所有单词的缩写方式都一致吗?
短名字 名字能够读出来吗?
短名字 避免使用容易被看错或者读错的名字吗?
短名字 在缩写对照表里对短名字做出说明吗?
常见命名问题:你避免使用…… ……容易让人误解的名字吗?
常见命名问题:你避免使用…… ……有相近含义的名字吗?
常见命名问题:你避免使用…… ……只有一两个字符不同的名字吗?
常见命名问题:你避免使用…… ……发音相近的名字吗?
常见命名问题:你避免使用…… ……包含数字的名字吗?
常见命名问题:你避免使用…… ……为了缩短而故意拼错的名字吗?
常见命名问题:你避免使用…… ……英语中经常拼错的名字吗?
常见命名问题:你避免使用…… ……与标准库子程序名或者预定义变量名冲突的名字吗?
常见命名问题:你避免使用…… ……过于随意的名字吗?
常见命名问题:你避免使用…… ……含有难读的字符的名字吗?

基本数据类型

数据类型分类 检查项
数值概论 代码中避免使用神秘数值吗?
数值概论 代码考虑了除零错误吗?
数值概论 类型转换很明显吗?
数值概论 如果在一条语句中存在两个不同类型的变量,那么这条语句会像你期望的那样求值吗?
数值概论 代码避免了混合类型比较吗?
数值概论 程序编译时没有警告信息吗?
整数 使用整数除法的表达式能按预期的那样工作吗?
整数 整数表达式避免整数溢出问题吗?
浮点数 代码避免了对数量级相差巨大的数字做加减运算吗?
浮点数 代码系统地阻止了舍入错误的发生吗?
浮点数 代码避免对浮点数做等量比较吗?
字符和字符串 代码避免使用神秘字符和神秘字符串吗?
字符和字符串 使用字符串时避免了 off - by - one 错误吗?
字符和字符串 C 代码把字符串指针和字符数组区别对待了吗?
字符和字符串 C 代码遵循了把字符串声明为 CONSTANT + 1 长度的规则了吗?
字符和字符串 C 代码在适当的时候用字符数组来代替指针了吗?
字符和字符串 C 代码把字符串初始化为 NULL 来避免无终端的字符串了吗?
字符和字符串 C 代码用 strncpy( )代替 strcpy( )吗? strncat( )和 strncmp( )呢?
布尔变量 程序用额外的布尔变量来说明条件判断了吗?
布尔变量 程序用额外的布尔变量来简化条件判断了吗?
枚举类型 程序用枚举类型而非具名常量来提高可读性、可靠性和可修改性吗?
枚举类型 当变量的用法不能仅用 true 和 false 表示的时候,程序用枚举类型来取代布尔变量吗?
枚举类型 针对枚举类型的测试检测了非法数值吗?
枚举类型 把枚举类型的第一项条目保留为“非法的”了吗?
具名常量 程序用具名常量而不是神秘数值来声明数据和表示循环界限吗?
具名常量 具名常量的使用一致吗? ——没有在有些位置使用具名常量又在其他位置使用文字量?
数组 所有的数组下标都没有超出数组边界吗?
数组 数组引用没有出现 off - by - one 错误吗?
数组 所有多维数组的下标的顺序都正确吗?
数组 在嵌套循环里,把正确的变量用于数组下标来避免循环下标串话了吗?
创建类型 程序对每一种可能变化的数据分别采用不同的类型吗?
创建类型 类型名是以该类型所表示的现实世界实体为导向,而不是以编程语言类型为导向的吗?
创建类型 类型名的描述性足以强,可以帮助解释数据声明吗?
创建类型 你避免重新定义预定义类型吗?
创建类型 与简单地重定义一个类型相比,你考虑过创建一个新类吗?

使用不常见数据类型的注意事项

数据类型及使用情况 检查项
结构体 你使用结构体而不是使用单纯的变量来组织和操作相关的数据吗?
结构体 你考虑创建一个类来代替使用结构体吗?
全局数据 所有的变量是否都是局部的或者是类范围的?除非绝对有必要才是全局的?
全局数据 变量的命名规则能把局部数据、类数据和全局数据区分开吗?
全局数据 你对所有的全局变量都加以文档说明吗?
全局数据 避免使用伪全局数据,即被四处传递且包含有杂乱数据的巨大对象吗?
全局数据 用访问器子程序来取代全局数据吗?
全局数据 把访问器子程序和数据组织到类里面吗?
全局数据 访问器子程序提供了一个在底层数据类型实现之上的抽象层吗?
全局数据 所有相关的访问器子程序都位于同一抽象层之上吗?
指针 把指针操作隔离在子程序里吗?
指针 指针引用合法吗?或者说指针有可能成为空悬指针吗?
指针 代码在使用指针之前检查它的有效性吗?
指针 在使用指针所指向的变量之前检查其有效性吗?
指针 指针用完后被设置为空值吗?
指针 就可读性而言,代码用了所有需要使用的指针变量吗?
指针 链表中的指针是按正确的顺序加以释放吗?
指针 程序分配了一片保留的内存后备区域,以便在耗尽内存的时候能够优雅地退出吗?
指针 是不是在没有其他方法可用的情况下最终才使用指针的?

组织直线型代码

类别 检查项
依赖关系呈现 代码使得语句之间的依赖关系变得明显吗?
依赖关系呈现 子程序的名字使得依赖关系变得明显吗?
依赖关系呈现 子程序的参数使得依赖关系变得明显吗?
依赖关系说明 如果依赖关系不明确,你是否用注释进行了说明?
顺序依赖检查 你用“内务管理变量 ”(housekeeping variables ) 来检查代码中关键位置的顺序依赖关系了吗?
代码可读性 代码容易按照自上而下的顺序阅读吗?
语句组织 相关的语句被组织在一起吗?
语句组处理 把相对独立的语句组放进各自的子程序里吗?

使用条件语句

语句类型 检查项
if - then 语句 代码的正常路径清晰吗?
if - then 语句 if - then 测试对等最分支的处理方式正确吗?
if - then 语句 使用了 else 子句并加以说明吗?
if - then 语句 else 子句用得对吗?
if - then 语句 用对了 if 和 else 子句,即没把它们用反吗?
if - then 语句 需要执行的正常情况是位于 if 而不是 else 子句里吗?
if - then - else - if 语句串 把复杂的判断封装到布尔函数调用里了吗?
if - then - else - if 语句串 先判断最常见的情况了吗?
if - then - else - if 语句串 判断包含所有的情况吗?
if - then - else - if 语句串 if - then - else - if 是最佳的实现吗?比 case 语句还要好吗?
case 语句 case 子句排序得有意义吗?
case 语句 每种情况的操作简单吗?必要的时候调用了其他子程序吗?
case 语句 case 语句检测的是一个真实的变量,而不是一个只为了滥用 case 语句而刻意制造变量吗?
case 语句 默认子句用得合法吗?
case 语句 用默认子句来检测和报告意料之外的情况了吗?
case 语句 在 C 、 C++ 或者 Java 里,每一个 case 的末尾都有一个 break 吗?

循环

这个表格已经清晰地呈现了不同语句类型对应的检查项。如果想要进一步优化格式,增强其美观性与易读性,可以做一些微调,比如增加表头的样式、对语句类型进行适当的强调等,以下是优化后的表格:

语句类型 检查项
if - then 语句 代码的正常路径清晰吗?
if - then 测试对等最分支的处理方式正确吗?
使用了 else 子句并加以说明吗?
else 子句用得对吗?
用对了 if 和 else 子句,即没把它们用反吗?
需要执行的正常情况是位于 if 而不是 else 子句里吗?
if - then - else - if 语句串 把复杂的判断封装到布尔函数调用里了吗?
先判断最常见的情况了吗?
判断包含所有的情况吗?
if - then - else - if 是最佳的实现吗?比 case 语句还要好吗?
case 语句 case 子句排序得有意义吗?
每种情况的操作简单吗?必要的时候调用了其他子程序吗?
case 语句检测的是一个真实的变量,而不是一个只为了滥用 case 语句而刻意制造变量吗?
默认子句用得合法吗?
用默认子句来检测和报告意料之外的情况了吗?
在 C 、 C++ 或者 Java 里,每一个 case 的末尾都有一个 break 吗?

不常见的控制结构

语句类型 检查项
return 每一个子程序都仅在有必要的时候才使用 return 吗?
return 使用 return 有助于增强可读性吗?
递归 递归子程序中包含了停止递归的代码吗?
递归 子程序用安全计数器来确保该子程序能停下来吗?
递归 递归只位于一个子程序里面吗?
递归 子程序的递归深度处于程序栈容量可以满足的限度内吗?
递归 递归是实现子程序的最佳方法吗?它要好于简单的迭代吗?
goto 是否只有在万不得已的时候才使用 goto? 如果用了 goto, 是否仅仅是出于增强可读性和可维护性呢?
goto 如果是出于效率因素而使用的 goto, 那么对这种效率上的提升做出衡量并且加以说明了吗?
goto 一个子程序里最多只用了一个 goto 标号吗?
goto 所有的 goto 都向前跳转,而不是向后跳转吗?
goto 所有的 goto 标号都用到了吗?

表驱动法

类别 检查项
表驱动法应用考量 你考虑过把表驱动法作为复杂逻辑的替换方案吗?
表驱动法应用考量 你考虑过把表驱动法作为复杂继承结构的替换方案吗?
表驱动法数据处理 你考虑过把表数据存储在外部并在运行期间读入,以便在不修改代码的情况下就可以改变这些数据吗?
表驱动法访问优化 如果无法用一种简单的数组索引(像 age 示例中那样)去访问表,那么你把计算访问键值的功能提取成单独的子程序,而不是在代码中重复地计算键值吗?

控制结构相关事宜

类别 检查项
布尔值使用 表达式中用的是 true 和 false, 而不是 1 和 0 吗?
布尔值比较 布尔值和 true 以及 false 做比较是隐式进行的吗?
数值比较 对数值做比较是显式进行的吗?
表达式简化 有没有通过增加新的布尔变量、使用布尔函数和决策表来简化表达式?
布尔表达式形式 布尔表达式是用肯定形式表达的吗?
括号使用 括号配对吗?
括号使用 在需要用括号来明确的地方都使用了括号吗?
逻辑表达式 把逻辑表达式全括起来了吗?
判断顺序 判断是按照数轴顺序编写的吗?
Java 判断方式 如果适当的话, Java 中的判断用的是 a.equals(b)方式,而没有用 a==b 方式吗?
空语句 空语句表述得明显吗?
嵌套语句简化 用重新判断部分条件、转换成 if - then - else 或者 case 语句、把嵌套代码提取成单独的子程序、换用一种更面向对象的设计或者其他的改进方法来简化嵌套语句了吗?
决策点数量 如果一个子程序的决策点超过 10 个,那么能提出不重新设计的理由吗?

质量保证计划

类别 检查项
质量特性认知 是否确定出对项目至关重要的特定质量特性了?
质量目标传达 是否让其他人意识到项目的质量目标了?
质量特性区分 是否能够区分质量的外在特性和内在特性?
特性关系考量 是否考虑过某些特性与其他特性相互制约或相互促进的具体方式?
错误检测规划 在软件开发的每一个阶段,项目是否要求针对不同错误类型使用不同的错误检测技术?
质量保证计划 项目计划中是否有计划有步骤地保证了软件在开发各阶段的质量?
质量评估 是否使用了某种质量评估方法,并由此确定质量是改善了还是下降了?
成本认知 管理层是否能理解为了质量保证在前期消耗额外成本,目的就是在项目后期减少成本?

有效的结对编程

类别 检查项
编码规范 是否已经有一个编码规范,以便让程序员始终把精力集中到编程,而不是编码风格的讨论上?
结对编程参与度 结对的双方是否都积极地参与?
结对编程应用合理性 是否避免了滥用结对编程,而是选择那些能够从中获得好处的工作进行结对编程?
人员与任务轮换 是否有规律地对人员和工作任务进行轮换?
结对组合匹配度 结对组合是否在开发速度和个性方面互相匹配?
项目管理与沟通 是否有一个组长专注于项目管理以及与项目外其他人的沟通?

有效的详查

类别 检查项
核对表使用 你是否有一个核对表,能让评论员将注意力集中于曾经发生过问题的领域?
详查目的 你是否专注于找出错误,而不是修正它们?
准备引导 你是否考虑制定某些视角或者场景,以帮助评论员在准备工作的时候集中注意力?
准备时间 你是否给予评论员足够的时间在详查会议之前进行准备,是否每一个人都做了准备?
角色分配 是否每一个参与者都扮演一个明确的角色——主持人、评论员及记录员等?
会议效率 会议是否以某种高效的速度进行?
会议时长 会议是否限制在两个小时以内?
培训情况 是否所有详查会议的参与者都接受了如何进行详查的针对性培训,是否主持人接受了有关主持技巧方面的针对性培训?
错误数据收集 是否将每次详查所发现的错误数据都收集起来,使你能调整本组织以后使用的核对表?
速度数据收集 是否收集了准备速度和详查速度方面的数据,以便你去优化以后的准备和详查工作?
活动跟进 是否每次详查中被指派下去的活动都被正确跟进了,无论是通过主持人自己还是一次重新详查?
管理层参与 管理层是否理解他们不应该参与详查会议?
修正跟进 是否有一个用于保证修正正确性的跟进计划?

测试用例

测试相关检查 检查项
需求覆盖测试 类和子程序所对应的每一项需求是否都有相应的测试用例?
设计元素测试 类和子程序所对应的每一个设计元素是否都有相应的测试用例?
代码覆盖测试 每行代码是否被至少一个测试用例所测试?你是否通过计算测试到每行代码所需的最少测试用例数量来验证这一点?
路径覆盖测试 所有已定义-已使用路径是否至少被一个测试用例测试过了?
异常数据流测试 是否测试过那些不太可能正确的数据流模式,例如已定义-已定义、已定义-已退出以及已定义-己销毁?
常见错误测试 是否有一张常见错误列表,并据此编写测试用例以检测过去经常出现的错误?
简单边界测试 所有的简单边界是否都已经测试过了:最大、最小以及 off - by - one?
组合边界测试 是否测试了组合边界——即,多个输入数据的组合导致输出数据过小或者过大?
数据类型错误测试 测试用例是否检查了数据类型错误,例如一个薪水记账程序里的雇员数量是负数?
典型数值测试 是否测试了那些中规中矩的典型数值?
最小正常形式测试 是否测试了最小正常形式?
最大正常形式测试 是否测试了最大正常形式?
兼容性测试 是否检查了与旧数据的兼容性?以及是否对旧硬件、旧操作系统版本以及其他旧版本软件的接口进行了测试?
测试用例可检验性 测试用例是否容易手工检验?

关于调试的建议

调试相关类别 检查项
寻找缺陷的方法 使用所有可用数据来构造你的假设。
寻找缺陷的方法 不断提炼产生错误的测试用例。
寻找缺陷的方法 在自己的单元测试族中测试代码。
寻找缺陷的方法 借助可以获得的任何工具。
寻找缺陷的方法 用不同的方式重现错误。
寻找缺陷的方法 通过产生更多的数据来构造更多的假设。
寻找缺陷的方法 利用证伪假设的测试结果。
寻找缺陷的方法 用头脑风暴的方式找出可能的假设。
寻找缺陷的方法 在桌上放一个记事本,把需要尝试的事情列出来。
寻找缺陷的方法 缩小被怀疑有问题的代码区域。
寻找缺陷的方法 对之前出现过问题的类和子程序保持警惕。
寻找缺陷的方法 检查最近修改的代码。
寻找缺陷的方法 扩展被怀疑有问题的代码区域。
寻找缺陷的方法 采用增量集成。
寻找缺陷的方法 检查常见的缺陷。
寻找缺陷的方法 和其他人一起讨论你的问题。
寻找缺陷的方法 抛开问题休息一下。
寻找缺陷的方法 在使用快速肮脏调试法的时候,要设置一个时间上限。
寻找缺陷的方法 列出所有的蛮力调试方法,逐条应用。
解决语法错误的方法 不要太信任编译器信息中给出的行号。
解决语法错误的方法 不要太信任编译器信息。
解决语法错误的方法 不要太信任编译器所给出的第二条出错信息。
解决语法错误的方法 分而治之,各个击破。
解决语法错误的方法 使用具有语法分析功能的编辑器来找出位置错误的注释和引号。
修正缺陷的方法 在动手之前先理解程序。
修正缺陷的方法 理解整个程序而非具体问题。
修正缺陷的方法 验证对错误的分析。
修正缺陷的方法 放松一下。
修正缺陷的方法 要保存最初的源代码。
修正缺陷的方法 治本,而非治标。
修正缺陷的方法 只有当理由充分的时候才去修改代码。
修正缺陷的方法 一次只做一个改动。
修正缺陷的方法 检查自己所做的修订。
修正缺陷的方法 添加单元测试来暴露代码中的缺陷。
修正缺陷的方法 找出类似的缺陷。
调试的一般方法 你是否会把调试看做是能让你更好地理解程序、错误、代码质量和解决问题方法的良机?
调试的一般方法 你是否会避免采用随机尝试查找错误或迷信式的调试方法?
调试的一般方法 你是否假设错误是你自己造成的?
调试的一般方法 你是否使用了科学的方法将间歇性的错误稳定下来?
调试的一般方法 你是否使用了科学的方法来寻找缺陷?
调试的一般方法 你在寻找缺陷的时候会使用多种不同的方法么?还是每次都是用相同的方法?
调试的一般方法 你会验证你的修改是否正确么?
调试的一般方法 你会在调试中使用编译器警告信息、执行性能分析、利用测试框架和交互式调试方法么?

重构的理由

潜在代码问题类型 检查项
代码复用问题 代码重复。
子程序设计问题 子程序太长。
循环结构问题 循环太长或者嵌套太深。
类设计问题 类的内聚性太差。
类接口问题 类的接口的抽象层次不一致。
参数设计问题 参数表中参数太多。
类内部修改问题 类的内部修改往往局限于某个部分。
多类修改问题 需要对多个类进行并行修改。
继承体系修改问题 对继承体系的并行修改。
case语句修改问题 需要对多个 case 语句进行并行修改。
数据组织问题 相关的数据项只是被放在一起,没有组织到类中。
成员函数使用问题 成员函数更多地使用了其他类的功能,而非自身类的。
数据类型依赖问题 过于依赖基本数据类型。
类功能问题 一个类不做什么事。
子程序数据传递问题 连串传递流浪数据的子程序。
中间人对象问题 中间人对象什么也不干。
类关系问题 某个类同其他类关系过于密切。
子程序命名问题 子程序的命名太差。
数据成员访问问题 数据成员被设置为公用。
派生类使用问题 派生类仅仅使用了基类的一小部分成员函数。
注释使用问题 用注释来掩饰拙劣的代码。
全局变量使用问题 使用了全局变量。
子程序调用问题 在子程序调用前使用设置代码,调用后使用收尾代码。
代码冗余问题 程序包含的某些代码似乎在将来某个时候才会被用到。

重构总结

重构级别 检查项
数据级的重构 用具名常量来代替神秘数值。
数据级的重构 用更明确或更具信息量的名字来重命名变量。
数据级的重构 将表达式内联化。
数据级的重构 用函数来代替表达式。
数据级的重构 引入中间变量。
数据级的重构 将多用途变量转换为多个单一用途变量。
数据级的重构 使用局部变量实现局部用途而不是使用参数。
数据级的重构 将基础数据类型转化为类。
数据级的重构 将一组类型码转化为类或是枚举类型。
数据级的重构 将一组类型码转化为含派生类的类。
数据级的重构 将数组转化为对象。
数据级的重构 封装群集。
数据级的重构 用数据类替代传统记录。
语句级的重构 分解布尔表达式。
语句级的重构 将复杂的的布尔表达式转换为命名精确的布尔函数。
语句级的重构 将条件语句中不同部分中的重复代码合并。
语句级的重构 使用 break 或 return 而不是循环控制变量。
语句级的重构 在嵌套的 if - then - else 语句中一旦知道结果就立刻退出,而不是仅仅赋一个返回值。
语句级的重构 用多态来代替条件语句(尤其是重复的 case 语句)。
语句级的重构 创建并使用空对象代替对空值的检测。
子程序级的重构 提取子程序。
子程序级的重构 将子程序代码内联化。
子程序级的重构 将冗长的子程序转化为类。
子程序级的重构 用简单的算法替代复杂算法。
子程序级的重构 增加参数。
子程序级的重构 减少参数。
子程序级的重构 将查询操作同修改操作区分开来。
子程序级的重构 合并功能相似的子程序,并用参数来区分他们。
子程序级的重构 通过传递不同的参数使子程序体现不同的功能。
子程序级的重构 传递整个对象而非特定成员。
子程序级的重构 传递特定成员而非整个对象。
子程序级的重构 封装向下转型操作。
类实现的重构 将值对象改为引用对象。
类实现的重构 将引用对象改为值对象。
类实现的重构 用数据初始化来代替虚函数。
类实现的重构 改变成员函数或数据的位置。
类实现的重构 将特定代码提出生成派生类。
类实现的重构 将相似的代码合并起来放到基类中。
类接口的重构 将某成员子程序放到另一个类中。
类接口的重构 将一个类转化成两个。
类接口的重构 删除某个类。
类接口的重构 隐藏委托关系。
类接口的重构 去掉中间人。
类接口的重构 用委托代替继承。
类接口的重构 用继承代替委托。
类接口的重构 引入外部子程序。
类接口的重构 引入扩展类。
类接口的重构 封装暴露在外的成员变量。
类接口的重构 对不能修改的成员去掉 Set( )函数。
类接口的重构 隐藏在类的外部不会使用的成员函数。
类接口的重构 封装不会用到的成员函数。
类接口的重构 如果基类和派生类的代码实现相似,将二者合并。
系统级的重构 为无法控制的数据创建明确的索引源。
系统级的重构 将单向类联系改为双向类联系。
系统级的重构 将双向的类联系改为单向类联系。
系统级的重构 使用工厂函数而非简单的构造函数。
系统级的重构 用异常代替错误代码,或者反其道而行之。

安全的重构

重构相关检查 检查项
改变策略 每一改变都是系统改变策略的一部分么?
代码保存 在重构之前,你保存了初始代码了么?
重构步伐 你是否保持较小的重构步伐?
重构数量 你是否同一时间只处理一项重构?
任务记录 在重构时你是否把要做的事情一条条列了出来?
想法记录 你是否设置了一个停车场,把你在重构时所想到的任何东西记下来?
测试环节 在每次重构后你会重新测试么?
修改检查 如果所做的修改非常复杂,或者影响到了关键代码,你会重新检查这些修改么?
风险考量 你是否考虑过特定重构的风险,并以此来调整你的重构方法?
质量影响 你所做的修改是提升还是降低了程序的内在质量?
重构目的 你是否避免了将重构作为先写后改的代名词,或者作为拒绝重写拙劣代码的托词?

代码调整策略

性能优化相关类别 检查项
程序整体性能 你是否考虑通过修改需求来提高性能?
程序整体性能 你是否考虑通过修改程序的设计来提高性能?
程序整体性能 你是否考虑通过修改类的设计来提高性能?
程序整体性能 你是否考虑过减少程序同操作系统的交互从而提高性能?
程序整体性能 是否考虑过避免 I/O 操作以提高性能?
程序整体性能 是否考虑使用编译型语言替代解释型语言以提高性能?
程序整体性能 是否考虑过使用编译器优化选项来提高性能?
程序整体性能 是否考虑过使用不同的硬件来提高性能?
程序整体性能 是否仅仅将代码调整看做是解决问题的最后一招?
代码调整方法 在开始调整代码之前,程序是完全正确的么?
代码调整方法 在调整之前是否测量过性能瓶颈在什么地方?
代码调整方法 是否记录了每一次修改所产生的效果?
代码调整方法 如果没有带来预期的性能提高,你是否放弃了所做的代码调整改变?
代码调整方法 你是否对每一个性能瓶颈进行不止一次的修改尝试——也就是说,你是在反复进行代码调整么?

代码调整方法

优化目标 检查项
同时改善代码执行速度和规模 用查询表替换复杂逻辑。
同时改善代码执行速度和规模 合并循环。
同时改善代码执行速度和规模 使用整型变量而非浮点变量。
同时改善代码执行速度和规模 在编译时初始化数据。
同时改善代码执行速度和规模 使用正确的常量类型。
同时改善代码执行速度和规模 预先计算结果。
同时改善代码执行速度和规模 删除公共子表达式。
同时改善代码执行速度和规模 只将关键子程序代码转化为某种低级语言代码。
仅仅提高代码执行速度 在知道答案后就停止执行判断。
仅仅提高代码执行速度 根据各种情况的出现频率对 case 语句和 if - then - else 串排序。
仅仅提高代码执行速度 比较相似逻辑结构的性能。
仅仅提高代码执行速度 使用惰性求值。
仅仅提高代码执行速度 将循环中的 if 判断转到外部。
仅仅提高代码执行速度 展开循环。
仅仅提高代码执行速度 将循环内部所做的工作减少到最低限度。
仅仅提高代码执行速度 在查找循环中使用哨兵。
仅仅提高代码执行速度 把执行最为频繁的循环放在嵌套循环的最里面。
仅仅提高代码执行速度 减轻内层循环的强度。
仅仅提高代码执行速度 将多维数组改为一维数组。
仅仅提高代码执行速度 最大限度减少数组索引。
仅仅提高代码执行速度 为数据类型扩充索引。
仅仅提高代码执行速度 对频繁使用的值进行缓存。
仅仅提高代码执行速度 利用代数恒等式。
仅仅提高代码执行速度 降低逻辑和数学表达式的强度。
仅仅提高代码执行速度 注意系统调用。
仅仅提高代码执行速度 用内联子程序重写代码。

配置管理

软件配置管理方面 检查项
概要 你的软件配置管理计划是否用于帮助程序员,并能将额外负担降至最低?
概要 你的软件配置管理方法是否避免了对项目的过度控制?
概要 你是否将一些变更请求聚成一组?无论采用非正式的方法(如创建一份未决更改的列表)还是更加系统的方法(如设立变更控制委员会)。
概要 你系统地评估了每一项提交的更改对成本、计划和质量的影响吗?
概要 你是否把重大的变更看做是需求分析还不够完备的警报信号?
工具 你用版本控制软件来促进配置管理吗?
工具 你用版本控制软件来减少团队工作中的协调问题吗?
备份 你定期地备份项目中的所有资料吗?
备份 你定期地把项目备份数据转移到 off - site storage 里了吗?
备份 所有的资料,包括源代码、文档、图表和重要的笔记都得到备份了吗?
备份 你测试过备份与恢复的过程吗?

集成

类别 检查项
集成策略 该策略是否指明了集成子系统、类、子程序时应该采用的最优顺序?
集成策略 集成的顺序是否与构建顺序协调,以便在适当的时候准备好供集成的类?
集成策略 该策略是否易于诊断缺陷?
集成策略 该策略是否使脚手架最少?
集成策略 所选的策略是否好于其他方式?
集成策略 组件之间的接口是否有明确定义? (定义接口不是集成的任务,但要验证这些接口的定义是否明确。)
Daily build与冒烟测试 项目是否经常build — 理想情况下,每天build一次 — 以支持增量集成?
Daily build与冒烟测试 每次build后是否都运行冒烟测试,让你知道这个build能否工作?
Daily build与冒烟测试 你是否已使build和冒烟测试自动进行?
Daily build与冒烟测试 开发人员是否频繁地check in他们的代码 — 两次check in之间最多间隔一两天?
Daily build与冒烟测试 冒烟测试是否与代码同步更新,随代码发展而发展?
Daily build与冒烟测试 破坏build是罕见事件吗?
Daily build与冒烟测试 是否在有压力的情况下,也对软件进行build和冒烟测试?

编程工具

工具使用相关 检查项
IDE情况 你有一套有效的 IDE 吗?
IDE功能集成 你的 IDE 集成了源代码控制、 build/测试/除错工具,以及其他有用的功能吗?
重构工具 你有能自动进行常用的重构操作的工具吗?
版本控制 你是否使用版本控制工具,对源代码、内容、需求、设计、项目计划及其他的项目构件进行管理?
大型项目工具 如果你正面对超大型的项目,你是否使用了数据字典或者其他“包含系统中使用的各个类的权威描述"的中央知识库?
代码库利用 当可以用到代码库时,你是否考虑用它来代替“编写定制代码”?
除错器使用 你是否充分利用了交互式除错器?
依赖关系控制 你是否使用 make 或其他“依赖关系控制软件”,用来高效并可靠地 build 程序?
测试环境工具 你的测试环境包含有自动化的测试框架、自动测试生成器、覆盖率监视器、系统扰动器、 diff 工具,以及缺陷跟踪软件吗?
定制工具 你有没有制造过定制工具——能满足特定项目的需求的那种,特别是能自动执行重复任务的工具?
整体工具效益 总而言之,你的工作环境有没有从“充足的工具支援"中获益?

布局

布局类别 检查项
一般问题 格式化主要是为了展现代码的逻辑结构吗?
一般问题 你的布局方案能统一地运用吗?
一般问题 你的布局方案能让代码易于维护吗?
一般问题 你的布局方案是否有利于代码的可读性?
控制结构的布局 你的代码中避免 begin - end 对或{}的双重缩进了吗?
控制结构的布局 相邻的块之间用空行分隔了吗?
控制结构的布局 对复杂表达式格式化时考虑到可读性吗?
控制结构的布局 对只有一条语句的块的布局始终如一吗?
控制结构的布局 case 语句与其他控制结构的格式化保持一致了吗?
控制结构的布局 对 goto 语句的格式化是否让其显眼了呢?
单条语句的布局 为逻辑表达式、数组下标和子程序参数的可读性而使用空格了吗?
单条语句的布局 不完整的语句在行末是以明显有错的方式结束吗?
单条语句的布局 后续行按照标准数目缩进了吗?
单条语句的布局 每行顶多只有一条语句吗?
单条语句的布局 所写的每个语句都没有副作用吗?
单条语句的布局 每行顶多只声明一个数据吗?
注释的布局 注释与其所注释的代码的缩进量相同吗?
注释的布局 注释的风格便于维护吗?
子程序的布局 你对每个子程序参数的格式化方式便于看懂、修改、注释吗?
子程序的布局 采用空行分隔子程序的各部分了吗?
类、文件和程序的布局 多数类和文件之间是一一对应的关系吗?
类、文件和程序的布局 如果文件内有多个类,各类中的子程序按类分组了吗?各类都清楚标识了吗?
类、文件和程序的布局 文件中的子程序用空行清楚地分开了吗?
类、文件和程序的布局 在没有更好的组织形式的场合,所有子程序都按字母顺序排列了吗?

自说明代码

代码审查维度 检查项
你的类接口体现出某种一致的抽象吗?
你的类名有意义吗,能表明其中心意图吗?
你的类接口对于如何使用该类显而易见吗?
你的类接口能抽象到不需考虑其实现过程吗?能把类看成是黑盒吗?
子程序 你的每个子程序名都能准确地指示该子程序确切干些什么吗?
子程序 你的各子程序的任务明确吗?
子程序 若各子程序中自成一体后更有用,你都将其各自独立出来了吗?
子程序 每个子程序的接口都清晰明了吗?
数据名 类型名描述有助于说明数据声明吗?
数据名 你的变量名有意义吗?
数据名 变量只用在其名字所代表意义的场合吗?
数据名 你的循环变量名能给出更多信息,而不是 i、j、k 之类的吗?
数据名 你用了名字有意义的枚举类型,而非临时拼凑的标识或者布尔变量吗?
数据名 用具名常量代替神秘数值或者字符串了吗?
数据名 你的命名规范能区分类型名、枚举类型、具名常量、局部变量、类变量以及全局变量吗?
数据组织 你根据编程清晰的需要,使用了额外变量来提高清晰度吗?
数据组织 你对某变量的引用集中吗?
数据组织 数据类型简化到了最低复杂度吗?
数据组织 你是通过抽象访问子程序(抽象数据类型)来访问复杂数据吗?
控制 代码中的正常执行路径很清晰吗?
控制 相关语句放在一起了吗?
控制 相对独立的语句组打包为子程序了吗?
控制 正常情况的处理位于 if 语句之后,而非在 else 子句中吗?
控制 控制结构简单明了,以使复杂度最低吗?
控制 每个循环完成且仅完成一个功能,是像定义良好的子程序那么做吗?
控制 嵌套层次是最少吗?
控制 逻辑表达式通过额外添加布尔变量、布尔函数和功能表简化了吗?
布局 程序的布局能表现出其逻辑结构吗?
设计 代码直截了当吗?是不是避免了自作聪明或新花样?
设计 实现细节尽可能隐藏了吗?
设计 程序是尽可能采用问题领域的术语,而非按照计算机科学或者编程语言的术语编写的吗?

好的注释技术

注释审查维度 检查项
一般问题 别人拿起你的代码就能立刻明白其意吗?
一般问题 你的注释是在解释代码用意,或概括代码在做什么,而非简单重复代码吗?
一般问题 采用了伪代码编程法来减少注释时间吗?
一般问题 是重写有玄机的代码,而非为其做注释吗?
一般问题 你的注释能否同代码一起更新?
一般问题 注释清楚正确吗?
一般问题 你的注释风格便于修改注释吗?
语句和段落 代码避免用行尾注释了吗?
语句和段落 注释是着力说明为什么而非怎么样吗?
语句和段落 注释为将要阅读代码的人们做好准备了吗?
语句和段落 每个注释都有其用处吗?删掉抑或改进了多余的、无关紧要的或随意的注释没有?
语句和段落 是否注释了代码的非常规之处?
语句和段落 避免使用缩略语了吗?
语句和段落 主次注释区别明显吗?
语句和段落 含错代码和未公开的代码特性有注释吗?
数据声明 对数据声明的注释说明了数值单位吗?
数据声明 数值数据的取值范围注释出来了吗?
数据声明 注释出了编码含义吗?
数据声明 对输入数据的限制有注释吗?
数据声明 对位标志做注释了吗?
数据声明 在各全局变量声明的地方对其做注释了吗?
数据声明 各全局变量是通过命名规范、注释(或者两者兼用)来标识其意义吗?
数据声明 神秘数值是否以具名常量或变量代替,而非只是标注之?
控制结构 控制语句都注释了吗?
控制结构 冗长或者复杂的控制结构结尾处有注释吗?抑或可能的话,简化之从而省去注释了吗?
子程序 各子程序的意图都注释出了吗?
子程序 子程序的其他有关情况(诸如输入输出数据、接口假设、局限性、纠错、全局效果和算法来源)都注释出来了吗?
文件、类和程序 程序有简短的文档(就像在“以书本为范例”中说明的那样)给出程序组织的概述吗?
文件、类和程序 每个文件的用途都有说明吗?
文件、类和程序 作者姓名、email及电话号码在代码清单中都有吗?
posted @   荣--  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
点击右上角即可分享
微信分享提示