一只会飞的旺旺
文章92
标签72
分类8
《代码大全》读后感

《代码大全》读后感

  1. 1. 软件创建
    1. 1.1. 问题定义
    2. 1.2. 需求分析
    3. 1.3. 实现计划
    4. 1.4. 总体设计
    5. 1.5. 详细设计
    6. 1.6. 创建即实现
    7. 1.7. 系统集成
    8. 1.8. 单元测试
    9. 1.9. 系统测试
    10. 1.10. 校正性的维护
    11. 1.11. 功能强化
  2. 2. 隐喻编程
    1. 2.1. 计算机科学的语言隐喻
    2. 2.2. 播种与培植庄稼的隐喻
    3. 2.3. 沉积与增量的隐喻
    4. 2.4. 建造房屋的隐喻
    5. 2.5. 利用现成资源的隐喻
    6. 2.6. 定制化建造的隐喻
    7. 2.7. 智能工具箱的隐喻
    8. 2.8. 结论
  3. 3. 软件创建的先决条件
    1. 3.1. 先决条件的重要性
    2. 3.2. 问题定义先决条件
    3. 3.3. 需求分析的先决条件
    4. 3.4. 结构设计先决条件
    5. 3.5. 选择编程语言先决条件
    6. 3.6. 编程约定
    7. 3.7. 应花在先决条件的时间
    8. 3.8. 编码前的技术评审
    9. 3.9. 团队协作准备
    10. 3.10. 技术栈和工具选择
  4. 4. 建立子程序的步骤
    1. 4.1. 描述子程序的操作
    2. 4.2. 命名子程序
    3. 4.3. 考虑效率
    4. 4.4. 算法和数据结构
    5. 4.5. 从抽象到具体
    6. 4.6. 逐步细化数据
    7. 4.7. 使用程序设计语言 (PDL)
    8. 4.8. 持续检查和改进
  5. 5. 高质量子程序的特点
    1. 5.1. 生成子程序的原因
      1. 5.1.1. 创建子程序的理由总结
      2. 5.1.2. 子程序命名
    2. 5.2. 强内聚性
      1. 5.2.1. 内聚性类型
    3. 5.3. 松耦合性
      1. 5.3.1. 耦合性的类型
    4. 5.4. 子程序长度
    5. 5.5. 防错性编程
    6. 5.6. 子程序参数
      1. 5.6.1. 参数设计和使用
  6. 6. 模块化设计
    1. 6.1. 模块的内聚性
    2. 6.2. 模块的耦合性
    3. 6.3. 封装和信息隐蔽
  7. 7. 高级结构设计
    1. 7.1. 设计流程
    2. 7.2. 设计方法
    3. 7.3. 设计原则
    4. 7.4. 面向对象设计步骤
    5. 7.5. 往返设计
    6. 7.6. 问题解决方法
  8. 8. 数据名称
    1. 8.1. 变量命名
    2. 8.2. 名称长度
    3. 8.3. 命名风格
    4. 8.4. 特殊类型的变量命名
    5. 8.5. 逻辑和枚举变量
  9. 9. 变量
    1. 9.1. 作用域和初始化
    2. 9.2. 持久性和全局变量
  10. 10. 控制
    1. 10.1. 循环和条件控制
    2. 10.2. 嵌套和子程序
  11. 11. 文档
    1. 11.1. 文档类型
    2. 11.2. 代码注释
    3. 11.3. 注释实践
  12. 12. 项目大小的影响
    1. 12.1. 交流和方法
    2. 12.2. 项目规模影响
  13. 13. 单元测试
    1. 13.1. 测试原则
小卖铺上新啦!ChatGPT账号大甩卖! 一键直达

软件创建

开发计算机软件是一项非常复杂的工作。在过去的十五年中,研究者们已经明确了这项工作的主要方面,包括以下几个关键阶段:

问题定义

  • 目的:明确软件需要解决的问题。
  • 方法:与利益相关者进行沟通,确定软件需求的初步想法。

需求分析

  • 目的:深入理解并定义软件的功能和约束条件。
  • 方法:收集详细的用户需求,编写需求文档。

实现计划

  • 目的:制定实现软件所需的详细步骤和时间表。
  • 方法:项目管理和资源分配。

总体设计

  • 目的:定义软件的架构和高层次结构。
  • 方法:创建设计文档,明确系统的组成部分和它们之间的交互。

