跳转至

📔 Part I : Laying the Foundation 学习笔记

Chapter 01 欢迎进入软件构件的世界

1. 什么是软件构建?

软件开发的过程是复杂的,所以一般在软件开发过程中,都有一些特定的构建活动:

  • 定义问题(problem definition)
  • 需求分析(requirements development)
  • 规划构建(constructions planning)
  • 软件架构(software architecture)或者高层设计(high-level design)
  • 详细设计(detailed design)
  • 编码与调试(coding and debugging)
  • 单元测试(unit testing)
  • 集成测试(integration testing)
  • 集成(integration)
  • 系统测试(system testing)
  • 保障维护(corrective maintenance)

同时也包含了一些重要的非构建活动:管理、需求分析、软件架构设计、用户界面设计、系统测试以及维护。

2. 软件构建的重要性?

软件构建的目的是提高软件质量和开发者的生产率。

  • 构建活动是软件开发的主要组成部分。
  • 构建活动是软件开发中的核心部分。
    • 需求分析和架构设计就是构建活动的基础工作。便于后期系统测试时验证构建的准确性。
  • 把主要精力集中在构建活动中,可以大大提高程序员的生产率。
  • 构建活动的产物 --- 源代码 --- 往往是对软件的唯一精确描述。
  • 构建活动是唯一一项确保会完成的工作。
    • 便于后期优化改进的一种方式。

构建活动的质量也会影响到软件的质量。

Chapter 02 用隐喻来更充分理解软件开发

隐喻描述了软件领域中各种特定的现象或者事物。便于去理解软件开发的过程。

1. 隐喻的重要性

通过类比的联系方式,将抽象不理解的变成可理解的东西,这种使用隐喻的方式叫做 建模

2. 如何使用软件隐喻?

隐喻的作用是启示(heuristic,启发、试探法),而不是算法。

  • 算法:
    • 算法是一套定义明确的指令,使得可以完成某个特定的任务。
    • 算法是可预测的、确定性的、不易变化的。
  • 启发式方法(试探法)
    • 帮助寻求答案的技术,但给出的答案具有偶然性。
    • 只告知你如何去找,而不告知具体找什么。

对于隐喻的使用:

  • 提高对编程问题和编程过程的洞察力。
  • 帮助思考编程过程中的活动。
  • 想象出更好的做事情的方法。

3. 常见的软件隐喻

  • 软件开发中最原始的隐喻就是:写代码。
  • 软件的耕作方法:培植系统

    • 通过写一段代码,就做一点测试,将代码集成到一整个系统中,通过小步前进的方式,将麻烦降到最小。
    • 存在缺点:暗示人无法对开发软件的过程和方式进行任何直接的控制。
  • 软件的牡蛎养殖观点:系统生长

    • 通过增量式进行设计、编译和测试,也是目前已知最强有力的软件开发概念。
    • 先做出简单可运行的软件系统版本,然后进行增量式开发。
  • 软件构建:构建软件

    • 对于大型的软件项目,需要高级别对的规划设计
    • 考虑成本,尽量使用现成的,而不是自己去“造轮子”。
    • 不要精心计划。非过度计划。可以把支撑结构规划清楚即可。
    • 对于不同的项目来说,需要不同的方法使其效益化。
    • 不同项目的部分进行结构性的修改成本不同。
  • 应用软件技术:智慧工具箱

    • 技术、技巧和诀窍的积累,可以有效开发高质量软件。
    • 不存在适合所有工作的任何一个工具,而是因地制宜去选择工具,从而使其成为有效编程的最佳工具。
  • 组合各个隐喻

Chapter 03 前期准备

  • 在构建活动开始之前,准备工作要做周全。

  • 软件开发中的构建部分,也应该是三思而后行(Measure twice,cut once)。

在前期准备工作中的几个主要的构建活动如下:

  • 定义问题
  • 需求分析
  • 软件架构

1. 前期准备的重要性

高质量的实践方法在软件项目的初期、中期、末期都在强调质量。对于不同的阶段来说,每个阶段要求的质量不同,从而需要做的准备工作也不同。

  • 前期
    • 需要计划、要求设计出一个高质量的产品。
    • 定义问题、定下解决方案、设计解决方案等。
  • 中期

    • 前期工作已被打下基础工作,此时可明辨当前形势。
    • 此时强调构建实践。
  • 末期

    • 主要强调系统测试,是软件质量保证的阶段。
    • 测试只是质量保证策略之一。

