软工Ⅱ复习
第一、二章
名词:软件工程
- 应用系统的、规范的、可量化的方法来开发、运行和维护软件,即将工程的方法应用于软件
- 对1中方法的研究
从1950s~2000s之间的特点
- 50s:
- 虚拟计算机:出现大型计算机
- 软件抽象实体:软件依赖于硬件,被视为硬件的一部分;指令码(第1代语言)、汇编码(第2代语言)
- 主要现实问题:科学计算
- 开发:像生产硬件一样生成软件
- 思想:软件的硬件的一部分
- 总结:科学计算;以机器为中心进行编程;软件是硬件的一部分
- 60s:
- 虚拟计算机:IBM,商业大型机
- 软件抽象实体:第三代语言,提供函数机制
- 主要现实问题:业务应用
- 开发:build-fix
- 思想:软件不同于硬件;用软件工程的方式生产软件
- 总结:业务应用;软件不同于硬件;用软件工程的方式生产软件
- 70s:
- 虚拟计算机:微型计算机,便宜了
- 软件抽象实体:结构化程序设计(函数过程、块、三种基本控制结构(顺序、分支、循环))
- 主要现实问题:软件花费超过硬件
- 开发:瀑布模型;结构化设计(数据流图DFD、实体关系图ERD、结构图)、结构化分析
- 思想:越早发现和修复问题,代价越低
- 总结:结构化方法;瀑布模型;强调规则和纪律
- 80s:
- 虚拟计算机:PC
- 软件抽象实体:面向对象编程
- 主要现实问题:软件维护上费用超过软件开发
- 技术:结构化方法;OO编程;软件复用
- 开发:过程模型(原型、渐进交付、演化、螺旋);过程评价;使用工具
- 思想:没有银弹(无法回避、轻易解决所有问题);重视人的作用
- 总结:追求生产力最大化;现代结构化/面向对象编程广泛使用;重视过程的作用
- 90s:
- 虚拟计算机:万维网
- 软件抽象实体:面向对象分析与设计方法
- 主要现实问题:大规模软件
- 技术:OO方法(设计模式、原则);软件体系结构;人机交互;需求工程;软件复用(框架、构件);web开发
- 开发:过程模型RUP;过程改进;开源软件
- 思想:重视最佳实践方法
- 总结:企业为中心的大规模软件开发;追求快速开发、可变更新和用户价值;Web应用出现
- 00s:
- 虚拟计算机:嵌入式设备、移动端
- 软件抽象实体:OO改进,UML
- 主要现实问题:基于internet应用;面向消费大众
- 开发:敏捷方法
- 总结:大规模Web应用;大量面向大众的Web产品;追求快速开发、可变更新、用户价值和创新
第四章
团队特征
- 共同目标
- 共担责任
- 技能互补
- 明确结构
几种团队结构
类型 | 示意 | 好处 | 坏处 |
---|---|---|---|
主程序员团队 | 规模小时效率高,保证一致性 | 1)主程序员一旦出错代价大,瓶颈 2)降低积极性,底下难交流 |
|
民主团队 | 1)参与度高 2)意见好表达 3)最大发挥团队成员的创新能力 |
决策效率低 | |
开放团队 | 黑箱管理 | 进度没有可视度 |
项目质量保障有哪些措施
- 软件开发过程不可见+越晚发现缺陷、修复代价越高 → 质量保证活动要贯穿整个开发过程独立、持续地进行
- 评审:需求评审、体系结构评审、详细设计评审、代码评审
- 度量:需求度量、设计度量、代码独立、测试度量
- 集成测试 测试度量
实验中如何进行配置管理活动
- 标识配置项(有哪些需要保存的管理,设置ID,说明特征,如生产者,基线建立时间,使用者等)
- 版本控制(版本号)
- 变更控制(发生变更时需要提交请求、评估、决策、执行等)
- 配置审计(定期进行,验证完整性、正确性,通常在交付or发行前、开发结束后或维护工作中)
- 状态报告
- 软件发布管理
名词:配置项
置于软件配置管理之下的软件配置的各组相关项目,包括各类管理文档、评审记录雨文档、软件文档、源码和可执行文件、运行所需的系统软件和支持软件以及有关数据。
(复习提纲无这个)
第五章
名词:需求
- 用户为了接解决问题或达到某些目标所需要的条件或能力
- 系统或系统部件为了满足合同、标准、规范或其它正式文档所规定的要求而需要具备的条件或能力
- 对1或2中的一个条件或一个能力的一种文档化表述
需求层次/类型
https://www.cnblogs.com/cpaulyz/p/12470218.html
第七章
为什么需要需求规格说明?
-
软件开发过程中会将开发任务细分为多个子任务分配给不同的人员,分解的子任务之间需要相互沟通和交流。
-
子任务和人员间存在错综复杂的关系,存在大量沟通与交流,所以软件系统开发中需要编写多种不同类型的文档来针对项目中需要进行广泛交流的内容。
-
用例文档以用户的角度以用例文本来描述系统和外界交互;需求规格说明文档从软件产品角度以系统级需求列表方式描述系统解决方案
对给定的需求示例,判定并修正其错误
主要考虑需求书写要点
-
使用用户术语
- 不要使用“类、函数、参数、对象”等计算机术语
-
可验证
- 不要用模糊和歧义词汇
- R1:用户查询界面应该友好 x
- R1:用户完成任何一个操作鼠标点击次数都不能超过5次 √
-
可行性
- 技术上、成本上
对给定的需求示例,设计功能测试用例
第八章
名词:软件设计
- 软件设计指软件实现的规格说明,也指产生这个规格说明的过程
- 软件设计是一份软件设计工程师创造的设计规格说明,包含软件设计描述和软件原型,保证软件能够满足需求规格,在一定的时间、费用、人员等限制条件下能够将软件部署在一定的物理环境里,达到业务目标。
- 工程设计和艺术设计都很重要。既要用系统化的方法构造软件内部结构,进行折中的设计策划,也要从艺术人员角度出发,注重效率和优雅。
- 设计过程是演化和迭代的
- 软件设计是问题求解和决策的过程;问题空间是用户的需求和项目约束,解空间是软件设计方案。这个过程叫决策。
软件设计的核心思想是什么?
- 主要思路:分而治之
- 核心思想:分解、抽象
- 分解:横向上将系统分割为子系统以及子系统之间的联系
- 抽象:纵向上分离接口和实现
软件工程设计有哪三个层次?各层的主要思想是什么?
-
高层设计,反映软件高层抽象的构建层次,描述高层结构、关注点和设计决策,主要是部件、连接件、配置
-
中层设计,关注构成组件的模块划分、导入导出、过程之间调用关系、类之间协作(模块化、信息隐藏、OO原则)
-
底层设计,深入模块和类内部,关注数据结构、算法、类型、语句、控制结构等(代码设计)
-
体系结构设计——高层和部分中层
-
详细设计——中层和部分底层
-
构造阶段——部分底层
第九、十章
体系结构的概念
软件体系结构 = 部件 + 连接件 + 配置
- 部件:承载系统主要功能
- 连接件:定义部件间交互(和部件平等)
- 配置:定义了部件和连接件之间的关联
一个软件系统的体系结构定义了系统的计算部件和部件之间的交互
四种体系结构的风格的优缺点
- 主程序/子程序
- 上层调用下层,下层不可调用上层;单线程;上层转移控制权
- 优点:流程清晰,易于理解;强控制性
- 缺点:强耦合,依赖交互方的接口规格,难以修改和复用;限制数据交互,可能产生公共耦合、
- 面向对象风格
- 对象隐藏内部数据,提供对外接口服务;通过方法调用来连接;对象维护自身数据一致性和完整性;自治单位
- 优点:内部实现可修改;易开发、易理解、易复用
- 缺点:接口耦合性;标识耦合性(需要有交互对象的标识);OO的副作用(如重入问题)
- 分层
- 下层为上层提供服务,上层调用下层;层次之间遵守协议;禁止跨层次连接;禁止逆向连接
- 优点:设计机制清晰,易于理解;支持并行开发;可复用性、内部修改性
- 缺点:交互协议难以修改;禁止跨层调用,可能会有冗余调用而性能损失;难以确定层次数量和粒度
- MVC
- 用户行为要通过控制层
- 优点:易开发性;视图、控制在开发中易修改性;多视图,适用web开发
- 缺点:复杂;模型修改难(视图和控制都依赖于它)
体系结构设计的过程
- 分析关键需求和项目约束
- 选择合适的体系结构风格
- 进行体系结构逻辑(抽象)设计
- 根据逻辑设计进行体系结构物理(实现)设计
- 完善体系结构设计
- 添加构件接口
- 迭代3~7
包设计原则
- 内聚
- 共同封闭原则 CCP
- 一起修改的类放在一起
- 越大越好
- 早期,对开发者而言
- 共同重用原则 CRP
- 一起被重用的放在一起
- 越小越好
- 后期,对重用者
- 重用等价发布原则 REP
- 包的目的是给人别人重用
- 重用的粒度就是包的粒度
- 共同封闭原则 CCP
- 耦合
- 无环依赖原则 ADP
- 包的依赖结构是一个有向无环图
- 抽取公共依赖or抽取接口
- 稳定依赖原则 SDP
- 依赖关系随着稳定的方向
- 依赖稳定的包,稳定性 = 依赖别人 / (依赖别人+别人依赖)
- 稳定抽象原则 SAP
- 稳定的包应该是抽象的,不稳定的包是具体的
- 无环依赖原则 ADP
体系结构构建之间接⼝的定义
p144
集成测试
p177
- 大爆炸式
- 持续集成
- 自顶向下
- 一个Driver,下层用stub,不断用下层模块来代替stub
- 按深度优先可以首先验证一个完整的功能需求;利于定位故障
- 桩开发量大;底层测试不充分
- 自底向上
- 用Driver来替代上层
- 桩工作量小;底层组件开发可以并行;利于故障定位
- 驱动开发量大;高层测试不充分
- 持续集成
- 每次完成一些开发任务后就用开发结果来替代stub测试
- 自顶向下
十一章
名词:可用性
衡量人机交互设计的目标,多维度的质量属性
- 易学性:新手用户容易学习;完全没有培训的用户完成特定任务所需的时间
- 效率:熟练用户完成特定任务需要的时间
- 易记性:以前使用过系统的用户完成特点任务需要的时间
- 出错率:用户使用系统时犯多少错、错误多严重、能否从错误中容易地恢复
- 主管满意度:用户体验,调查问卷
人机交互三因素
- 人
- 精神模型
- 用户总是看到自己想看的
- 精神模型就是人机交互时头脑中的人物模型。用户识别图像,根据隐喻将控件和熟悉事务联系起来。
- 差异性
- 不同群体的任务模型不同,比如新手用户、熟练用户、专家用户
- 为不同用户群体提供差异化的交互机制。比如为新手提供GUI,为专家提供命令行、快捷方式、热键
- 精神模型
- 计算机
- 可视化设计
- 不要暴露内部设计
- 展示细节
- 可视化设计
- 交互
- 导航
- 为用户提供完成任务的入口,好的导航符合精神模型
- 菜单导航、快捷方式导航、列表导航、状态栏导航、按钮导航
- 反馈
- 对用户行为进行反馈,让用户意识到行为的后果
- 声音、视觉...
- 交互原则(重点)
- 简介设计:图片比描述文字更清晰。7±2原则,有效表达下越简洁越好
- 一致性设计:相似的任务相似的交互;与已有的软件类似,遵循用户已有的精神模型
- 低出错率设计:避免错误操作(disabled button);错误提示;故障恢复手册
- 易记性:减少记忆负担(自动补全、提示);逐层递进地展示;直观的快捷方式(图片按钮);设置有意义的默认值
- 导航
例⼦**违反了哪些条界⾯设计原则
精神模型、差异性
导航、反馈、协作式设计
第十二章
详细设计的出发点
- 需求开发的结果(需求规格说明和需求分析模型)
- 软件体系结构的结果(软件体系结构设计方案与原型)
职责分配
-
信息专家:
- 把职责分配给有实现功能必需的信息的类
-
创造者:
-
实际应用中,符合下列任一条件的时候,都应该由类A来创建类B,这时A是B的创建者:
a. A是B的聚合
b. A是B的容器
c. A持有初始化B的信息(数据)
d. A记录B的实例
e. A频繁使用B
-
-
控制器
-
将处理外部传来的系统事件信息的职责分配给一个类
a. 系统事件的接收与处理通常由一个高级类来代替。
b. 一个子系统会有很多控制器类,分别处理不同的事务。
-
协作
每个类/方法的职责有限,对象之间进行协作可以完成更大的的职责
- 从小到大,将对象的小职责聚合形成大职责
- 从大到小,将大职责分配给各个小对象
控制风格
为了完成大职责,需要对职责分配做决策。控制风格决定了决策由谁来做和怎么做决策。
设计类图
P203 表12-2
详细顺序图
P206 表12-3
第十三章
名词:耦合(结构化设计)
描述两个模块间关系的复杂程度
名词:内聚(结构化设计)
一个模块内部的联系的紧密性
信息隐藏的思想
每个模块承担着一定的职责,对外表现为一份契约,并且在这份契约之下隐藏着只有这个模块知道的设计决策或秘密,决策实现的细节只有模块自己知道
封装类的职责,隐藏职责的实现;预计将发生的变更,抽象它的接口,隐藏内部实现机制
- 主要秘密:实现的用户需求
- 次要秘密:实现细节,如数据结构、算法
两种常见的信息隐藏决策
- 根据需求分配职责
- 内部实现机制
第十四、十五章
OO耦合
-
访问耦合
降低方法:
- 面向接口编程
- 接口分离原则
- 迪米特法则
-
继承耦合
降低方法:
- 里氏替换原则
- 组合代替继承
模块化原则
-
全局变量是危险的
-
显示一些
martin.data["firstname"] = "Martin"; // 不好 martin.firstName = "Martin"; // 好
-
不要重复
-
面向接口编程
-
迪米特法则
不和陌生人说话——引入局部变量、委托
-
接口分离原则
面向最小接口
-
里氏替换原则
父类能被子类代替;require no more,promise no less
-
组合代替继承
-
单一职责原则
信息隐藏原则(接上)
- 封装
隐藏内部结构(迭代器)、隐藏内部对象(给副本,不给引用)
- 权限最小化原则
- 开放/关闭原则
对扩展开放、对修改关闭;多态增加新类型(变更放在子类中)
- 依赖倒置原则
改变耦合的方向性;高层依赖接口,底层实现接口;LSP作为保障,实现OCP
第十六章
如何实现可修改性、可扩展性、灵活性
接口和实现分离
第十七、十八章
名词:重构
- 修改软件系统的严谨方法,在不修改外部表现的情况下改进内部结构
- 时机:增加新功能时(完成后、消除新功能带来的坏味道);发现缺陷进行修复时;代码评审时
名词:测试驱动开发
- 测试优先的开发,随着极限编程而普及
- 在编写代码前优先完成该段代码的测试代码,由测试工具自动装载执行,也可以程序员手动执行。完成测试代码后,程序员再编写程序代码,并在编程过程中重复执行测试代码,以验证程序代码的正确性。
名词:结对编程
思想:两个程序员挨着坐在一起,共同协作进行软件构造活动
驾驶员:输入代码
观察员:评审,考虑战略性方向
两个程序员经常互换角色
软件构造包含活动
- 详细设计
- 编程
- 测试
- 调试
- 代码评审
- 集成与构建
- 构造管理
给定代码段示例,对其进行改进或者 发现其中的问题
- 易读性:代码缩进;相关逻辑组织在一起(成员变量生命、构造析构、public、private...);空行分割;命名;注释
- 易维护:
- 小型任务:方法的代码内聚,恰好完成一个功能与目标
- 复杂决策:用新的布尔变量(多个布尔运算);封装决策;表驱动
- 数据使用:命名、全局变量
契约式设计
思想:在前置条件满足下开始执行,完成后能满足后置条件,那么这个函数或方法就是正确、可靠的
-
异常方式:
// 前置检查 if (...){ throw new Exception("...."); } // do... // 后置检查 if (...){ throw new Exception("...."); }
测试驱动开发也是一种契约式设计,把契约放在测试用例中
-
断言方式:
// 前置检查 assert() // do... // 后置检查 assert()
防御式编程
思想:与其他方法、操作系统、硬件等外界环境交互时,外界发生错误,保护方法内部不受损害
- 异常
- 断言
相同:
都要检查输入参数的正确性
差异:
防御式编程将所有与外界的交互都纳入防御范围,如IO、有效性等
防御式编程不检查后置条件,交给使用者自行检查
设计测试用例
第十九章 软件测试
黑盒测试
完全基于输入和输出数据来判定测试对象的正确性,使用规格说明来设计输入和输出
- 等价类划分:把输入域划分为若干部分,从每部分选取少数具有代表性数据作为测试用例
- 边界值划分:等价类的边界
- 决策表
- 状态转换
白盒测试
不关心测试对象的规格,按照测试对象内部的程序结构来设计测试用例进行测试
- 语句覆盖:每条语句都至少执行一次
- 条件覆盖:每个判断的结果至少执行一次
- 和语句覆盖的区别在于只有if没有else的情况下,条件覆盖要都有,语句覆盖只要单侧
- 路径覆盖:每条路径至少执行一次
第二十、二十一章
开发可维护软件的方法
- 考虑软件的可变更性
- 需求分析时候,分析需求的稳定性,预测可能发生的变化
- 设计时,使用信息隐藏,OCP等方法
- 为降低维护难度而开发
- 技术文档
- 代码可读性
- 维护需求跟踪链 “需求←→设计←→编码←→测试”
- 维护回归测试集线
演化式生命周期模型
包括初始开发、演化、服务、逐步淘汰、停止五个阶段
-
初步开发:第一个版本,重要工作是建立一个好的软件体系结构
-
演化:新增需求、变更需求、修改缺陷
↓转换
- 丧失可演化性
- 没有业务价值
- 竞品
-
服务:仍被部分用户使用,但不是重点。周期性修复bug、少量需求增量
-
逐步淘汰:不维护
-
停止:用户不再使用
逆向工程
处理遗留软件时,可能是一个没有任何文档和源程序的软件,这时候就需要逆向工程
思想:抽取软件系统的需求与设计而隐藏实现细节,然后在需求和设计的层次上描述软件系统,以建立对系统更加准确和清晰的理解
再工程
逆向工程是理解软件,而不修改软件,再工程是对软件修改,而不花大力气理解软件,因此在处理遗留软件时,需要逆向工程前导。
检查和改造一个目标系统,用新的模式及其实现来复原该目标系统。目的是对遗留软件系统进行在开发,用新技术来改进。
已有系统 (逆向工程)→ 抽象视图 (再工程)→ (正向工程)→ 再工程系统
第二十二、二十三章
构建-修复模型 build-fix
构建第一个版本 → 修复 → 修复 → ... → 维护
- 缺点:
- 没有规范,复杂度一旦超出个人控制能力就会失败
- 没有分析需求、考虑体系结构、测试和可维护性,也没有任何文档
- 适用:
- 软件规模很小,几百行程序,个人开发
- 对质量要求不高,出错也无所谓
- 只关注开发,不用维护
瀑布模型
文档驱动,分为需求分析、软件设计、软件构造、软件测试、软件交付、软件维护
-
允许反复和迭代
-
每个活动结束都需要进行验证
-
缺点
- 文档期望过高(成本工作量大、很难为变更的需求建立完备的文档)
- 线性假设局限性(需要一定后续工作后才能验证)
- 里程碑颗粒过粗(丧失早发现缺陷早修复)
-
使用
- 需求成熟、稳定
- 使用技术成熟、稳定,没有不确定的技术难题,没有开发人员不熟悉
- 复杂度适中,不会有太大文档负担和过粗里程碑
增量迭代模型
需求驱动,迭代式、渐进交付和并行开发
-
第一个迭代完成核心内容,满足基本需求
-
少量的不确定性和影响不大的变更通过迭代的方式加以解决
-
优点
- 迭代式,符合软件开发实践
- 渐进交付,加强用户反馈
- 并行开发,缩短软件开发时间
-
缺点:需要一个完备、清晰的项目前景
-
适用性:大规模软件系统开发
演化模型
和增量迭代模型类似,不同在于模糊了维护和新开发的界限
- 优点:同上
- 缺点:在前代基础上修改和扩展,容易让后代忽略分析和设计工作,变成build-fix
- 适用:不稳定领域的开规模软件开发
原型模型
-
抛弃式原型:解决不确定性,用于建立需求,用完抛弃
-
演化式原型:成为产品的一部分,必须有很好的质量
-
优点:
- 加强了与客户、用户的交流
- 适用于非常新颖的领域,因为这些领域有不确定性
-
缺点:
- 原型开发成本时间高
- 很多时候不舍得抛弃“抛弃式原型”,使得质量差的代码进入产品
-
适用:有大量不确定性的新颖领域
螺旋模型
风险驱动,充分利用原型方法解决风险
思想:尽早解决比较高的风险,如果无法解决,那么早发现比项目结束时再发现好,至少损失少得多
分为制定计划、风险评估、实施工程、客户评估四个象限,开发阶段是瀑布式的,风险分析是迭代的
- 与原型模型相比,原型只解决需求不确定性,螺旋模型还解决项目开发中常见的各组类型风险
- 优点:降低风险
- 缺点:
- 同原型
- 模型过于复杂,不利于管理者依据其组织软件开发活动
- 适用:大规模高风险软件开发
Rational 统一过程模型 RUP
四个阶段:初始、细化、构造、交付
核心过程工作流:商业建模,需求、分析和设计、实现、测试、部署
核心支持工作流:配置和变更管理、项目管理、环境
- 优点:
- 吸取和借鉴实践方法
- 可以进行裁剪,适用面广
- 有工程工具支持
- 缺点:
- 没有考虑交付后的维护问题
- 裁剪和配置困难
- 适用:
- 重量级/轻量级