详细设计

  • 目的:具体化每个组件的设计。
  • 方法:详细说明具体模块的功能和接口。

创建即实现

  • 目的:将设计转化为实际代码。
  • 方法:编程和代码实现。

系统集成

  • 目的:将不同模块或组件整合为一个完整的系统。
  • 方法:集成测试,确保各部分协同工作。

单元测试

  • 目的:验证单个模块或组件的功能。
  • 方法:编写和执行针对单一模块的测试用例。

系统测试

  • 目的:确保整个系统满足设计和需求规格。
  • 方法:进行全面的测试,包括功能测试、性能测试等。

校正性的维护

  • 目的:修复软件运行中出现现的错误和问题。

  • 方法:定期更新软件,解决已发现的缺陷和性能问题。

功能强化

  • 目的:根据用户反馈和市场变化,增加新的特性或改进现有功能。
  • 方法:持续迭代开发,增强软件的功能和性能。

隐喻编程

隐喻在软件开发中起着关键的启发性作用,它通过将软件开发过程与我们熟悉的事物相比较,帮助我们更深入地理解软件开发的本质。以下是几个重要的隐喻及其在软件开发中的应用。

计算机科学的语言隐喻

  • 描述:计算机科学的语言丰富多彩,包括病毒、蠕虫、臭虫、炸弹等。
  • 意义:这些形象的隐喻描述了特定的软件现象,有助于我们理解和描述软件中的复杂问题。

播种与培植庄稼的隐喻

  • 描述:将创建软件比作播种或培植庄稼。
  • 意义:强调通过小步前进的方法(增量设计、构造、测试)来减少错误,提高软件质量。

沉积与增量的隐喻

  • 描述:将软件开发比作从水中沉积物中积累出代码。
  • 意义:强调在系统中逐渐添加新功能的重要性,即增量设计和测试。

建造房屋的隐喻

  • 描述:将软件创建比作建造房屋的过程。
  • 意义:展示了软件开发的各个阶段,从问题定义到优化,与建房子的步骤相类似。

利用现成资源的隐喻

  • 描述:在建房时,使用现成的洗衣机、电冰箱等,而不是自己制造。
  • 意义:鼓励在软件开发中利用现有的资源,如库、框架和高级语言特性。

定制化建造的隐喻

  • 描述:如果要建造一流的别墅,可能会选择定制家具和装饰。
  • 意义:对于高级别的软件开发,可能需要创建定制化的组件和功能,以实现特定的需求。

智能工具箱的隐喻

  • 描述:软件开发实践像一个装满各种工具的工具箱。
  • 意义:强调没有万能的工具,为每个任务选择合适的工具是成为优秀程序员的关键。

结论

  • 隐喻的重要性:隐喻帮助我们通过比较熟悉的事物来理解软件开发的复杂性。
  • 选择合适的隐喻:不同的隐喻适用于不同的情境。选择恰当的隐喻可以帮助更好地解决问题和理解软件开发的特性。
  • 工具箱理念:每位程序员都有自己的技术和方法集合。在不同的开发阶段选择合适的技术和方法是至关重要的。

软件创建的先决条件

先决条件的重要性

软件开发过程中的准备工作对于最终产品的质量至关重要。以下是几个关键点:

  1. 项目启动前的准备:像建筑工人在修建房屋前做准备一样,优秀的程序员在项目开始前会进行充分的准备。这包括确保所有必要的资源已准备就绪,并在计划的每个阶段都注重高质量。
  2. 抵制立即编码的冲动:许多程序员倾向于立即开始编码,但应先考虑准备阶段可能出现的问题。准备工作的经验是必不可少的,特别是在大型项目中。
  3. 教育周围的人:程序员的职责之一是教育管理人员和同事理解技术项目的开发过程,确保他们理解先决条件的重要性。
  4. 项目规划的重要性:在大型项目开始前进行彻底的规划至关重要。这与建造房屋前的规划工作相似。
  5. 避免不必要的修改:研究表明,最好是一次完成项目,因为不必要的修改成本很高。错误应尽早在软件开发过程中被发现并修正。

问题定义先决条件

在需求分析之前,应该清晰地定义问题。良好的问题定义应遵循以下准则:

  • 专注于问题本身:问题定义应仅描述要解决的问题,而不涉及解决方案。例如,“我们无法跟上指令系统”是一个问题,而“我们需要优化数据入口系统以便跟上指令系统”则偏向解决方案。
  • 从用户视角出发:问题定义应使用用户的语言,避免使用计算机技术术语。这有助于确保最佳的解决方案可能并不局限于技术实现。

