软件工程笔记

软件工程

前言

  • 写编译器的时候深感自己的软工能力太弱了,速刷了一下很久就想自学的软工
  • 鸭大18计科没有软工课实在是太离谱了
  • UML 部分比较简略

绪论

  • 软件:程序+文档
  • 软件测试和系统维护开发占比高
  • 软件分类
    • 系统软件:e.g. 操作系统,编译器
    • 支撑软件:e.g. 中间件
    • 应用软件
  • 开发的本质:不断地抽象
    • 问题->需求->设计->实现
  • 软件工程是一门交叉学科,涉及计算机,工程,管理学等
  • 好的软件是设计出来的

软件过程

  • 软件生存周期

  • 软件生存周期模型/软件开发模型:软件过程、活动、任务的结构组织框架

  • 常见软件构件: WEB 应用、包或框架、独立环境系统等

  • 软件生存周期过程

    • 基本过程:获取,供应,开发,运行维护
    • 支持过程:e.g. 文档,配置,审计,验证
    • 组织过程:e.g. 基础设施,人力资源
    • 个人理解,广义上的软件工程就是涉及开公司的方方面面

瀑布模型

  • 分阶段开发:系统需求、软件需求、需求分析、设计、编码、测试、运行
  • 不允许跨阶段返工
  • 优点:强调编码前的设计
  • 缺点:必须提前确定需求;过分强调文档;直到开发完全结束前都不能演示系统
  • 客户其实很难在一开始就知道自已要什么,更不必提清晰地表达需求,让开发人员捕获需求
  • 通常用于较成熟的领域开发

增量模型

  • 需求可以分多阶段,每个增量的开发是一个瀑布模型
  • 优点:第一个版本的成本低
  • 缺点:若需求变化大,现有代码的修改成本高
  • 构造:不需要交付的增量;发布版本:需要交付的增量

演化模型

  • 根据用户的反馈不断获取新需求,每次演化的开发是一个瀑布模型
  • 优点:需求不明确时方便快速迭代
  • 缺点:管理需求高,容易不写文档;没有风险控制

喷泉模型

  • 用于描述面向对象的开发过程,软件开发各阶段间没有明显边界

螺旋模型

  • 反复:规划、风险分析、开发、评估
  • 类似增量模型,但是决策的风险源不止有需求;类似演化模型,但是加入了风险分析
  • 感觉模型种类字眼没有必要扣那么死,弄得很绕

快速原型模型

  • 开发原型是为了帮助获取用户真正的需求;测试项目中某些部分的技术、成本、进度等的可行性;即做一个 demo 看看

面向复用的软件开发模型

  • 面向可复用的软件构件的集成框架开发过程

软件需求

  • 产品经理入门

  • 需求

    • 分类:功能,性能,外部接口,设计约束,质量属性等
    • 基本性质:必要的,无歧义的,可测试的,可跟踪的,可测量的
  • 需求捕获方式:自悟,交谈,观察,会议,提炼等

  • 需求规约 SRS :需求陈述的正式文档,概念模型

    • 性质:重要性和稳定性程度,可修改的,完整的,一致的
    • 事实上的交付合同

软件开发方法学

结构化方法

  • 结构化设计哲学:一切都是数据流动

结构化分析

  • 建立数据流图 DFD ;自顶向下,逐层分解数据加工;建立数据字典
    • 数据源:数据流的起点,系统外的实体
    • 数据谭:数据流的终点,系统外的实体
  • 太抽象了,工作中感觉根本不会这么一丝不苟
  • 复杂度控制:上层数据可以打包,图元个数经验上应控制在$7\pm2$

结构化设计

