0%

《代码大全(第2版)》Part 1:打好基础

1 欢迎进入软件构建的世界

1.1 什么是软件构建

  构建就是软件工程中“编码”的那一部分,关心的是程序的实现与可行。构建活动主要是编码与调试,但也涉及详细设计、规划构建、单元测试、集成等其他活动。

构建活动中的具体任务:

  • 验证有关基础工作是否完成
  • 确定如何测试所写代码
  • 设计并编写类和子程序
  • 创建并命名变量和常
  • 选择控制结构、组织语句块
  • 单元测试与集成测试
  • 评审设计与代码
  • 集成
  • 调整代码、性能优化

1.2 软件构建为何如此重要

  作者给出以下几个论点(其实也是我们所熟知的)

  • 构建活动是软件开发的主要组成部分
  • 构建活动是软件开发中的核心活动
  • 主要精力集中于构建可提高生产率
  • 构建活动的产物——源代码往往是对软件唯一精确的描述
  • 构建活动是唯一一项确保会完成的工作

1.3 如何阅读本书

  参考原书,不赘述

2 用隐喻来更充分地理解软件开发

  本章介绍了隐喻的重要性、隐喻的启发作用以及常用的软件隐喻。

2.1 隐喻的重要性

  作者用一些科学发展事迹来表达隐喻的重要性,如基于“撞球”模型提出的气体分子运动、伽利略观察挂在绳子上的小球提出钟摆模型等等。这里的“隐喻”与“建模”、“抽象化”意思相近。

  • 隐喻是对概念进行内在化(internalizing)和抽象化(abstracting)的一种途径。——Fernando J. Corbato
  • 科学发展的历史并不是从一系列”错误“的隐喻到”正确“的隐喻的转变,而是一些列从”不太合适“的隐喻到”更好“的隐喻的转变

2.2 如何使用软件隐喻

  这一节主要讲软件中要怎么使用隐喻,并论述了算法与启发式方法的区别。我的理解是:编程中的问题很独特,没办法用“一个模型”去描述编程中遇到的所有问题,所以隐喻只能起到“启发”的作用,帮助发现问题的突破口。

算法直接给你解决问题的指导,而启发式方法则告诉你该如何发现这些指导信息,或者至少到哪里去寻找它们。

2.3 常见的软件隐喻

  作者列举了常用的软件开发隐喻,由浅到深依次是:写作-培植-生长-建造。最后肯定了“建造”这一种隐喻并提出大量“建造”与软件开发的类比作为作证,比如“决定建什么样的房子”对应软件中的问题定义;“和某个建筑师探讨总体设计”对应架构设计;“准备建造地点、打地基、搭建房屋框架、砌墙砌瓦等”对应软件中的构建等等。但作者也说了,隐喻毕竟是启发式方法,个人可以有自己的见解,只要它能激发自己的思维灵感。当然,不当的隐喻可能会让你误入歧途。

3 三思而后行:前期准备

  需求、架构这些前期准备非常重要。明确要做的准备工作、明确这些工作是否达标,能够有效减小后期解决问题的代价

3.1 前期准备的重要性

  本节作者分析了无法做前器准备的原因,并讲述“老板不认可前期准备”时的说服办法,其实也在试图告诉我们前期准备有多重要。

  • 程序员时软件食物链的最后一环。架构师吃掉需求,设计师吃掉架构,而程序员则消化设计
  • 缺陷在软件食物链里面呆的时间越长,它对食物链的后级造成损害就越严重

3.2 辨明你所从事的软件的类型

  本节对比了软件开发的两种类型:迭代式方法和序列式方法。迭代式方法的特点是:边走边看(as-you-go,走着瞧),适用于需求理解不透彻、模糊、有挑战性、不熟悉、风险大的项目;序列式方法的特点是:各个流程按部就班,适用于需求稳定、团队对这一领域熟悉、风险小的项目。此外,本节还介绍了有无前期准备对这两种开发流程的影响。

开发商业系统的项目往往受益于高度迭代的开发法,这种方法的“计划、需求、架构”活动与“构建、系统测试、质量保证”活动交织在一起。性命攸关的系统往往要求采用更加序列式的方法——“需求稳定”是确保“超高等级的可靠性”的必备条件之一。