1.1 前期准备是否适用于现代软件项目?

  • 前期准备工作的目的是降低风险。

    • 消除潜藏的风险,保证大部分的工作顺利平稳进行。
  • 前期准备要根据项目的特点来选择特定的风险规避方法。

1.2 准备不周全的诱因

  • 造成准备工作不充分的一个常见原因:分配去做前期准备活动的开发人员不具备完成这一任务的专业技能。

    • 当开发人员不知道如何进行这些前期工作的时候,建议“做更多的前期工作”就完全没有用;如果不能首先把这项工作做好,那么做再多也没有意义!
  • 最后一个原因:管理者们对那些“花时间进行构建活动的前期淮备的程序员”的冷漠已经到了人神共愤的程度。

1.3 在开始构建之前要做前期准备的强有力且简明的论据

  • 诉诸逻辑

    • 管理角度:做计划意味着确定项目所需要用的时间、人力等。
    • 技术角度:做计划意味着弄清楚想要做的是什么?防止浪费时间和金钱,避免走进死胡同。
  • 诉诸类比

    • 建造软件系统和其它阿护肺人力财力的项目是类似的。
    • 开始构建活动之前,需要针对每一部分,弄清楚哪些是最关键的需求和架构要素。
    • 做好准备工作,隐患存在会导致后续顺序存在错误。
  • 诉诸数据

    • 在构建活动开始之前清除一个错误,则返工的成本是“在开发过程的最后阶段(在系统测试期间或者发布之后)做同样的事情”的十分之一到百分之一。
    • 发现错误的时间要尽可能接近引入该错误的时间
    • 修复缺陷的成本随着“从引入缺陷到检测到该缺陷之间的时间”变长而急剧增加。

2. 辨明所从事的软件类型

  • 不同种类的软件项目,需要在“准备工作” 和 “构建活动” 之间做出不同的平衡。

  • 开发商业系统的项目往往受益于 高度迭代 的开发法,该方法的 “计划、需求、架构” 活动 与 “构建、系统测试、质量保证” 活动交织在一起。

  • 性命攸关的系统往往要求采用更加 序列式 的方法 ----- “需求稳定” 是确保 “超高等级的可靠性” 的必备条件之一。

2.1 迭代开发对前期准备的影响

  • 迭代方法往往能够减少 “前期准备不足” 造成的负面影响。但不能完全消除此影响。

对于序列式开发方法和迭代式开发法之间的比较:

  • 序列式开发法

    • 过度依赖于测试,将绝大部份缺陷修复工作推迟到项目快结束的时候进行,会遇到重新设计、重新编码并重新设计的情况,使得成本较高。
  • 迭代式开发法

    • 迭代方式进行,在项目推进过程中不断找出错误。
    • 分次进行交付,而不会聚集到项目末尾一次性交付,成本控制明显。

无论使用的是迭代式开发法还是序列式开发法,只要进行了 前期准备,就可以减少成本。

绝大多数的项目 都不会 完全使用 序列式开发法 或者完全使用 迭代式开发法

很有用的两种经验方案:

  • 计划好预先对大约80%的需求做出详细说明,并给“稍后再进行详细说明的额外需求”分配一定的时间。然后在项目进行过程中,实施系统化的变更控制错误(只接受最有价值的新需求)。

  • 预先只对20%的需求做出详细说明,并将计划以小幅增量开发软件的剩余部分,随着项目的进行,对额外的需求和设计做出详细说明。

2.2 在序列式开发法和迭代式开发法之间的选择

  • 会让你更加选择 序列化开发法 的原因:

    • 需求相对稳定
    • 设计直截了当、理解透彻
    • 开发团队对这一应用领域非常熟悉
    • 项目的风险很小
    • “长期可预测性” 很重要
    • 后期改变需求、设计、和编码的代价可能较昂贵
  • 会让你更加选择 迭代式开发法 的原因:

    • 需求并没有理解透彻,或者出于其他理由,认为它是不稳定的
    • 设计很复杂或者有挑战性,或者两者都有
    • 开发团队对这一应用领域不熟悉
    • 项目包含许多风险
    • “长期可预测性”不重要
    • 后期改变需求、设计、和编码的代价很可能较低