总体设计
  • 总体设计分三阶段

  • 首先,把数据流图初步转化为模块结构图 MSD;自顶向下,逐层细化;确定系统与外部的接口

    • 分类处理:变换型数据流图、事务型数据流图
    • 大体上是一个机械过程
  • 其次,MSD 进一步模块和模块化;设计全局数据结构和每个模块的接口

    • 准则:高内聚,低耦合
    • 体现设计人员的智慧
    • 模块的作用域要在控制域之内
  • 最后,设计复审

  • 耦合

    • 内容耦合:一个模块直接修改/操作另一个模块的数据

    • 公共耦合:两个以上的模块共同引用一个全局数据项

    • 控制耦合:一个模块向另一个模块传递一个控制信号

    • 标记耦合:模块间通过界面传递复杂类型的数据

    • 数据耦合:模块间通过参数传递基本类型的数据

    • 原则:使用数据/标记耦合,少用控制耦合,限制公共耦合的范围,避免内容耦合

数据设计
  • 文件设计
    • 大的非结构化数据: e.g. 多媒体信息
    • 大的松散数据: e.g. 历史记录、档案
    • 非关系层次化数据: e.g. 系统配置文件
    • 临时数据
  • 数据库设计
    • 详见数据库
详细设计
  • 结构化程序设计:代码块仅仅通过顺序选择循环进行连接,且仅有单一入口和单一出口
    • “ goto 有害 ”:但偶尔有时候需要在效率和结构上平衡
  • 常见程序表达
    • 伪代码
    • 流程图/程序框图
    • PAD 图:支持逐步求精设计
    • N-S 图:支持逐步求精设计
    • 判定表/判定树
软件设计说明书&代码评审

敏捷开发

概念

  • 敏捷开发是应对快速变化的需求的一种增量式软件开发,是一种哲学理念和一系列开发指南的综合
  • 一般适应小而高度自主的团队开发小软件
  • 个人认为敏捷开发的核心是以人为本,重视每个人都发挥主观能动性,重视团队的力量而不是工具的作用
  • 本人第一次实习完全就是敏捷开发,体会很深

敏捷原则

  • 敏捷联盟宣言

    • 个体和交互胜过过程和工具:团队沟通强过个人编程能力;不要过分夸大工具的作用,要考虑团队的学习成本;团队的构建比环境的构建重要得多
    • 可以工作的软件胜过面面俱到的文档:没有文档是灾难,过多的文档更是灾难,尽可能维护一份系统原理和结构方面的文档
    • 客户合作胜过合同谈判:频繁与客户沟通反馈强过合同陈述,换句话说客户不单纯是甲方,而应与乙方协同工作;这有利于共同把事情做好,但是另一方面,可能导致无穷无尽的需求
    • 响应变化胜过遵循计划:计划不能考虑过远,响应变化的能力是决定软件成败的关键
  • 敏捷原则

    • 尽早地,持续地交付先跑起来
    • 开发后期也欢迎改变需求
    • 频繁交付,用户可见
    • 客户和开发人员合作开发
    • 激励信任开发人员,提供环境和支持
    • 强调面对面交流
    • 首要的进度标准是软件本身
    • 提倡可持续的开发速度
    • 不断关注优秀的技能和设计
    • 尽可能简单
    • 整个团队对整个项目负责任,成员也需要了解他人的工作
    • 团队不断反省调整

极限编程

  • 极限编程 XP:敏捷方法中最显著的一个,由一系列简单相互依赖的实践组成
    • 客户作为团队成员
    • “用户素材”,概念类似工单
    • 短的交付周期
    • 验收测试
    • 结对编程:尽可能两个人配对写
    • 测试驱动的开发,即尽可能先把测试流程跑起来
    • 集体所有权:没有程序员对一个特定模块或技术单独负责,所有人都应该关心负责一切扁平化管理?
    • 持续集成
    • 可持续的开发速度
    • 开放的工作空间
    • 规划游戏:开发人员提供多种开发选择,业务人员根据成本选择用户素材
    • 简单的设计
      • 尽可能用最简单的实现方法
      • 只有在较复杂的基础设施(数据库,远程过程调用,多线程等)使用明显合算时才引入
      • 不允许出现重复代码
    • 重构
    • 隐喻:架构善用比喻
  • 极限编程过程:策划、设计、编码、测试