需求分析的先决条件

需求分析是确定系统功能的关键步骤,应注意以下要点:

  1. 明确需求的重要性:清晰的需求有助于由用户而非程序员决定系统功能。这可以防止程序员在编程过程中对用户需求进行猜测。
  2. 需求分析的质量:如果需求分析不佳,应停止当前工作并返回需求分析阶段。
  3. 管理变更请求:对于在需求分析阶段之外提出的新想法,应进行成本和进度估计,然后再决定是否采纳。
  4. 应对不稳定需求:如果需求特别奇怪或频繁变化,考虑放弃项目可能是一个明智的选择。

结构设计先决条件

结构设计阶段需要考虑以下关键因素:

  1. 模块功能的明确性:每个模块应只完成一项任务,并应尽可能降低模块间的相互了解程度。
  2. 变动应对策略:结构设计应清晰描述系统应对变动的策略,包括对旧软件的重用和代码购买。
  3. 关键数据结构:明确使用的主要文件、表和数据结构,及其替代方案。
  4. 依赖特定算法的设计:如果设计依赖于特定算法,应详细描述或指出该算法。
  5. 内存管理:预估正常和极端情况下所需的内存。
  6. 错误处理:错误处理是软件开发中的关键部分,应在设计中明确处理策略。
  7. 坚固性和容错性:设计应指明所期望的系统坚固性和容错性类型。
  8. 性能目标:如果考虑性能,应在设计中明确性能目标,包括速度和内存使用。
  9. 设计一致性:确保结构设计的每次变动都与总体设计概念一致。

选择编程语言先决条件

选择编程语言时,应考虑以下因素:

  • 语言对思维的影响:编程语言会影响程序员的思维方式。确保所选语言适合项目的需求和团队的技术背景。

编程约定

在开始编码之前,明确的编程约定是至关重要的。这些约定应该详细到在编程过程中不需改动,确保代码的一致性和可维护性。

  • 编程风格:包括命名规范、代码布局、注释风格等。
  • 代码标准:定义函数、类的结构,变量的使用规则等。
  • 错误处理:统一的错误报告和处理机制。
  • 性能要求:对于性能的基本要求和目标。
  • 安全性:安全编程准则,防止常见的安全漏洞。

应花在先决条件的时间

软件项目的先决条件阶段需要投入适当的时间和资源,一般建议分配项目总时间的20%至30%。

  • 项目规模与复杂度:大型或复杂项目可能需要更多的时间进行准备。
  • 团队经验:经验丰富的团队可能在某些阶段更快地完成准备工作。
  • 风险评估:高风险项目需要更细致的先决条件分析。

编码前的技术评审

在正式开始编码之前进行技术评审,以确保设计的合理性和可行性。

  • 设计评审:评估设计方案是否符合需求。
  • 代码审查:早期发现潜在的代码问题和不一致之处。
  • 性能分析:确保设计能满足性能要求。

团队协作准备

确保团队成员间的有效沟通和协作。

  • 角色分配:明确每个团队成员的职责和任务。
  • 沟通机制:建立有效的沟通渠道和会议安排。
  • 文档共享:确保所有相关文档易于团队成员访问。

技术栈和工具选择

选择合适的技术栈和工具是项目成功的关键。

  • 编程语言:根据项目需求和团队技能选择合适的编程语言。
  • 开发框架:选择支持项目需求的开发框架和库。
  • 开发和测试工具:选用高效的IDE、版本控制系统和测试工具。

建立子程序的步骤

建立子程序是软件开发中的一个重要过程,需要遵循一系列明确的步骤以确保代码的质量和可维护性。

描述子程序的操作

  • 使用自然语言:以清晰的自然语言描述子程序的每一步操作,确保其目的和功能明确。

命名子程序

  • 清晰且具体:子程序的命名应清楚、具体,避免引起误解。
  • 反映功能:名称应反映子程序的功能和作用。

考虑效率

  • 性能优化:在保证功能和清晰性的基础上,考虑子程序的运行效率。
  • 资源管理:注意资源使用和管理,避免不必要的资源浪费。