事实上,在软件开发中,适用迭代式开发法的情况比使用序列式开发法的情况多得多。

3. 问题定义的先决条件

  • 问题定义指的是在开始构建之前,对这个系统要解决的问题做出清楚的陈述。有时也称为“产品设想、产品陈述、产品定义”。

  • 对于 “问题定义” 只定义了 “问题是什么”,而不涉及任何可能的解决方案。

  • 问题定义在具体的需求分析工作之前,而需求分析是对所定义的问题的深入调查。

    • 应该站在客户角度的语言来写,从客户的角度来描述问题。
    • 如果是计算机的角度,则直接使用计算机的专业术语描述即可。

对于未能定义问题,则会浪费时间去解决错误的问题。

4. 需求的先决条件

“需求” 详细描述软件系统应该做什么,这是达成解决方案的第一步。

需求活动有时也叫做“需求开发、需求分析、需求定义、规格书”等。

4.1 为什么要有正式的需求?

明确需求的好处:

  • 有助于确保是用户(而不是程序员)驾驭系统的功能。

    • 用户自行评审,并进行核准。
    • 避免程序员去猜测用户想要的的是什么。
  • 避免争论。

    • 范围明确,意见不一致时,可直接查看书面需求。
  • 有助于减少开始编程开发之后的系统变更情况。

    • 代码上错误,可以直接通过修改几行即可。
    • 需求上的错误,则可能需要改变之前的设计,使之符合更改后的需求。

充分详尽地描述需求,则是项目成功的关键。甚至可能比有效的构建技术更加重要。

如果没有好的需求,可能会对问题有总体的把握,但是却没有正中问题靶心的特定能力。

4.2 稳定需求的神话

  • 稳定点需求是软件开发的圣杯。一旦需求稳定,项目就能有序、可预测、平稳方式,完成从架构到设计到编码到测试等一系列工作。

  • 永不变更的需求并不存在。

  • 需求变更的主要来源:客户参与项目的时间越长,对项目的理解越深入。

4.3 在构建期间处理需求变更

在构建期间,更好的应对需求变更可采用的方式:

  • 使用需求核对表来评估需求的质量。

  • 确保每一个人都知道需求变更的代价。

  • 建立一套变更控制程序

  • 使用能适应变更的开发方法

  • 放弃这个项目

  • 注意项目的商业案例

4.4 核对表:需求

  • 针对功能需求

    • 是否详细定义了系统的全部输入?是否包括其来源、精度、取值范围、出现频率等。
    • 是否详细定义了系统的全部输出?包括目的地、精度、取值范围、出现频率、格式等?
    • 是否详细定义了所有输出格式?
    • 是否详细定义了所有硬件及软件的外部接口?
    • 是否详细定义了全部外部通信接口,包括握手协议、纠错协议、通信协议等?
    • 是否列出了用户想要做的全部事情?
    • 是否详细定义了每个任务所用的数据,以及每个任务得到的数据?
  • 针对非功能需求(质量需求)

    • 是否为全部必要的操作,从用户的视角,详细描述了期望响应时间?
    • 是否详细描述了其他与计时相关的考虑,例如处理时间,数据传输率,系统吞吐量?
    • 是否详细定义了安全级别?
    • 是否详细定义了可靠性,包括软件失灵的后果,发生故障时需要保护的至关重要的信息、错误检测与恢复的策略等?
    • 是否详细定义了机器内存与剩余磁盘空间的最小值?
    • 是否详细定义了系统的可维护性,包括适应特定功能的变更、操作环境的变更、与其他软件的接口的变更能力?
    • 是否包含对“成功”的定义?“失败”的定义呢?
  • 需求的质量

    • 需求是用用户的语言写的吗?用户是否也是这么认为的?
    • 每条需求都不与其他需求冲突吗?
    • 是否详细定义了相互竞争的特性之间的权衡,例如健壮性与正确性之间的权衡?
    • 是否避免在需求中规定设计(方案)?
    • 需求是否在详细程度上保持相当一致的水平?有些需求应该更详细地描述吗?有些需要是否应该更粗略地描述?
    • 需求是否足够清晰,即使转交给一个独立的小组去构建,也能理解吗?开发者是否也会这么想?
    • 每个条款都与待解决的问题及其解决方案相关吗?能从每个条款上溯到它在问题域中对应的根源吗?
    • 是否每条需求都是可测试的?是否可能进行独立的测试,以检验满不满足各项需求?
    • 是否详细描述了所有可能的对需求的改动?包括各项改动的可能性?
  • 需求的完备性

    • 对于在开始开发之前无法获得的信息,是否详细描述了信息不完全的区域?
    • 需求的完备度是否达到了这种程度,如果产品满足所有需求,那么它是否可被接受?
    • 你对全部需求都感到舒服吗?是否已经去掉那些不可能实现的需求(那些只是为了安抚客户和老板的东西)?