3.3 问题定义的先决条件

  本节讲的是如何辨认自己已经对一个系统要解决的问题做出了清楚的陈述。问题就是问题本身,不包含解决方案;问题要用客户的语言、站在客户的角度描述。错误的问题可能会导致错误的方向。

如果“框框”是约束和条件的边界,那么诀窍在于找到这个“框框”……不要在“框框”之外思考——找到这个“框框”

3.4 需求的先决条件

  本节讲的是正式需求的重要性,以及如何判断是否已经很好地完成了需求分析、如何在构建期间处理需求变更。处理需求变更的方法有:确保每个人都知道需求变更的代价、建立一套变更控制程序(委员会、特定时间)、使用能适应变更的开发方法、放弃这个项目(哈哈哈)、注意项目的商业案例(考虑需求的商业价值)。

  • 有些需求作为功能特色来看是不错的想法,但是当你评估“增加的商业价值”时就会觉得它是个糟透了的主意。那些记得“考虑自己的决定所带来的商业影响”的程序员的身价与黄金相当。
  • 需求核对表:

3.5 架构的先决条件

  本节讲了架构的基本概念、组织,列举了考察一个架构是否满足要求的标准,大体的思想就是:知道怎么做的同时还要知道为什么选择这种做法、巨细无遗而又不过度。架构的典型组成部分包括:程序组织、主要的类、数据设计、业务规则、用户界面设计、资源管理、安全性、性能、可伸缩性、互用性、国际化/本地化、输入输出、错误处理、容错性、架构可行性、过度工程(比要求的更好)、关于“买”还是“造”的决策、关于复用的决策、变更策略、架构整体质量

  • “架构”要区别于“高层设计”:架构是指适用于整个系统范围的设计约束,而高层设计指的是适用于子系统层次或多个类层次上的设计约束(但不是整个系统范围的设计)。
  • 架构的质量决定了系统的“概念完整性”,后者继而决定了系统的最终质量。
  • 在构建期间或者更晚的时候进行架构变更,代价也是高昂的。
  • “维护‘设计的缘由’”至少与“维护设计本身”一样重要。
  • 在查看架构的时候,你应该很愉快,因为它给出的解决方案看上去既自然又容易。而不应该看起来像是用胶带把架构和待解决的问题硬捆绑到一起。
  • 架构应该踏在对系统“欠描述(underspecifying)”和“过度描述(overspecifying)”之间的那条分界线上。
  • 架构核对表

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

  花费在问题定义、需求分析、软件架构上的时间,依据项目的需要而变化。如果是需求不稳定的大项目,你需要与需求分析师合作;如果是需求不稳定的小项目,可能需要自己解决需求方面的问题;如果需求在任何项目上都不稳定,那就将需求分析工作视为独立项目来做。如果有必要,架构工作也作为独立的项目来对待。

4 关键的“构建”决策

  本章讲的是编码之前应该明确的事情,如语言的选择、编程的约束,以及认清自己在浪潮中的位置,合理地决策。应该明确“深入语言去编程”,也就是用思想引领而非被语言约束。

4.1 选择编程语言

  选择正确的编程语言不仅可以提高生产力,还能有效表达思想。作者还介绍了一些常用编程语言的特点。

Sapir-Whorf假说是,你思考的能力取决于你是否知道能够表达该思想的词汇。如果你不知道这些词汇,就无法表达出这种思想,甚至不可能形成这种思想。

4.2 编程约定

  本节讲述“架构的概念完整性”与“其底层实现”之间的关系。实现必须与架构保持已知,程序需有底层完整性(如变量的名称、类名、格式约束之类的约定)

  • 成功编程的一个关键就在于避免随意地变化,这样你的大脑可以专注于那些真正需要的变化。
  • 编码约定的细节要达到这样的精确度:在编写完软件之后,几乎不可能改变(翻新)软件所遵循的编码约定。

4.3 你在技术浪潮中的位置

  编程实践取决于你在技术浪潮中所处的位置。技术浪潮的前期,编程语言有bug,文档少;技术浪潮的后期则相反,基础设施丰富。当处在前期时,“深入一种语言去编程”至关重要,也就是要让思想指导编程,而不是被语言限制思想。

坚持原创技术分享,您的支持将鼓励我继续创作!

欢迎关注我的其它发布渠道