软件工程基础
AI WARNING
未进行全面的对照审核。
软件的概念
软件
软件(Software)并不仅仅是程序代码。根据 IEEE 的定义(IEEE610.12-1990),软件是计算机程序、规程、规则以及相关的文档和数据的完整集合。更广泛地理解,软件可以看作是「程序 + 文档 + 数据 + 知识」的综合体。
软件的演进与本质
软件的发展经历了从依附于硬件到成为独立且复杂的系统的过程:
- 早期(40s-50s):软件被视为硬件的一部分,例如 ENIAC 的编程需要手动接线和设置开关。随着存储程序概念(冯·诺依曼结构)的提出,软件开始与硬件分离。
- 程序时代(60s-80s):软件的核心被认为是「程序 = 算法 + 数据结构」。高级编程语言(如 FORTRAN, LISP, COBOL)的出现使得软件开发脱离具体的机器指令。但此时,软件开发仍被视为类似于硬件工程的过程。
- 软件开发时代(90s-至今):人们逐渐认识到,软件开发远比编程复杂。随着应用规模的扩大(如万维网、社交网络、移动电商、云计算、大数据、AI),文档、需求、设计、测试、维护、团队协作等在软件项目中的比重越来越大。
软件的本质
- 独立于硬件:软件可以在不同的硬件平台上运行(通过操作系统、虚拟机等抽象层)。
- 工具性:软件是解决现实世界问题的工具。
- 复杂性:现代软件开发涉及需求、设计、构建、测试、交付、维护等多个复杂活动,远超简单的编码。
软件的特性
软件具有区别于硬件或其他工程产品的独特特性:
- 与现实世界关系密切:应用软件通常源于现实世界的问题,其需求的精确描述(规格化)比硬件更困难。
- 易于修改:相比硬件,软件修改成本较低,但也更容易引入错误。软件的复制几乎没有成本。
- 没有物理损耗:软件不会像硬件一样磨损老化,但可能因需求变更、环境变化而变得过时或需要维护(软件退化)。
- 不可见性:软件是逻辑的、无形的,这给理解、度量和管理带来了挑战。
软件的分类
根据用途和目的,软件大致可分为三类:
- 系统软件:为其他软件提供运行平台和服务的软件。
- 例子:操作系统、数据库管理系统(DBMS)、驱动程序、嵌入式系统固件、安全软件。
- 编程软件:用于开发、测试和维护其他软件的工具。
- 例子:集成开发环境(IDE)、编译器、调试器、版本控制系统(如 Git)、持续集成工具、建模工具、度量工具。
- 应用软件:直接面向用户,解决特定领域问题的软件。
- 例子:商业(ERP, CRM)、政府、办公(Word, Excel)、休闲娱乐(游戏, 视频)、医疗、教育、国防、个人、专业(CAD, CAE)、科学计算等。
应用软件与现实
应用软件基于现实又高于现实。它源于现实问题,必须基于对现实的理解来构建解决方案,最终又被用于改进现实世界。
软件工程的概念
软件工程
软件工程(Software Engineering)是(IEEE610.12-1990)定义为:
- 将系统的、规范的、可量化的方法应用于软件的开发、运行和维护的过程,即工程化应用于软件。
- 对 1. 中所述方法的研究。
工程 的内涵
理解软件工程,首先要理解「工程」的普遍含义。工程通常指:
- 创造性地应用科学原理。
- 目标是设计、开发、构建、运行结构、机器、设备、过程或利用它们的组合。
- 充分考虑设计的预期功能、运行经济性和生命财产安全。
软件工程的要素与理解
Mary Shaw 教授总结了工程学科的普遍特征,这有助于我们理解软件工程:
- 解决实际问题的动机:工程服务于工程领域之外的消费者需求。软件工程旨在解决现实世界中广泛存在的、通常定义不清或需要探索的问题。
- 应用科学知识指导活动:工程强调以计算科学等科学知识为基础,采用系统化、可重复的方法和技术进行设计与分析,而非依赖个人技巧。
- 以成本效益有效为基本条件:工程不仅要解决问题,还要有效地利用资源,确保成本低于效益。软件工程师需要在多种方案中权衡,选择最具成本效益的方案(未必是技术最先进的)。可行性研究是重要环节。
- 构建机器或事物(软件方案):工程强调构建实体工具。软件工程构建的是运行在虚拟计算机(通用计算机 + 特定软件解决方案)上的软件方案。开发解决方案是软件工程的核心任务,将其映射到通用计算机上是辅助任务。
- 以服务人类为最终目的:工程旨在运用技术和经验推动整个社会的进步,而非仅仅满足单个客户。
对软件工程的理解
- 软件工程是一种工程活动。
- 其核心动机是解决实际问题。
- 它并重科学性、实践性和工艺性(Engineering = Science + Principle + Art)。科学性体现在计算理论基础上,实践性体现在方法、技术和经验的积累与共享,工艺性体现在分析和设计中的创造力。
- 它追求足够好,而非理论上的绝对最优,需要在各种约束(成本、时间、质量)下进行权衡。
- 其真正的产品是基于虚拟计算机的软件解决方案。
- 其最终目的是促进整个社会的进步。
软件开发活动与产物
软件工程涉及一系列核心活动,每个活动都有其目标和产出的制品:
活动(Activity) | 目标(Target) | 主要产物(Artifact) |
---|---|---|
软件需求 | 定义要做什么(What) | 需求规格说明书(SRS) |
软件设计 | 定义如何做(How) | 软件设计文档(SDD),包括体系结构和详细设计 |
软件构造 | 构建系统(Build) | 源代码、可执行文件 |
软件测试 | 验证是否构建了正确的系统? 系统是否正确地构建? |
测试报告 |
软件交付(与维护) | 部署系统(Install) | 用户文档、系统文档 |
软件维护(与交付) | 系统的演化(Revolution) | 新版本软件 |
软件开发 编程
随着软件规模增大,编码(编程)在整个软件开发工作量中所占的比例逐渐降低。需求、设计、测试、文档编写、缺陷清除、项目管理、沟通交流等占据了越来越大的比重。例如,对于百万行代码量级(LOC) 的大型系统,缺陷清除、文档编写、会议交流的成本可能远超编码本身。
软件开发的角色分工
复杂的软件项目通常需要不同角色的专业人员协作完成:
- 需求工程师/分析师:负责获取、分析、定义和管理软件需求。
- 软件体系结构师:负责设计软件的顶层结构和关键机制。
- 软件设计师:负责模块或组件的详细设计。
- 程序员:负责根据设计编写、调试和单元测试代码(通常与设计师角色重叠)。
- 人机交互设计师:负责设计用户界面和交互流程,提升易用性。
- 软件测试人员:负责制定测试计划、设计测试用例、执行测试并报告缺陷。
- 项目管理人员:负责计划、组织、领导、协调和控制整个开发过程。
- 软件配置管理人员:负责管理软件开发过程中产生的各种制品(代码、文档、模型等)的版本和变更。
- 质量保障人员:负责监督和控制软件产品和过程的质量。
- 培训和支持人员:负责软件的部署、用户培训和后续支持。
- 文档编写人员:专门负责编写各类技术文档和用户文档。
软件工程知识域(SWEBOK)
SWEBOK
软件工程知识体系(Software Engineering Body of Knowledge, SWEBOK)是由 IEEE 计算机学会组织编写的,旨在界定软件工程学科所包含的知识领域。
SWEBOK 将软件工程知识划分为多个知识域(Knowledge Area, KA),主要包括:
技术知识域:
- 软件需求(Software Requirements)
- 软件设计(Software Design)
- 软件构造(Software Construction)
- 软件测试(Software Testing)
- 软件维护(Software Maintenance)
管理知识域:
- 软件配置管理(Software Configuration Management)
- 软件工程管理(Software Engineering Management)
- 软件工程过程(Software Engineering Process)
- 软件工程模型和方法(Software Engineering Models and Methods)
- 软件质量(Software Quality)
支撑知识域(部分):
- 软件工程经济学(Software Engineering Economics)
- 计算基础(Computing Foundations)
- 数学基础(Mathematical Foundations)
- 工程基础(Engineering Foundations)
注:SWEBOK 版本会更新,知识域可能有所调整,例如 V4 版本增加了软件架构、软件工程运维、软件安全等。
知识的重要性
对职业软件工程师而言,不同的知识领域重要性不同。通常,与编程语言、数据结构、算法、软件架构、需求工程、测试、项目管理等直接相关的知识更为重要。同时,沟通表达能力、团队协作能力和职业素养也至关重要。
项目管理基础
软件开发通常以项目(Project)的形式进行。
项目的定义
项目是为创造独特的产品、服务或成果而进行的临时性工作。其主要特征包括(Kerzner2009):
- 明确的目标:项目旨在达成一个或多个具体目标。
- 有限的起止日期:项目有明确的开始和结束时间。
- 成本限制:项目需要在预算内完成。
- 资源消耗:项目需要消耗人力、设备、资金等资源。
- 多工种合作:项目通常需要不同技能的人员协作。
项目管理的目标
项目管理是将知识、技能、工具与技术应用于项目活动,以满足项目的要求。其核心目标是在满足范围、时间、成本和质量等约束条件下,成功交付项目成果。具体目标包括:
- 在限定时间内完成。
- 在预算成本内完成。
- 达到要求的质量水平。
- 高效使用资源。
- 获得客户(或干系人)认可。
过程组与活动
项目管理活动可以划分为不同的过程组和具体的管理活动。
- 五大过程组(PMBOK):
- 启动(Initiating):定义新项目或项目新阶段,授权开始。
- 规划(Planning):明确项目范围,优化目标,制定行动方案。
- 执行(Executing):完成规划中确定的工作,以满足项目要求。
- 监控(Monitoring & Controlling):跟踪、审查和调整项目进展与绩效,识别并管理变更。
- 收尾(Closing):正式完成或结束项目、阶段或合同。
- 项目管理活动(示例):
- 计划制定(范围、进度、成本、质量、资源、沟通、风险、采购、干系人)
- 团队管理
- 成本控制
- 质量保障
- 度量分析
- 过程管理
- 进度跟踪与控制
- 风险管理
- 配置管理
团队组织与管理
团队的重要性
一个协作良好的团队是任何项目成功的基础。软件开发是以人为核心的活动,人力资源是软件项目最宝贵的资产。建立一个凝聚力强的团队,其意义甚至可能超过生产高质量产品本身。
团队的特征
根据 [Katzenbach1993] 的定义,团队是为了共同的目标、绩效标准和方法而承担共同责任、并且技能互补的一小群人。关键特征包括:
- 共同的目标:成员理解并致力于实现共同目标。
- 共担责任:团队成员对团队的成败共同负责。
- 技能互补:成员具备完成任务所需的不同技能,相互补充。
- 明确的结构:团队内部有清晰的角色、职责和沟通协作方式。
团队结构
常见的软件开发团队结构有:
- 主程序员团队(Chief Programmer Team):
- 结构:类似外科手术团队,由一位能力极强的主程序员负责核心设计和编码,辅以备份程序员、管理员、文档员、测试员等支持角色。
- 特点:等级化,沟通路径清晰,效率高,但对主程序员依赖性强,不利于成员成长。
graph TD CP(主程序员) --> P1(程序员1) CP --> P2(程序员2) CP --> P3(...) style CP fill:#f9f,stroke:#333,stroke-width:2px
- 民主团队(Democratic Team/Egoless Team):
- 结构:扁平化,成员地位平等,决策通过协商或投票产生。
- 特点:沟通充分,成员积极性高,有利于解决复杂问题,但决策效率可能较低,责任分散。
graph TD P1 --- P2 P1 --- P3 P1 --- P4 P2 --- P3 P2 --- P4 P3 --- P4 style P1 fill:#ccf,stroke:#333,stroke-width:1px style P2 fill:#ccf,stroke:#333,stroke-width:1px style P3 fill:#ccf,stroke:#333,stroke-width:1px style P4 fill:#ccf,stroke:#333,stroke-width:1px
- 开放团队(Open Team/Adaptive Team):
- 结构:介于前两者之间,通常有一个技术负责人或协调者,但鼓励成员主动承担责任和贡献想法。类似于开源社区的组织模式。
- 特点:灵活性高,能适应变化,鼓励创新,但需要较强的自管理能力和良好的沟通机制。
graph TD direction LR Leader(协调者/负责人) -.-> Member1 Leader -.-> Member2 Leader -.-> Member3 Member1 <--> Member2 Member1 <--> Member3 Member2 <--> Member3 style Leader fill:#9cf,stroke:#333,stroke-width:2px
团队建设
构建高效团队需要关注以下方面:
- 建立团队章程:明确团队的目标、角色职责、沟通方式、决策机制、工作流程、行为规范等。
- 持续成功:通过设定可达成的阶段性目标,让团队不断获得成就感,建立信心。
- 和谐沟通:营造开放、信任、尊重的沟通氛围,鼓励成员表达观点和反馈。定期进行团队活动(如聚餐、团建)有助于增进了解。
- 避免团队杀手 [DeMarco1999]:
- 防范式管理:过度控制,不信任成员。
- 官僚主义:僵化的流程和审批。
- 地理分散:影响沟通效率和团队凝聚力。
- 时间分割:成员同时参与多个项目,精力分散。
- 产品质量的降低:牺牲质量赶进度,打击士气。
- 虚假的最后期限:不切实际的时间要求。
- 小圈子控制:团队内部形成小团体,影响整体协作。
激励因素
不同角色的成员激励因素不同。例如,开发人员可能更看重成就感、发展机遇和工作乐趣,而项目经理可能更看重责任感、成就感和认可度。了解成员需求有助于更好地激励团队。(参考 Boehm1981 的研究)
软件质量保障
软件质量
软件质量(Software Quality)是指软件产品满足明确或隐含需求的能力。软件工程师对产品的质量负有责任。质量要求可能是显式的(如性能指标),也可能是隐式的(如用户体验)。
质量模型
为了系统地描述和评价软件质量,人们提出了质量模型(Quality Model)。这些模型定义了一系列质量属性(Quality Attribute)或特征。
ISO/IEC 9126 (及后续的 ISO/IEC 25010):是一个广泛使用的质量模型,定义了六个主要质量特性(因素),每个特性下又包含若干子特性:
- 功能性(Functionality):软件满足规定和隐含功能需求的能力。 (适合性、准确性、互操作性、安全性、依从性)
- 可靠性(Reliability):在规定条件下,软件维持其性能水平的能力。(成熟性、容错性、易恢复性、依从性)
- 易用性(Usability):用户理解、学习、使用软件以及软件对用户有吸引力的能力。(易理解性、易学性、易操作性、吸引性、依从性)
- 效率(Efficiency):在规定条件下,软件性能水平与所用资源量之间的关系。(时间特性、资源利用性、依从性)
- 可维护性(Maintainability):软件可被修改的能力(包括修正、改进或适应环境变化)。(易分析性、易改变性、稳定性、易测试性、依从性)
- 可移植性(Portability):软件从一种环境迁移到另一种环境的能力。(适应性、易安装性、共存性、易替换性、依从性)
质量保障(Quality Assurance, QA)
质量保障是指为确保软件产品或服务满足既定质量要求而进行的所有有计划、有系统的活动。QA 活动贯穿于整个软件开发过程。
主要活动:
- 评审(Review):对软件开发过程中的制品(如需求文档、设计文档、代码、测试计划等)进行检查,以发现和移除缺陷。
- 质量度量(Quality Measurement):对软件产品或过程的特定属性进行量化测量,以评估质量状态。
- 测试(Testing):(虽然测试本身是发现缺陷的活动,但 QA 会关注测试过程的有效性)
- 过程改进:基于度量和反馈,改进开发过程以提升质量。
评审(Review)
评审是重要的静态质量保证活动。常见的评审过程包括:
- 规划(Planning):确定评审对象、目标、参与者、时间地点、评审标准和方法(如检查单)。
- 总体部署(Overview):向评审参与者介绍待评审材料的背景、目标和内容。
- 准备(Preparation):参与者独立阅读和检查材料,记录发现的问题。
- 评审会议(Inspection Meeting):通过集体讨论,识别、确认和分类发现的错误。
- 返工(Rework):作者根据评审意见修改制品。
- 跟踪(Follow-up):确认所有问题都得到解决,错误得到修正。
质量度量(Quality Measurement)
度量相关概念:
- 测度(Measure):为描述软件产品或过程而提供的定量指标。例如,代码行数(LOC)、圈复杂度、缺陷密度。
- 测量(Measurement):进行测度的活动。
- 度量(Metric):软件产品或过程在特定属性上的量化测度程度。通常基于一个或多个测度计算得到。例如,平均代码行数、最大代码行数、测试覆盖率。
度量是进行质量控制和过程改进的基础。「你不能控制自己无法度量的东西」[DeMarco1998]。
软件配置管理(SCM)
软件配置管理
软件配置管理(Software Configuration Management, SCM)是 [IEEE610.12-1990] 定义为:运用技术和管理的指导和监督方法,来标识和说明配置项的功能和物理特征,控制对这些特征的变更,记录和报告变更处理及其实现状态,并验证与规格需求的一致性。
SCM 的动机
在软件开发中,除了最终产品,还会产生大量中间制品(文档、模型、代码、测试脚本等)。SCM 主要解决以下问题:
- 管理众多制品:跟踪项目产生的所有重要制品及其状态。
- 协同开发:确保不同阶段、不同角色的开发者能够基于一致、最新的制品进行工作,避免协同问题。
- 变更控制:管理制品发生的变化,确保变更经过评审和批准,避免混乱。
核心概念
- 配置项(Configuration Item, CI):置于 SCM 控制之下的软件开发过程中的各种产物。例如:
- 管理文档(计划、报告)
- 评审记录
- 软件文档(需求 SRS, 设计 SDD, 用户手册)
- 源代码及其可执行码
- 测试用例、测试数据
- 运行所需的系统软件、支持软件、数据等。
- 每个需要独立管理和控制的单元都可以是一个配置项。
- 基线(Baseline):[IEEE610.12-1990] 定义为:已经过正式评审和批准的规格说明或产品,它可以作为后续开发的基础,并且只有通过正式的变更控制程序才能进行修改。
- 基线是项目发展过程中的里程碑,代表了一个相对稳定的状态。常见的基线包括需求基线、设计基线、产品基线等。
- 制品一旦纳入基线,就进入受控状态。
graph LR
A[制品] -- 开发/修改 --> B(完成?);
B -- 否 --> A;
B -- 是 --> C{正式评审};
C -- 否 --> A;
C -- 是 --> D(配置项);
D -- Check In --> E[(存储库<br>需求基线<br>设计基线<br>…)]
E -- Check Out --> F{变更控制};
F -- 批准 --> A;
style E fill:#eee,stroke:#333,stroke-width:1px
SCM 活动
SCM 主要包括以下活动:
- 标识配置项:确定哪些制品需要纳入 SCM 管理,并为每个配置项分配唯一的标识符。
- 版本管理(Version Control):管理配置项随时间发生的变更,记录不同版本,允许多人协同工作。
- 问题:并发修改可能导致覆盖丢失(Lost Update)。
- 解决方案:
- 锁定-修改-解锁(Lock-Modify-Unlock):用户修改前锁定文件,阻止他人修改,完成后解锁。简单但可能降低并发性,易发生死锁或长时间等待。
- 拷贝-修改-合并(Copy-Modify-Merge):用户拷贝文件到本地修改,完成后尝试合并回仓库。如果仓库版本已被他人修改,需要解决冲突。这是 Git, SVN 等现代版本控制系统的常用模式。
- 变更控制(Change Control):对基线化配置项的修改请求进行管理、评估、批准或拒绝的正式流程。
- 通常涉及变更请求表单(Change Request Form) 和变更控制委员会(Change Control Board, CCB)。
graph TD A(提请者<br>提出变更) --> B(接收者<br>接受变更请求); B --> C(评估者<br>变更评估); C --> D{变更表单}; D --> E(变更控制委员会<br>变更决策); E -- 批准 --> F(修改者<br>执行变更); E -- 拒绝 --> G((结束)); F --> H(验证者<br>验证变更); H --> I((结束)); style A fill:#f9f,stroke:#333,stroke-width:1px style B fill:#f9f,stroke:#333,stroke-width:1px style C fill:#f9f,stroke:#333,stroke-width:1px style E fill:#f9f,stroke:#333,stroke-width:1px style F fill:#f9f,stroke:#333,stroke-width:1px style H fill:#f9f,stroke:#333,stroke-width:1px
- 配置审计(Configuration Auditing):验证配置项是否完整、准确,是否符合基线要求,以及变更控制流程是否被遵守。
- 状态报告(Status Reporting/Accounting):记录和报告配置项的状态、变更历史和审计结果,提供项目可见性。
- 软件发布管理(Release Management):管理软件产品的构建、打包和交付过程。
分支管理策略(Branching Strategy)
版本控制系统通常支持分支,以隔离不同的开发活动。常见的分支策略(以 Git Flow 为例):
- 主分支(Master/Main):存放正式发布的、稳定的版本,通常只接受来自 Release 或 Hotfix 分支的合并。每个提交都应打上版本标签(Tag)。
- 开发分支(Develop):作为日常开发的主集成分支,汇集所有已完成的功能。新功能开发从 Develop 分支拉出。
- 临时性分支:
- 功能分支(Feature):用于开发新功能。从 Develop 拉出,完成后合并回 Develop。
feature/xxx
- 预发布分支(Release):用于准备发布新版本。从 Develop 拉出,进行测试、缺陷修复、文档更新等。完成后合并回 Develop 和 Master。
release/vx.y
- 修补 Bug 分支(Hotfix):用于紧急修复 Master 分支上的 Bug。从 Master 拉出,修复后合并回 Master 和 Develop。
hotfix/vx.y.z
- 功能分支(Feature):用于开发新功能。从 Develop 拉出,完成后合并回 Develop。
gitGraph
commit id: "0" type: HIGHLIGHT tag: "v0.1"
branch develop
checkout develop
commit id: "d1"
commit id: "d2"
branch feature/A
checkout feature/A
commit id: "fA1"
commit id: "fA2"
checkout develop
commit id: "d3"
checkout feature/A
commit id: "fA3"
checkout develop
merge feature/A id: "m1"
commit id: "d4"
branch release/0.2
checkout release/0.2
commit id: "r1"
commit id: "r2" type: REVERSE
checkout main
merge release/0.2 id: "m2" type: HIGHLIGHT tag: "v0.2"
checkout develop
merge release/0.2 id: "m3"
commit id: "d5"
checkout main
branch hotfix/0.2.1
checkout hotfix/0.2.1
commit id: "h1" type: REVERSE
checkout main
merge hotfix/0.2.1 id: "m4" type: HIGHLIGHT tag: "v0.2.1"
checkout develop
merge hotfix/0.2.1 id: "m5"
Git 工作区
Git 有三个主要区域:
- 工作区(Working Directory):你实际修改文件的区域。
- 暂存区(Staging Area/Index):标记下次要提交(commit) 的文件快照。
git add
将文件从工作区添加到暂存区。 - 版本库(Repository/
.git
directory):存储项目的元数据和对象数据库(所有提交历史)。git commit
将暂存区的文件快照永久保存到版本库。
暂存区的存在增加了灵活性,允许你选择性地提交文件的部分修改,或者在提交前整理提交内容。