敏捷设计

  • 敏捷设计
    • 避免僵化性:连锁改太多导致难以改动
    • 避免脆弱性:改动会影响概念上无关的部分
    • 避免粘固性:通用功能模块和某部分耦合程度太高难以复用
    • 避免粘滞性
      • 软件粘滞性:改动很容易破幻整体设计
      • 环境粘滞性:环境迟钝低效,如编译时间过长
    • 避免不必要的复杂性:设计中不要没有用的成分
    • 避免不必要的复制:不要简单 CTRL-CV
    • 避免晦涩性:模块不要难以理解
  • 基本途径
    • 不进行预先详细设计,预设计尽可能简单
    • 多单元测试和验收测试
    • 持续迭代
    • 坚持多种敏捷设计原则
    • 使用设计模式
  • 设计模式:经验的总结,对软件开发中一些反复出现、具有共性的问题给出的良好解决方案

面向对象方法

  • 面向对象设计哲学:一切都是对象

UML

  • UML 是系统分析和设计的工具,是面向对象软件工程使用的统一建模语言,是一种图形化的语言,主要以图形方式表示,是一种开放的标准

  • 多层次的设计图:每种图都展示系统的一个侧面

    • 维基
    • 系统静态部分
      • 类图
      • 构件图:说明构件之间的依赖关系
      • 组合结构图:可以看做类图的部分
      • 对象图:和类图类似,实例的快照
      • 部署图:系统物理视图
      • 制品图:展示制品之间的依赖关系
    • 系统动态部分
      • 用例图:需求模型回想起自己实习的时候问 mentor 什么是用例现在有点难绷
      • 状态图
      • 活动图:说明对象的操作流程,类似流程图
      • 时序图(顺序图)
      • 通信图:说明对象间的交互情况
  • UML 术语

    • 类:一组具有相同属性、操作、关系和语义的对象的描述
    • 对象:类的实例
    • 类间关系:依赖、关联、聚合、组合、泛化(继承)、实现
    • 太抽象了,很多概念术语这里暂略
  • 类图

  • 用例图
  • 时序图

面向对象分析

  • OOA 过程

    • 定义用例
    • 发现对象
    • 定义属性与操作
    • 建立对象间的关系
    • 划分包
    • 建立顺序图、状态图等
  • 识别关系策略

    • 个人认为,总体上需要领域知识和常识

    • 继承

      • 领域分类学知识
      • 常识
      • 根据继承定义
      • 考虑属性与操作的适用范围
      • 考虑领域复用
    • 关联

      • 考虑对象间的静态联系/责任
      • 考虑关联的属性与操作
      • 分析关联多重性

面向对象设计

  • 根本目标:提高软件生产率、提高质量
  • 和结构化设计不同,OOD 和 OOA 之间不存在鸿沟,不是转化关系,是调整和增补
  • 实现考量
    • 编程语言
    • 硬件
    • 复用支持
    • 数据管理系统
  • 可能的细节
    • 能复用尽可能复用
    • 增加一般类
    • 根据编程语言调整细节
    • 提高性能
      • 合并通讯频繁的类
    • 永久存储
    • 细化对象分类
  • 人机交互
  • 数据管理
    • 文件

      • 基本策略:一个类一个文件,一个对象一个记录
      • 继承处理:父子分文件存储,继承信息另外存储
      • 实现“对象存储器”类,并且增加一个接口来供类实现
    • 关系数据库

      • 通常第三范式

软件测试

  • 静态分析:对源代码进行分析审查

  • 动态分析:功能测试/黑盒测试;结构测试/白盒测试