5. 架构的先决条件

  • 软件架构是软件设计的高层部分。用于支持更细节设计的框架。

  • 架构也称为“系统架构、高层设计、顶层设计”。

  • 架构作为前期准备之一的原因:架构的质量决定了系统的“概念完整性”。

  • 好的架构使得构建活动变得容易,糟糕的架构则使构建活动几乎寸步难行。

    • 如果离开了良好的软件架构,可能瞄准了正确的问题,但却使用了错误的解决方案。也许完全不可能有成功的构建。
  • 在构建期间或者更晚时进行架构变更,代价昂贵。

    • 修复软件架构中的错误所需的时间与修复需求错误所需的时间同处于一个数量级。

5.1 架构的典型组成部分

如果自己构建整个系统,则在架构工作会与更详细的设计工作有重叠部分,此时需要思考架构的每个组成部分。

如果目前从事的系统架构是别人做的,则需要找出其中重要的组成部分。

对于两种情况,则需要参考如下的架构组成部分:

  • 程序组织

    • 在系统架构中,首先要以概括的形势对有关系统做一个综述。
      • 如果没有综述,很难将成千的局部图片拼接成一个完整的图。
    • 在架构中,能发现对曾经考虑过的最终组织结构的替代方案的记叙。找到最终选用组织结构,而不是其他替代方案的理由。

      • 如果对某个类在系统中的角色没有一个清晰的构思,那么写这个类就是令人丧气的工作。
    • 架构应该定义程序的主要构造块。

      • 程序规模不同,则各个构造块可能是单个类,也可能是许多类组成的一个子系统。
      • 对于每个构造块无论是一个类还是一组协同工作的类和子程序,都是共同实现一个高层功能。
    • 应该明确定义各个构造块的责任。

      • 将设计信息局限于构造块之内,使之对其他构造块的了解降到最小。
    • 应明确定义每个构造块的通信规则。
      • 明确构造块能直接使用、间接使用、不能使用。
  • 主要的类

    • 架构应该详细定义所用的主要的类。
      • 指出每个主要的类的责任,以及该类如何与其它类交互。
      • 包含对类的继承体系、状态转换、对象持久化等的描述。
      • 注意 80/20准则 :对架构系统80%的行为的20%的类进行详细说明。
      • 遇到已经有过其它的方案设计,给出使用当前架构的理由。
  • 数据设计

    • 架构应该描述用到的主要文件和数据表的设计。
    • 如果描述曾经考虑过的其他方案,则说明并给出选择的理由。
    • 架构应该详细定义所用数据库的高层组织结构和内容。
  • 业务规则

    • 如果架构依赖于特定的业务规则,则应该详细描述规则,并描述规则对系统设计的影响。
  • 用户界面设计

    • 用户界面常常在 需求阶段 进行详细说明。如果没有,则在软件架构中进行详细说明。
    • 架构应该模块化,以便于在替换为新用户界面时不影响业务规则和程序的输出部分。
  • 资源管理

    • 架构应该描述一份管理稀缺资源的计划。稀缺资源包括:数据库连接、线程、句柄等。
    • 在内存受限的应用领域,如驱动程序开发和嵌入式系统中,内存管理是架构应该认真对待的另一个重要领域。
  • 安全性

    • 架构应该描述实现设计层面和代码层面的安全性的方法。
    • 如果先前尚未建立 威胁模型(threat model),那么就应该在架构阶段建立威胁模型。
    • 在制定编码规范的时候应该把安全性牢记在心,包括处理缓冲区的方法、处理非受信(untrudted)数据(用户输入的数据、cookies、配置数据(文件)和其他外部接口输入的数据)的规则、加密、错误消息的细致程度、保护内存中的秘密数据,以及其他事项。
  • 性能

    • 如果需要关注性能,则应该在需求中详细定义性能目标。包括了资源的使用。
    • 架构此时需要提供估计的数据
      • 需要解释说明为什么架构师认为可以达到性能目标。
      • 达不到或者存在风险,则也需要指出。
    • 如果为了满足性能目标,则某些部分使用特定的算法或数据类型,也应该说明。
  • 可伸缩性

    • 可伸缩性是指系统增长以满足未来需求的能力。
  • 互用性

    • 如果遇到系统需要与其它软件或者硬件共享数据或资源,则架构应该描述如何完成。
  • 国际化/本地化

  • 输入/输出

    • 输入输出(I/O)是架构中值得注意的另一个领域。架构应该详细定义读取策略(reading scheme)是先做(look-ahead)、后做(look-behind)还是即时做(just-in-time)。
  • 错误处理

    • 错误处理常被视为“代码约定层次”的事情。
    • 错误处理会影响整个系统,所以在架构层次设计时,需要关注几个问题:
      • 错误处理时进行救助还是仅仅进行检测?
      • 错误检测是主动的还是被动的?
      • 程序如何传播错误?
      • 错误信息的处理有什么约定?
      • 如何处理异常?
      • 在程序中,在什么层次上处理错误?
      • 每个类在验证其输入数据的有效性方面需要负荷何种责任?
      • 希望在运行环境中内建的错误处理机制,还是建立自己的一套机制?
  • 容错性

    • 架构应该详细定义所期望的容错种类。
    • 容错是增强系统可靠性的一组技术。
    • 对于错误,可能的话从错误中恢复,不能的话,则直接包容其不利影响。
    • 对于系统的容错策略有以下几种:
      • 系统在检测到错误的时候退回去,再试一次。
      • 系统拥有一套辅助代码,以备注主代码出错的时候使用。
      • 系统使用一种表决算法。
      • 系统使用某个不会对系统其余部分产生危害的虚假值替代这个错误的值。
  • 架构的可行性

    • 架构应该要论证系统的技术可行性。
    • 如果在任何一个方面不可行都会导致项目无法实施,所以架构需要说明:“这些问题是如何经过研究的”。
  • 过度工程

    • 健壮性是指“系统检测到错误后继续运行”的能力。
    • 架构详细描述的系统会比需求详细描述的系统更健壮。
    • 架构应该清楚地指出程序员应该“为了谨慎起见宁可进行过度过程”,还是应该做出最简单的能工作的东西。
    • 通过在架构中明确地设立期望目标,就能避免出现“某些类异常健壮,而其它类勉强够健壮”的现象。
  • 关于买还是造的决策

    • 最激进的构建软件的解决方案是根本不去构建它——购买软件,或者免费下载开源的软件。
    • 如果架构不采用现货供应的组件,则应该说明“自己定制的组件应该在哪些方面胜过现成的程序库和组建”。
  • 关于复用的决策

    • 如果开发计划提倡使用业已存在的软件、测试用例、数据格式或其他原料,架构应该说明:如果需要使之符合的话,如何对复用的软件进行加工,使之符合其他架构目标。
  • 变更策略

    • 对于程序员和用户来说,构建软件产品是一个学习过程,所以在开发过程中产品都会发生变化。

      • 此时,架构师面临的一个主要挑战:让架构足够灵活,能够适应可能出现的变化。
    • 架构应当清楚地描述处理变更的策略。

      • 架构师应该列出已经考虑过的有可能有所增强的功能,并说明“最有可能的功能同样的也是最容容易实现的”。
    • 架构应该指出 “延迟提交/delay commitment”所用的策略。