算法和数据结构

  • 合适的选择:根据子程序的功能选择合适的算法和数据结构。
  • 效率与可维护性:平衡算法的效率和代码的可维护性。

从抽象到具体

  • 注释先行:编写子程序时,先从抽象的注释开始,明确子程序的目的和功能。
  • 清晰的目标:如果在这一步遇到困难,可能需要对子程序的角色和功能进行深入思考。

逐步细化数据

  • 数据设计:仔细考虑子程序将处理的数据类型和结构。

  • 逐步实现:从大致框架开始,逐步细化实现细节。

使用程序设计语言 (PDL)

  • 易懂的语言:使用清晰易懂的自然语言编写PDL,避免过度依赖特定编程语言的语法。
  • 注重目的:PDL应关注于描述子程序要做什么,而非具体实现方式。
  • 从PDL到代码:PDL可以直接转化为代码的注释,确保注释的准确性和实用性。

持续检查和改进

  • 代码检查:在开发过程的每一步中检查子程序,确保质量。
  • 同事审查:鼓励团队成员互相审查代码,及早发现并纠正错误。
  • 降低成本:通过早期发现和修正错误,降低后期修复成本。

高质量子程序的特点

生成子程序的原因

创建子程序的理由总结

  • 降低复杂性:使代码更易于理解和维护。
  • 避免重复代码:促进代码重用,减少冗余。
  • 限制改动影响:简化维护和更新。
  • 隐含顺序和控制:明确代码的执行流程。
  • 改进性能:通过优化关键子程序来提升整体性能。
  • 进行集中控制:统一管理相关操作。
  • 隐含数据结构和指针操作:隐藏复杂的数据处理。
  • 隐含全局变量:减少全局变量的直接使用。
  • 促进代码重用:提高代码的可重用性。
  • 计划开发软件族:为未来的扩展做准备。
  • 改善可读性和可移植性:使代码更易于阅读和适应不同环境。
  • 分隔复杂操作:将复杂的操作拆解成更小的单元。
  • 独立非标准语言函数的使用:减少对特定语言特性的依赖。
  • 简化复杂的布尔测试:使逻辑判断更清晰。

子程序命名

  • 清晰描述:名称应明确反映子程序的功能。
  • 适当的长度:长度应足以描述功能,但不过于冗长。
  • 避免模糊用语:选择明确无歧义的词汇。

强内聚性

内聚性类型

  • 功能内聚性:子程序执行单一且明确的功能。
  • 顺序内聚性:操作需要按特定顺序执行。
  • 通讯内聚性:操作使用相同的数据。
  • 临时内聚性:操作基于相同的时间发生。

松耦合性

耦合性的类型

  • 简单数据耦合:优选,通过参数表传递非结构化数据。
  • 数据结构耦合:通过参数表传递结构化数据。
  • 控制耦合:一个子程序通过参数控制另一个子程序的行为。
  • 全局数据耦合:子程序通过全局变量进行通信。
  • 不合理耦合:直接修改另一个子程序的内部数据或代码(应避免)。

子程序长度

  • 理想长度:一般建议子程序长度为一到两页代码(大约66到132行)。

防错性编程

  • 使用断言:验证程序状态,确保数据的正确性。
  • 垃圾输入处理:确保对不合理的输入给予合适的响应。
  • 异常处理:设计异常处理机制,应对意外情况。
  • 预计可能的改动:考虑未来可能的变化和扩展。
  • 去除调试代码:发布时移除专用于调试的代码部分。
  • 保留错误提示信息:对于错误和异常提供清晰的反馈。
  • 检查函数返回值:验证其他函数的返回值,确保数据的正确性。

子程序参数

参数设计和使用

  • 匹配实际与形式参数:确保调用时传递的参数与子程序定义匹配。
  • 参数顺序:输入、修改、输出参数的顺序应一致。
  • 类似子程序的参数顺序一致性:相似功能的子程序应有相同的参数顺序。
  • 使用所有参数:不使用的参数应从子程序接口中移除。
  • 状态和错误变量放在最后:使子程序的主要功能更明显。
  • 参数非工作变量:避免将参数用作内部的工作变量。
  • 特殊情况的说明:明确参数的特殊用途和限制。
  • 限制参数个数:减少参数数量,避免过度复杂。
  • 规范参数命名:清晰、一致的命名提高代码可读性。
  • 传递必要部分的结构化变量:仅传递子程序所需的数据结构部分。

模块化设计