黑盒测试

  • 把程序当做黑盒,尽可能穷举输入;数据驱动

  • 事务流图:事务的抽象,一种数据流图,太复杂,不怎么用

  • 等价类划分

    • “找代表”

    • 等价类:输入域的一个子集,该集合中的每个输入数据对于揭示程序中的错误都是等效的

    • 有效等价类

      • 输入有效的等价类
      • 寻找测例覆盖尽可能多的有效等价类,即覆盖多一些测试功能点,直至覆盖所有有效等价类
    • 无效等价类

      • 输入无效的等价类
      • 寻找一个测例覆盖一个无效等价类,直至覆盖所有无效等价类
  • 边界值分析

    • 找刚好在测试边界的测例以及刚好超过测试边界的测例
    • 用得多
  • 因果图

白盒测试

  • 根据程序逻辑结构测试

  • 路径测试 PX

    • 执行程序所有可能执行的路径
    • 达不到
  • 语句测试 P1

    • 至少执行程序中所有语句一次
    • 语句覆盖是最弱的逻辑覆盖准则
  • 分支测试 P2

    • 至少执行程序中所有分支一次
  • 条件组合测试

    • 设计足够的测试用例使所有条件取值组合至少执行一次
    • 一定符合分支测试
  • 循环

    • 选取关键路径测例

软件测试步骤

  • 单元测试

    • 白盒测试
    • 同时侧重代码审查等静态分析手段
    • 回归测试:修改旧代码后,重新进行测试以确认没有引入新的错误
  • 集成测试

    • 黑盒测试
    • 注重接口以及各模块的衔接问题
    • 冒烟测试:即入门测试,初步地测试,侧重看软件是否能全流程跑起来,系统是否值得测试
  • 有效性测试

    • 黑盒测试
    • 即确认测试,验收测试
    • 用户参与,用户为主
    • Alpha测试:产品发布前开发单位内部综合测试
    • Beta测试:产品正式投入市场前有关用户试用测试
  • 系统测试

    • 实际环境中检测整个系统是否协调
    • 功能测试:运行软件系统所有功能,验证有无错误
    • 恢复测试:使软件崩溃,检验软件是否可恢复,开销几何
    • 安全性测试:试图入侵系统
    • 强度测试:在非正常强度(数量/频率/容量等)下运行系统
    • 可用性测试:测试使用合理性
    • 部署测试:即配置测试,测试多平台环境运行情况

测试驱动开发

  • 敏捷开发中常用
  • 在开发功能前,先编写测例,再进行开发直至满足测例,循环往复直至满足所有需求
  • 测试驱动原则
    • 测试隔离:不同代码测试应相互隔离
    • 测试列表:任何阶段增加需求时先将相关功能点测例加入测试列表,再继续手头的开发
    • 先写断言:先用断言,再写相应功能代码
    • 可测试性:代码的设计和编写应具有较强的可测试性,e.g. 别轻易卡在某处影响其它部分的测试
    • 及时重构

面向对象测试

  • 单元测试:类测试
  • 集成测试
    • 基于线程
    • 基于使用:先测很少使用服务的类(独立类),逐步测试来增加闭包

Web测试

  • 众多测试框架

软件项目管理

  • 项目经理入门
  • 通过案例和书的经验学习
  • 四大核心知识领域:范围、时间、成本和质量
  • 四大辅助知识领域:人力资源管理、风险管理、沟通管理和采购管理
  • “人是项目成败与否最重要的因素”
  • “传统软件工程是制造业,互联网是服务业”

软件开发工具

  • 各种 IDE 等

参考

  • 北京大学公开课
    • 有些内容可能有点过时
    • 貌似是13年的公开课,老师一开头就在感慨中国的软件产业(外包?)不如印度,却不知道中国互联网产业的东风即将到来,而如今22年了,或许即将(已经?)结束,令人感慨
  • plantuml

软件工程笔记
http://example.com/2022/09/06/软件工程笔记/
作者
zty
发布于
2022年9月6日
许可协议