5.2 架构的总体质量核对表

  • 针对各架构主题

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

    • 架构是否解决了全部需求?
    • 有没有哪个部分是“过度架构/overarchitected”或“欠架构/underarchitected'?是否明确宣布了在这方面的预期指标?
    • 整个架构是否在概念上协调一致?
    • 顶层设计是否独立于用作实现它的机器和语言?
    • 是否说明了所有主要的决策的动机?
    • 你,作为一名实现该系统的程序员,是否对这个架构感觉良好?

6. 花费在前期准备上的时间长度

  • 花费在问题定义、需求分析、软件架构上的时间,依据项目的需要而变化。

如果需求不稳定,在不同的项目角度上,需要关注点:

  • 大型的正式项目

    • 需要与需求分析师合作,解决构建活动早期指出的需求问题。
  • 小型的非正式项目

    • 可能解决需求方面的问题。
  • 任何项目(不区分正式项目还是非正式项目)

    • 将需求分析工作视为独立的项目来做。
    • 需求完成后,并明确剩下的事情要花多少时间。在弄清楚要做的是什么之前,没人相信能估算出合理的进度表。
    • 在为软件架构分配时间时,要使用与需求分析类似的方法。如果软件是以前没做过的类型,则需要为“在新的领域中做设计”的不确定性预留更多时间。

