文章目录
Chapter01-软件工程学概述
-
软件工程三要素:方法、工具、过程
-
方法:为软件开发提供 “如何做” 的技术。
- 工具:软件工具为软件工程方法提供了自动的或半自动的软件支撑环境
- 过程:软件过程是指制作软件产品的一组活动及其结果。
- 方法,工具和过程 三要素必须围绕质量开展
-
软件危机的表现主要有以下几个方面
- 软件成本日益增长
- 开发进度难以控制
- 软件质量差
- 开发过程无法有效介入和管理
- 代码难以维护等
-
软件工程的基本原理(开发与维护的指导)
- 用分阶段的生命周期计划严格管理
- 坚持进行阶段评审
- 实行严格的产品控制
- 采用现代程序设计技术
- 结果应能清楚地审查
- 开发小组的人员应该少而精
- 承认不断改进软件工程实践的必要性
-
软件生命周期由软件定义、软件开发和运行维护(也称为软件维护)3个时期组成,每个时期又进一步划分成若干个阶段。
-
瀑布模型
-
需求分析->规格说明->设计->编码->综合测试->维护
-
阶段间具有顺序性和依赖性
-
每个阶段都必须提交文档
-
经过仔细的质量验证
-
V模型:非常明确地标明了设计过程和测试过程中存在的不同级别;
并且清楚地描述了这些测试阶段和开发过程期间各阶段的对应关系。
-
-
快速原型模型
-
它所能完成的功能往往是最终产品能完成的功能的一个子集(强调要快速)
-
快速原型模型是不带反馈环的
-
原型系统已经通过与用户交互而得到验证,据此产生的规格说明文档正确地描述了用户需求
-
-
增量模型
- 第一个增量构件往往实现软件的基本需求,提供最核心的功能
- 能在较短时间内向用户提交可完成部分工作的产品
- 在把每个新的增量构件集成到现有软件体系结构中时,必须不破坏原来已经开发出的产品
-
螺旋模型
- 使用原型及其他方法来尽量降低风险
- 把它看作在每个阶段之前都增加了风险分析过程的快速原型模型。
-
喷泉模型
-
-
Rational统一过程-最佳实践
- 迭代式开发
- 管理需求
- 使用基于构件的体系结构
- 可视化建模
- 验证软件质量
- 控制软件变更
-
RUP-软件生命周期四个阶段
初始阶段: 建立业务模型,定义最终产品视图,并且确定项目的范围。
精化阶段: 设计并确定系统的体系结构,制定项目计划,确定资源需求。
构建阶段: 开发出所有构件和应用程序,把它们集成为客户需要的产品,并且详尽地测试所有功能。
移交阶段: 把开发出的产品提交给用户使用 -
敏捷过程:
-
敏捷过程的四条价值观:
人员交流重于过程与工具
软件产品重于长篇大论
客户协作重于合同谈判
随机应变重于循规蹈矩
-
Chapter02-可行性研究
-
可行性研究的概念:可行性研究必须从系统总体出发,对技术、经济、财务、商业以至环境保护、法律等多个方面进行分析论证,以确定建设项目/产品是否可行,为投资决策提供科学依据。
-
可行性研究的目的是做还是不做
-
可行性研究的内容:可以从技术可行性、经济可行性、用户操作可行性、社会环境可行性等方面评价系统是否值得做,是否能做
-
典型可行性研究过程的步骤
(1)确定项目/产品规模和目标;
(2)研究当前正在运行的系统;
(3)建立新系统的高层逻辑模型;
(4)导出和评价各种方案;
(5)推荐可行的方案;
(6)草拟开发计划;
(7)编写可行性研究报告,提交审查
Chapter03-需求分析
-
需求分析的目的是分析系统必须做什么。该阶段需要给出软件需求规格说明书
-
业务需求:客户对于系统的高层次目标要求,定义项目的远景和范畴
-
用户需求:从用户角度描述系统功能需求与非功能需求,通常只涉及系统对外表现出的行为而不涉及系统内部特性。
-
功能需求:系统应该提供的功能或服务
-
性能需求:一个系统或系统构件必须具有的性能特性
-
非功能性需求:从各个角度对系统进行约束和限制,反映了客户对软件系统质量和特性的额外要求,如数据精度、可靠性等。
-
外部接口需求:描述系统与其所处环境之间进行的交互
功能模型的构建
DFD绘制
-
数据流图(Data Flow Diagram,DFD):以图形方式来表达系统的逻辑功能、数据在系统内部的逻辑流向和逻辑变换过程
-
步骤:顶层DFD图->一级细化->二级细化
-
数据流图分层细化时,必须保持信息的连续性,即细化前后对应功能的输入输出数据必须相同。
-
数据存储和数据流都是数据,仅所处的状态不同
-
每个数据处理都应该有输入输出
-
除流入流出数据存储的数据流可以命名相同之外,其他的数据流命名需要唯一,即便是同样内容
-
DFD主要纠错点:
- 外部实体之间不可能有数据流
- 外部实体不可能直接写数据
- 加工输入输出流不可以同名
- 加工不可能只有输出或输出
数据模型的构建
数据字典
-
对于数据流图中出现的所有被命名的图形元素在字典中作为一个词条加以定义,使得每一个图形元素的名字都有一个确切的解释。
-
数据字典中的符号表示:
-
数据字典中对数据处理的描述方法
-
自然语言
-
判定表
-
判定树
-
ER图
ER图(Entity Relationship Diagram)是在数据字典的基础上,用来建立数据模型的工具。
数据模型中包含3种相互关联的信息:数据对象(实体)、数据对象的属性及数据对象彼此间相互连接的关系。
-
数据规范化
-
规范化是将数据的逻辑结构归结为满足一定条件的二维表(关系)
-
通常用“范式(Normal Forms)”定义消除数据冗余的程度。
-
第一范式:不能表中有表
-
第二范式:用关键字划分
-
第三范式:非主属性之间无依赖关系
-
-
-
需求验证与确认贯彻整个软件生命周期
-
验证软件需求四方面:一致性、完整性、现实性和有效性
Chapter04-总体设计
总体设计要解决的问题是系统应该如何实现
软件设计的内容
- 软件设计的四方面内容:架构、接口、数据、过程设计
软件架构概述
软件架构关注的是:如何将复杂的软件系统划分为模块、如何规范模块的构成和性能、以及如何将这些模块组织为完整的系统。
- 构件
- 构件是一个抽象的概念,任何在系统运行中承担一定功能、发挥一定作用的软件体都可看作是构件。
- 构件作为一个封装的实体,只能通过其**接口(Interface )**与外部环境交互,表示了构件和外部环境的交互点,内部具体实现则被隐藏起来(Black-box)
- 连接件
- 连接件(Connector):表示构件之间的交互并实现构件之间的连接。
- 需要有连接的物质基础和信息交换的规则
软件架构的风格
-
调用-返回风格
以函数/对象作为基本构造单元,彼此通过call-return相互连接
特征:不考虑分层,主要遵循同步调用方式 -
以数据为中心的风格
数据的持久化存储被分离出去,形成两层结构
-
层次风格
除了数据被分离出去,软件系统的其他各部分进一步分离,形成更复杂的层次结构
-
C/S架构(Client-Server)
5.B/S架构(Browser-Server)
软件架构设计原理
模块化、抽象、逐步求精、信息隐藏、模块独立(必考)
-
模块化:
- 定义:模块是作为一个整体来处理的一级独立的、可识别的程序指令。是大型程序指令的组成部分
- 模块化就是把程序划分成独立命名且可独立访问的模块,每个模块完成一个子功能,把这些模块集成起来构成一个整体,可以完成满足用户的需求的指定功能。
- 并不是说模块划分越多越好,这样反而会导致接口更加复杂,成本上升。
- 优点:结构清晰,容易设计;便于调试,增强可靠性;提高软件的可修改性;便于组织管理
-
抽象:
- 软件开发实际上就是一个从高层次抽象到低层次抽象逐步过渡的过程。
-
逐步求精:(解决主要矛盾)
-
定义:为了能集中精力解决主要问题而尽量推迟对问题细节的考虑。
-
原则:把精力集中在与当前开发阶段最相关的那些方面;忽略那些对整体解决方案来说虽然是必要的,然而目前还不需要考虑的细节;以后再考虑细节
-
抽象和求精是互补的过程
- 抽象→ 过程, 数据, 忽略底层细节
求精→ 设计中揭示出底层细节
- 抽象→ 过程, 数据, 忽略底层细节
-
-
信息隐藏和局部化:
- 一个模块内部包含的信息(过程和数据)对于不需要这些信息的模块来说,是不能访问的。
- 应该隐藏的不是有关模块的一切信息,而是模块的实现细节----- “细节隐藏”
- 局部化是指把一些关系密切的软件元素物理地放得彼此靠近。
- 信息隐藏和局部化便于软件的测试和维护
-
模块独立:
-
定义:每个模块完成一个相对独立的子功能,并且和其他模块之间的关系很简单
-
衡量模块独立程度的两个度量标准:内聚、耦合
-
模块化设计的目标:高内聚、低耦合
-
耦合度
-
原则:尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,完全不用内容耦合
-
-
内聚:
-
软件架构的启发规则
- 改进软件结构提高模块独立性
- 模块规模应该适中
- 深度、宽度、扇出和扇入都应适当(尽量减少高扇出)
- 模块的作用域应该在控制域之内(一个模块的控制域,等于模块本身加上其下级模块,即可供它调用的模块。)
- 力争降低模块接口的复杂程度
- 设计单入口单出口的模块
- 模块功能应该可以预测
描绘软件架构的图形工具
了解即可,不是重点
面向数据流的架构设计方法
-
面向数据流的设计方法,是将数据流图变换成软件结构,通常也称为结构化设计方法(简称SD方法)
-
变换流:输入->加工处理->输出
-
事务流:输入->选一个动作执行->输出
-
变换分析设计步骤:
- 复查基本系统模型:确保系统的输入数据和输出数据符合实际。
- 复查并精化数据流图:确保数据流图给出了正确的逻辑模型,使数据流图中每个处理都代表一个相对独立的子功能。
- 确定数据流图具有变换特性还是事务特性
- 确定输入流和输出流的边界,从而孤立出变换中心。
- 完成“第一级分解”。最顶层的控制模块协调下述从属的控制功能
- 完成“第二级分解”。输入部分、转换部分、输出部分分别映射成接收模块、处理模块、输出模块。
- 使用设计度量和启发式规则对第一次分割得到的软件结构进一步精化。
接口设计:人机界面
很多常识性问题。
Chapter05-详细设计
- 详细设计的主要任务:为每个模块确定采用的算法。选择工具表达算法的过程,写出模块的详细过程描述(又称为过程设计);确定每一模块使用的数据结构;
结构程序设计
- 结构程序设计经典定义:如果一个程序的代码块仅仅通过顺序、选择和循环这3种基本控制结构进行连接,并且每个代码块只有一个入口和一个出口,则称这个程序是结构化的。
过程设计的工具
-
判定表
-
判定表能够清晰地表示复杂的条件组合与应做的动作之间的对应关系。
-
-
判定树
-
流程图
-
伪代码
程序复杂程度的定量度量
-
McCabe度量法:又称环路复杂性度量
实践表明,模块规模以V(G)≤10为宜。
Chapter06-实现(编码与测试)
- 实现=编码+测试
编码
-
代码注释:
- 不要解释程序是怎么工作的,程序本身就应该能说明只一点
- 很多课本中的代码对语法做注释,是为了让大家看明白语法,在实际开发不允许的
//不合适的注释示例 //this loop starts the i from 0 to len, in //each step, it does Something for (i = 0; i<len; i++){ DoSomeThing(); }
- 注释用来解释程序做什么(What),为什么这样做(Why),以及要特别注意的地方。
//合适的注释 //go thru the array, note the last element //is at [len-1] for (i = 0; i<len; i++){ DoSomeThing(); }
- 复杂的注释应该放在函数头,很多函数头的注释都是解释参数的类型等,如果程序正文已经能够说明参数的类型,就不要重复!
软件测试基础
- 软件测试的目标
- 测试的正确定义是“为了发现程序中的错误而执行程序的过程”。因此,测试的目标就是:发现程序中的错误。
- 测试不能证明程序是正确的。即使经过了最严格的测试之后,仍然可能还有没被发现的错误潜藏在程序中。
- 测试步骤:模块测试(单元测试)、子系统测试、系统测试、验收测试和平行运行。
单元测试
- 单元测试和编码属于软件过程的同一个阶段,主要使用白盒测试技术,而且对多个模块的测试可以并行地进行
集成测试
- 通过单元测试的模块要按照一定的策略组装为完整的程序,在该组装过程中进行的测试称为集成测试或组装测试。
白盒测试
- 路径测试
黑盒测试
- 等价测试和边界测试
- 把输入数据的可能值划分为若干个等价类,使每类中的任何一个测试用例,都能代表同一等价类中的其它测试用例。
- 划分等价类不仅要考虑代表“有效”输入值的有效等价类,还要考虑代表“无效”输入值得无效等价类;
- 每一个无效等价类至少要用一个测试用例,不然可能漏掉某一类错误,但允许若干个有效等价类合用一个测试用例,以便进一步减少测试的次数。
- 实践表明,程序员在处理边界情况时,很容易发生编码错误。例如,数组容量、循环次数以及输入数据与输出数据在边界值附近程序出错概率往往较大。
- 使用边界值分析方法设计测试方案首先应该确定边界情况,通常输入等价类和输出等价类的边界。选取的测试数据应该刚好等于、刚刚小于和刚刚大于边界值。
Chapter07-维护
-
定义:所谓软件维护就是在软件已经交付使用之后,为了改正错误或满足新的需要而修改软件的过程。
-
四种维护
改正性维护
适应性维护
完善性维护
预防性维护
chapter08-软件项目管理
- 所谓管理就是通过计划、组织和控制等一系列活动,合理地配置和使用各种资源,以达到既定目标的过程。
- 软件项目管理先于任何技术活动之前开始,并且贯穿于软件的整个生命周期之中。
(工程图在数据结构中有详细描述,此处不再赘述。)