模块的内聚性

  • 原则:模块应提供一组相互联系的服务,保持高内聚。
  • 意义:内聚性强的模块能更清晰地定义功能,简化理解和维护。

模块的耦合性

  • 原则:设计模块时应保持与其他模块的耦合度低。
  • 实践:模块应被设计成可提供完整功能,确保与其他部分的清晰交互。

封装和信息隐蔽

  • 定义:将模块的信息细节隐蔽起来,也称为“封装”。
  • 优点:
    • 便于修改。
    • 澄清代码编写意图。
    • 提高可靠性。
    • 简化调试。
    • 统一数据存取模式。

高级结构设计

设计流程

  1. 子系统划分。
  2. 模块化设计。
  3. 程序的细节设计。
  4. 子程序内部和设计。

设计方法

  • 自顶向下分解。
  • 自底向上合成。

设计原则

  • 抽象:创建与问题同等抽象层次的编程抽象,避免过度细节化。
  • 封装:在老旧语言中是自愿的,而在如Ada等现代语言中则是强制性的。
  • 继承:在面向对象编程中,继承性简化了编程,通过通用和专用子程序处理对象间的共同与不同特性。

面向对象设计步骤

  1. 识别对象及其属性。
  2. 确定对象的功能。
  3. 确定对象间的相互作用。
  4. 确定对象的可见性和接口。

往返设计

  • 概念:设计是一个迭代过程,可能需要多次往返以深化理解。
  • 好处:在设计过程中进行迭代可以带来更大的好处。

问题解决方法

  1. 理解问题。
  2. 设计方案。
  3. 执行解决方案并检查每一步。
  4. 回顾并检查答案。

数据名称

变量命名

  • 原则:变量名称应准确描述其代表的实体。
  • 建议:使用自然语言描述变量代表的实体,名称应体现问题而非解决方法。

名称长度

  • 标准:选择合适长度的变量名,确保清晰易懂。
  • 例外:在特定情况下,如临时变量,短名称(如i)可能更合适。

命名风格

  • 限定词使用:如totals, averages, maximums等,限定词放在变量名末尾。
  • 反义词使用:恰当使用反义词以增强变量意义的清晰度。

特殊类型的变量命名

  • 状态变量:避免使用模糊的名字如flag,应使用更具描述性的名称。
  • 临时变量:通常用作保存中间计算结果,应避免无意义的命名。

逻辑和枚举变量

  • 逻辑变量:使用肯定的名称,易于理解。
  • 枚举变量:使用统一的前缀或后缀以表明同一类型。

变量

作用域和初始化

  • 作用域:变量在程序中的可见范围。
  • 初始化:应在使用前恰当地初始化变量。

持久性和全局变量

  • 持久性:变量的使用寿命,避免硬编码,确保功能单一性。
  • 全局变量:最初设为局部变量,必要时转为全局变量,但应优先考虑使用存取子程序。

控制

循环和条件控制

  • 边界错误:明确循环结束点和条件语句中的等号情况,避免边界错误。
  • 简化循环:通过减少循环次数、明确进出口等方式简化循环。

嵌套和子程序

  • 简化嵌套:重新编写测试条件,将深层嵌套代码转为子程序或使用case语句替代if嵌套。

文档

文档类型

  • 综合资料:供开发者使用的非正式记录。
  • 详细设计文档:描述模块层或程序层的决策。

代码注释

  • 注释类别:包括代码的重复、解释、标记、总结和意图描述。
  • 注释原则:避免无关注释,注释应清晰表达代码意图。

注释实践

  • 行注释:避免过度使用,注释应与代码紧密相关。
  • 结束行注释:应集中在“为什么”而非“如何”上。

项目大小的影响

交流和方法

  • 交流规范化:对大型项目而言,规范化文档和交流方式非常重要。
  • 方法应用:小型项目可能采用偶然和本能的方法,而大型项目则需要精确和计划性的方法。

项目规模影响

  • 代码行数和参与人数:项目大小不仅由代码行数和参与人数决定,还包括软件的质量和复杂性。
  • 生产效率:受人员素质、编程语言、方法、产品复杂性等多种因素影响。

单元测试

测试原则

  • 测试覆盖:选择能有效发现错误的测试用例,包括结构测试和数据流测试。
  • 边界条件:重点关注边界条件和最小最大值。
微信支付码 微信支付
支付宝支付码 支付宝支付