7. 前期准备的核对表

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

Chapter 04 关键的“构建”决策

1. 选择编程语言

  • 编程语言的选择从多个方面影响生产率和代码质量。

  • 程序员使用熟悉的语言时,生产率比使用不熟悉语言的要高。

  • 使用高级语言的程序员比使用低级语言的程序员达到更好的生产率和质量。

  • 高级语言比低级语言在生产率、可靠性、简洁性、易理解性等方面高5倍至15倍。

  • 高级语言比低级语言的表达力更强,每行代码能表达更多的含义。

  • 编程语言影响程序员的思维。

2. 编程约定

为了 “实现” 必须与 “架构” 保持一致性,则需要变量名称、类的名称、子程序名称、格式约定、注释约定等一些编程约定,才是完成 “构建活动”的构建所在。

  • 架构上的知道方针使得程序的结构平衡,该结构可以统一编程语言的细节。

  • 大型结构的部分在于各个部件都能发映出整体架构的内涵。如果没有统一的规则,则创作出来的东西充斥着各种不同的风格。混乱而邋遢。这些不同的风格,会使大脑承受沉重的负担。

  • 在编写完软件后,几乎不可能改变(翻新)软件所遵循的编码约定。

3. 在技术浪潮中的位置?

  • “你如何面对自己的编程工作”,取决于你在技术浪潮中所处的位置。

  • “深入一种语言去编程”的程序员首先决定他要表达的思想时什么,然后决定如何使用特定语言提供的工具来表达这些思想。

  • 大多数重要的编程原则并不依赖于特定的语言,而依赖于使用语言的方式。

4. 选择主要的构建事件方法

  • 编码

    • 你有没有确定,多少设计工作将要预先进行,多少设计工作在键盘上进行(在编写代码的同时)?
    • 你有没有规定诸如名称、注释、代码格式等“编码约定”?
    • 你有没有规定特定的由软件架构决定的编码实践,比如如何处理错误条件、如何处理安全性事项、对于类借口有哪些约定、可重用的代码遵循哪些标准、在编码时考虑多少性能因素等?
    • 你有没有找到自己在技术浪潮中的位置,并相应调整自己的措施?如果必要,你是否知道如何“深入一种语言去编程”,而不受限于语言(仅仅”在一种语言上编程“)?
  • 团队工作

    • 你有没有定义一套集成工序——即,你有没有定义一套特定的步骤,规定程序员在把代码check in(签入)到主源码(代码库)中之前,必须履行这些步骤?
    • 程序员是结对编程、还是独自编程,或者这二者的某种组合?
  • 质量保证

    • 程序员在编写代码之前,是否先为之编写测试用例
    • 程序员会为自己的代码编写单元测试吗(无论先写还是后写)
    • 程序员在check in代码之前,会用调试器单步跟踪整个代码流程吗
    • 程序员在check in代码之前,是否进行集成测试(integration-test)
    • 程序员会复审(review)或检查别人的代码吗?
  • 工具

    • 你是否选用了某种版本控制工具?
    • 你是否选定了一种语言,以及语言的版本或者编译器版本?
    • 你是否选择了某个编程框架(framework,如J2EE或者Microsoft .NET),或者明确地坚决不使用编程框架?
    • 你是否决定允许使用非标准的语言特性?
    • 你是否选定并拥有了其他将要用到的工具——编辑器、重构工具、调试器、测试框架(test framework)、语法检查器等?