高级软件工程复习总结
工欲善其事必先利其器
VSCode
常用快捷键
- 打开文件夹( Ctrl/⌘+O)和关闭文件夹工作区( Ctrl/⌘+K F)
- 新建文件(Ctrl/⌘+N)、关闭文件(Ctrl/⌘+W)、编辑文件和保存文件(Ctrl/⌘+S)
- 文件内搜索(Ctrl/⌘+F)
- 关闭所有文件(Ctrl/⌘+K W)
- 关闭已保存的文件(Ctrl/⌘+K U)
- Ctrl+/用于单行代码注释和取消注释,Ctrl+Shift+A用于代码块注释和取消注释。
特性
- 专注于开发者“最常用”的功能
- 进程隔离的插件模型
- UI渲染与业务逻辑隔离,一致的用户体验
- 代码理解和调试——LSP和DAP两大协议
- 集大成的 Remote Development
Git
常用命令
- init 创建版本库
- clone 在本地克隆远端的版本库
- log 查看提交记录
- add 将文件添加到暂存区以便于commit
- commit 提交版本
- push 将本地仓库更新到远程仓库
- pull 获取远程仓库以更新本地仓库
- merge 合并两个以上的开发历史记录
- checkout 切换分支
- rebase 整理提交记录
Vim
三种模式
- 命令模式
- 输入模式
- 底线命令模式
常用命令
- hjkl 左下上右
- 0或Home 移动到本行第一个字符
- $或End 移动到本行最后一个字符
- gg 移动到第一行
- G 移动到最后一行 = 1G
- n+Enter 向下移动n行
- x del向后删除一个字符
- X backspace向前删除一个字符
- dd 删除一行
- ndd 删除光标之后n行
- yy 复制一行
- nyy 复制光标之后n行
- p 在当前行之后粘贴
- P 在当前行之前粘贴
- u 撤销
- ctrl+r 重做
- /word 在光标之后查找word字符串
- n1,n2s/word1/word2/g 在第n1行与n2行之间将word1替换为word2
- n1,$s/word1/word2/g 在第n1行之后将word1替换为word2
- n1,$s/word1/word2/gc 在第n1行之后将word1替换为word2并且替换前需要确认
- i 从光标处开始输入
- I 从所在行的第一个非空格字符开始输入
- a 从光标的下一个字符开始输入
- A 从所在行的最后一个字符开始输入
- o 从光标的下一行输入新的一行
- O 从光标的上一行输入新的一行
- r 取代模式,只取代光标处字符一次
- R 一直取代字符(覆写)
- :q 退出
- :q! 强制退出
- :w 将修改写入文件
- :wq 保存退出
- :wq! 强制保存退出
正则表达式
通配符
- . 任意字符
- + 一次或多次
- * 零次或多次
- ? 可能存在前一个元素或使用最短匹配
- [] 匹配组
- - 匹配的字符范围
- ^ 不相匹配的字符或字符串开头
- $ 字符串结尾
- \W [^A-Za-z0-9_]
- \w [A-Za-z0-9_]
- \D [^0-9]
- \d [0-9]
- () 捕获组
代码中的软件工程
代码风格的基本原则
简明、易读、无二义性
代码的基本结构
顺序执行、条件分支、循环结构、递归结构(部分语言支持)
编写高质量代码的基本方法
- 通过控制结构优化代码
- 通过数据结构简化代码
- 一定要有错误处理
模块化
模块化(Modularity)是在软件系统设计时保持系统内各部分相对独立,以便每一个部分可以被独立地进行设计和开发
关注点的分离在软件工程领域是最重要的原则
耦合度
耦合度是指软件模块之间的依赖程度
- 公共耦合:软件模块之间共享数据区或变量名的软件模块之间
- 数据耦合:软件模块之间仅通过显式的调用传递基本数据类型
- 标记耦合:软件模块之间仅通过显式的调用传递复杂的数据结构(结构化数据),耦合度高于数据耦合低于公共耦合
内聚度
内聚度是指一个软件模块内部各种元素之间互相依赖的紧密程度
KISS(Keep It Simple & Stupid)原则
- 一行代码只做一件事
- 一个块代码只做一件事
- 一个函数只做一件事
- 一个软件模块只做一件事
可重用软件设计
接口
接口就是互相联系的双方共同遵守的一种协议规范
5个基本要素
- 目的
- 前置条件或假定条件
- 协议规范
- 后置条件
- 质量属性
2种方式
- Call-in
- Callback
基本方法
- 参数化上下文
- 移除前置条件
- 简化后置条件
可重入函数与线程安全
线程(thread)是操作系统能够进行运算调度的最小单位。
- 可重入:可由多个任务并发使用不会产生数据错误,可随时中断并继续运行
- 不可重入:不能由超过一个任务共享,除非保证互斥
可重入函数基本要求
- 不为连续的调用持有静态数据;
- 不返回指向静态数据的指针;
- 所有数据都由函数的调用者提供;
- 使用局部变量,或者通过制作全局数据的局部变量拷贝来保护全局数据;
- 使用静态数据或全局变量时做周密的并行时序分析,通过临界区互斥避免临界区冲突;
- 绝不调用任何不可重入函数。
线程安全
多个线程同时运行且结果总与预期相同
线程安全问题都是由全局变量及静态变量引起的
Makefile
- $@ 目标文件
- $^ 所有依赖文件
- $< 第一个依赖文件
看待软件质量的角度
产品、用户、商业
从需求分析到软件设计
需求类型
- 功能性需求:根据需要的活动描述需要的行为
- 质量需求或非功能需求:描述软件必须具备的一些质量特征
- 设计约束:设计决策,如平台或接口组件的选择
- 过程约束:对可用于构建系统的技术或资源的限制
高质量需求
- 可测试性
- 处理冲突
- 特点:准确的,一致的、无二义性的、完整的、可行的、无与主要目标不相关的需求、可测试的、可追踪的
需求分析的两种基本方法
原型化方法、建模
用例
用例的基本要素
- 是一个业务过程
- 由某个参与者触发开始
- 显式或隐式地终止于某个参与者
- 为某个参与者完成了有用的业务工作
面向对象分析
- 对象和属性(类和对象的UML图)
- 继承关系(空心箭头指向父类)
- 聚合关系(菱形箭头指向整体类)
- 关联关系(实线)
业务领域建模
- 收集信息
- 头脑风暴
- 概念分类及关系
- 画出UML图
敏捷统一过程
敏捷统一过程进一步将软件过程中每一次迭代过程划分为计划阶段和增量阶段。
4个关键步骤
- 确定需求
- 通过用例满足需求
- 将用例分配到各增量阶段
- 完成各增量阶段的任务
增量阶段的5个步骤
- 用例建模
- 业务领域建模
- 对象交互建模
- 形成设计类图
- 软件的编码实现和软件应用部署
统一过程
统一过程的核心要义是用例驱动(以用例为开发目标)、以架构为中心(保持架构稳定,减少重构)、增量且迭代的过程
涉及UML图
用例图、序列图(顺序图)、类图
软件科学基础概论
软件的基本构成元素
- 对象:类的实例,属性和方法的集合
- 函数和变量/常量
- 指令和操作数:CPU加载和执行的基本单元
- 0和1:基本信息元素
软件的基本结构
顺序结构、分支结构、循环结构、函数调用框架、继承和对象组合
软件中的一些特殊机制
- 回调函数:函数作为参数
- 多态:代码相同不同上下文行为不同
- 闭包:返回的函数附带函数外部上下文
- 异步调用
- 匿名函数
设计模式
优点:
- 可以提高程序员的思维能力、编程能力和设计能力。
- 使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
- 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强
分类:
- 类模式、对象模式
- 创建型模式、结构型模式、行为型模式
常用的设计模式
- 单例模式:只有一个实例
- 原型模式:新实例均为某实例的拷贝
- 建造者模式:根据需求添加功能模块最终形成复杂对象
- 代理模式:使某对象对外提供指定/统一的接口
- 适配器模式:连接两个不兼容接口
- 装饰模式:不改变对象结构,使用对象组合方式扩展其功能
- 外观模式(门面模式):为系统各功能提供统一的对外接口集合
- 享元模式:提取相同的部分以复用,节省空间
- 策略模式:某些函数可替换
- 命令模式:将命令封装为对象并调用
- 模板方法模式:继承重载重定义某些函数
- 责任链模式:请求沿处理对象链传递直到被处理
- 中介者模式:使用中介者对象协调其他所有对象间的交互
- 观察者模式:某个观察者发生变化时通知其他观察者
设计原则
- 开闭原则:对扩展开放,对修改关闭
- 里氏(Liskov)替换原则:子类可扩展不可重写父类
- 依赖倒置原则:面向接口编程,调用使用抽象或接口而非具体类
- 单一职责原则:一个类只负责一个职责
- 迪米特法则:最少知道原则,对其他类了解越少越好
- 合成复用原则:复用时优先考虑组合、聚合,其次才是遵循里氏替换原则的继承
常见软件架构
- 三层架构
- MVC(模型-视图-控制器)架构:包容变化,三部分分离提高灵活性
- MVVM(C->ViewModel)架构:通过拦截绑定监听器自动更新视图
软件架构模型
2种不同层级的软件架构复用方法
克隆、重构
作用
- 有助于整体理解
- 为复用提供高层视图
- 为项目构建提供蓝图
- 有利于理清系统演化的内在逻辑,跟踪分析架构的依赖关系,有助于项目管理决策和项目风险管理
常见分解方法
- 面向功能
- 面向特征
- 面向数据
架构风格
- 管道-过滤器:流水线处理
- C/S客户-服务:客户主动,服务被动
- P2P: C/S的特殊形式,每个节点既是C又是S
- 发布-订阅:类似于观察者模式
- CRUD:Create创建、Read读取、Update更新、Delete删除(类似于数据库增删改查)
- 层次化:层次结构,如操作系统
视图
- 分解视图:模块划分
- 依赖视图:模块之间的依赖关系
- 泛化视图:模块之间的泛化关系(一般化或具体化,如继承)
- 执行视图:流程图、时序图(顺序图)等
- 实现视图:类似于目录树,用于查找具体实现
- 部署视图:用实际硬件建立联系
- 工作任务分配视图:任务划分
软件的质量属性
IEEE将软件质量定义为,一个系统、组件或过程符合指定要求的程度,或者满足客户或用户期望的程度。
- 可修改性:高内聚低耦合
- 性能:响应时间、吞吐量、负载
- 提高资源的利用率
- 更有效地管理资源分配
- 先到先得:按收到请求的顺序处理
- 显式优先级:按其分配优先级的顺序处理请求
- 最早截止时间优先:按收到请求的截止时间的顺序处理请求
- 减少对资源的需求
- 安全性:2个关键特征:系统免疫力、自我恢复能力
- 可靠性:指定条件下正确执行要求的功能,与缺陷有关
- 健壮性:不正确条件能正确执行,与容忍程度有关,“防人之心不可无,害人之心不可有”
- 易用性:用户操作的难易度,多与交互有关
- 商业目标:客户希望的质量属性
软件危机和软件过程
没有银弹
软件工程中不存在银弹——没有任何一项技术或方法可使软件工程的生产力在十年内提高十倍。软件工程之所以不存在银弹是因为,软件工程本身存在复杂性,一致性,不可预见性,不可视化性。
软件危机的根本问题
软件概念结构的复杂性,无法达成软件概念的完整性和一致性,自然无法从根本上解决软件危机带来的困境。
软件的生命周期
- 分析:需求分析和定义
- 设计:软件架构设计、软件详细设计
- 实现:编码和测试(单元、集成、系统测试)
- 交付:部署、交付、培训
- 维护
软件的故障率曲线
出现故障:垂直上升,修复故障:类1/x曲线回落,总体呈上升趋势
软件过程模型
软件过程
- 描述性(实际发生)
- 说明性(应该发生)
瀑布模型
几乎不会发生需求变化/变更,无任何迭代
原型化瀑布模型:瀑布模型增加原型化阶段,即先做基本雏形,将风险前移,增加可控性
原型分为用户接口原型和软件架构原型
V模型
将瀑布模型中的测试与开发结合,改善开发效率
分阶段的交付开发策略
- 增量开发:部分->整体,扩展功能
- 迭代开发:整体->整体,升级功能
分阶段开发优点
- 在开发完成之前即可进行交付和用户培训
- 可以让开发者及时处理意外情况
- 开发团队在不同版本关注不同功能,提高效率
- 提前抢占市场
生死相依原则:特定过程活动和评估该过程的过程活动成对出现
螺旋模型
基本策略:在每个迭代阶段构建原型以减小风险
每个循环重复计划,确定目标、替代方案和约束条件,评估替代方案和风险,开发和测试
个人软件过程PSP
- 计划阶段 (PSP0)
- 项目评估 (PSP1)
- 开发阶段 (PSP0)
- 分析 (PSP2.1)
- 设计规格 (PSP2.1)
- 编码标准规范 (PSP0.1)
- 设计 (PSP0)
- 设计评审 (PSP2)
- 编码 (PSP0)
- 代码评审 (PSP2)
- 测试 (PSP0)
- 统计记录各项工作用了多少时间 (PSP1.1)
- 项目测试报告 (PSP1)
- 程序规模度量 (PSP0.1)
- 开发完成后进行总结分析 (PSP0)
- 过程改进计划 (PSP0.1)
- PSP0、PSP0.1重点是个体度量过程,量化
- PSP1、PSP1.1重点是个体计划过程,评估
- PSP2、PSP2.1重点是个体质量管理,开发早期能够发现缺陷
- PSP3重点是个体循环过程,螺旋上升将模块增量和迭代为大型软件
团队软件过程TSP
团队的基本要素
- 团队规模
- 团队的凝聚力
- 团队协作的基本条件
建设高效团队
- 建设具有凝聚力的团队
- 设定有挑战性的目标
- 反馈
- 共同遵守的工作流程和框架
基本策略
- 计划先行,也就是做出承诺之前先计划
- 完成概念设计
- 选择开发策略
- 完成初步规模估算
- 完成初步时间估算
- 评估风险
- 建立策略文档
- 制定配置管理计划
CMM/CMMI 能力成熟度模型
用于评估软件开发商的能力
2种通用的评估方法
- 软件过程评估
- 软件能力评估
评估的三个阶段
- 准备
- 评估
- 报告
CMM/CMMI的5个等级
- 一级-初始级:目标清晰,但同类目标不保证也能完成,成功与否主要取决于实施人员
- 二级-管理级:在一级基础上,对项目有管理程序,避免偶然性
- 三级-已定义级:在二级基础上,制度化管理体系和流程,可用于同类项目和其他项目
- 四级-量化管理级:在三级基础上,实现数字化,提高精度和稳定性,降低质量波动
- 五级-持续优化级:在四级基础上,预防可能出现的问题,主动优化流程
敏捷方法
敏捷宣言
- 个体和互动 高于 流程和工具
- 工作的软件 高于 详尽的文档
- 客户合作 高于 合同谈判
- 响应变化 高于 遵循计划
核心思想:尽管右项有其价值,我们更重视左项的价值
Scrum敏捷开发
每一轮迭代称为一个冲刺,冲刺包括:
- 冲刺规划会议
- 每日站立会议
- 冲刺评审会议
- 冲刺回顾会议
基本流程
- 找出要做的事
- 决定当前冲刺要做的事
- 冲刺
- 得到增量版本,冲刺评审并发给用户
总结
- 全员规划,分块并行
- 文档为纲,当面交流
- 迭代开发,分块检查,持续交付
- 优先开发,讲究实效
DevOps
可以将DevOps看成是敏捷方法从技术开发领域扩展到业务运维领域
精益原则
在需要的时候、按需要的量、生产所需的产品,特点
- 零库存
- 快速反应
- 企业内部活动和外部市场(顾客)需求统一
- 强调人力资源的重要性