软件工程|高级软件工程课程总结

高级软件工程课程总结 写在前面
2022年春我学习了孟宁老师的《高级软件工程》课程,以下对这学期的知识内容和感想做一个回顾总结。
学号姓名:399thg
其他实验博客连接:

  • Linux配置go环境并使用vscode远程连接及创建版本库上传Github
  • Go实现LinkTable
参考资料:
《代码中的软件工程》 https://gitee.com/mengning997/se
收获和感想 首先,《高级软件工程》这门课程和其他课程不同的地方在于,其他课程绝大多数只会教纯理论的知识,而《高级软件工程》还会交一些实操性的内容和工具,就比如VSCode、Vim、Git等工具,这些在工程领域都是用的比较多的。在此之前我只知道git的几个极少数的命令,由于不知道原理使用起来经常报错,在上完课后,学会了git的结构和基本概念,用起来就得心应手,我想这也是呼应了课程标题中的那句话:“工欲善其事,必先利其器”。
其次,《高级软件工程》这门课程就像是个大熔炉,不仅会教大家软件设计的方法和过程,包括需求分析、设计、编程、测试和维护的全部内容,而且还涵盖了前端、后端、数据库等相关知识,前端比如说javascript、vue,后端和数据库就有Golang、Mongodb等,让我对整个软件体系结构有了一个整体的认识,特别是在这个前后端分离、微服务框架盛行的时代下,在每个人分工明确各施其职的工作环境中,对自己的方向要有深度的同时,对其他方向和技术有一个基本的了解同样不可或缺。
最后,我觉得《高级软件工程》让我收获最大的,是对软件工程的有了更深层次的理解。在此之前,也就是上学期我们工程实践团队在写项目的时候,没有系统性的软件设计方法,在做项目过程中遇到了各种各样的问题,现在回想起来,要是上学期就选高软课程就好了。软件工程,涵盖了软件生命周期中所有的工程方法、技术和工具,包括需求分析、设计、编程、测试和维护的全部内容,即完成一个软件产品所必备的思想、理论、方法、技术和工具。我在这方面做得还不够,这也是我需要在后面的学习和工作中需要不断进行总结反思改进的地方。
最后的最后,感谢孟宁老师一学期课程的教导,孟老师授课由浅入深,引人入胜,时刻抓住我们的听课兴趣,使我对一个软件工程有了整体性的认知,也祝孟宁老师工作顺利,万事顺意!
课程知识点总结 [1] VS Code
文件操作
Ctrl + O #打开文件夹/工作区
Ctrl + KF #关闭文件夹/工作区
Ctrl + N #新建文件
Ctrl + W #关闭文件
Ctrl + KW #关闭所有文件
Ctrl + KU #关闭所有已保存的文件
其他
Ctrl + / #单行注释
Ctrl + Shift + A #多行注释
Ctrl + Shift + E #文件资源管理
Ctrl + Shift + F #跨文件搜索
Ctrl + Shift + D #启动和调试
Ctrl + Shift + M #查看错误警告
Ctrl + Shift + X #管理扩展文件
Ctrl + ` #切换终端
[2] GIT

查看命令
git status #查看当前工作区(workspace/branch)
git log #查看当前head之前提交的记录,便于回溯
git reflog #查看当前head之后提交的记录,便于前进
git reset --hard commit-id #回退
仓库
git init #初始化一个本地版仓库
git add [files] #将文件添加进缓存区
git commit -m “mesage” #将文件添加进本地repo
远程命令
git clone #克隆一个仓库到本地目录下
git fetch #查看远程仓库是否更新,更新就爬过来
git push # 将本地仓库的信息推送到远程仓库
git merge # 合并两个或多个仓库
git pull #从其他存储分支抓取或合并到当前分支
工作场景 建议团队项目的每一个开发者都采用的工作流程大致如下:
? 1 克隆或同步最新的代码到本地存储库;
? 2 为自己的工作创建一个分支,该分支应该只负责单一功能模块或代码模块的版本控制;
? 3 在该分支上完成某单一功能模块或代码模块的开发工作;
? 4 最后,将该分支合并到主分支。
合并方法
1.快进式合并(默认) git merge
2.git merge --no-ff
区别:
git merge
A---B---C feature /master D---E---F

git merge --no-ff
A---B---C feature /\ D---E---F-----------G master

  • --no-ff 会让 Git 合并成一个新的提交对象,再改变head指向对象,而快进合只是把head指针置为feature
  • –no-ff 在后退得时候会退回到合并之前的版本,而快进合并只会推到合并分支的前一个版本
分支命令
git branch #查看分支
git checkout #切换分支
git checkout -b mybranch #创建并切换
git branch # 基于某个分支上开出新分支
Rebase rebase命令用来合并之前提交(commit)的记录,log 记录将来更容易回顾参考,用 git rebase 重新整理一下提交记录。
?git rebase -i [startpoint] [endpoint]
[3] 正则表达式
通配符
  • 通配符==.== 匹配任意一个字符
    例如hu.来匹配hug huh hut等
  • 通配符==+== 匹配出现一次或多次的字符
    hahhhhh可以使用hah+来匹配
  • 通配符==*== 匹配0次或者多次出现的字符
  • 通配符==?== 检查前一个元素是否存在 colou?r
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 或 “does” 。? 等价于 {0,1}。
. 匹配除换行符(\n、\r)之外的任何单个字符
  • {a,b}表示前一个字符至少出现a次,至多出现b次
集合
  • [xyz] 表示匹配xyz中任意一个字符
  • [^xyz] 表示匹配未包含的任意字符
  • [a-z] 匹配字符范围
  • [^a-z] 负字符范围
  • 快捷方式1:\w搜索字母数字
  • 快捷方式2:\d搜索数字
  • 快捷方式2:\D搜索非数字
贪婪匹配和懒惰匹配
  • 贪婪匹配:在所有的匹配项中选择最长的(默认)
  • 懒惰匹配:选择最短的
例如titanic
  • 贪婪匹配t[a-z]*i 则匹配titani
  • 懒惰匹配t[a-z]*?i 匹配ti
?紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的.
开头结尾
  • ^匹配已此为开头
  • $匹配以此为结尾
查找开头的 Ricky 则为^Ricky,查找结尾的 found 则为/found$
特殊字符
  • \s 空格
  • \n 换行
  • \r 回车
  • \f:换页
  • \t:水平跳格
捕获组复用模式 我们在搜索的某些模式在字符串中多次出现,手动重复这些正则表达式是浪费时间的。
用括号(and)可以定义capture groups 捕获组,用于查找重复的子串,即把会重复的模式的正则表达式放在括号内。
例如我们匹配字符串中连续出现三次的数字,每个数字由空格分隔
原本要写成:\d+\s\d+\s\d+
现在写成: (\d+)(\s)\1\2\1
字符替换 从第一行到最后一行,将word1替换成word2
:%s/word1/word2/g

想在当前文件中将所有的HTML标题标签中h改为大写H则正则表达式为:1
$s///g

练习 1.匹配如下规则
  • 数字只能在用户名的末尾,出现任意次
  • 用户名只有数字和大小写字母组成。
  • 用户名至少有2个字符
([a-zA-Z]){2,}\d*|\1*\d{2,}

[4] 模块化
编写高质量代码的基本方法
  • 通过控制结构简化代码(if else/while/switch)
  • 通过数据结构简化代码
  • 一定要有错误处理
  • 注意性能优先的代价
  • 拒绝修修补补要不断重构代码
模块化基本原理 模块化(Modularity)是在软件系统设计时保持系统内各部分相对独立,以便每一个部分可以被独 立地进行设计和开发。
基本原理是关注点的分离 (SoC, Separation of Concerns) 分解成易解决的小问题,降低思考负担,容易定位软件缺陷,减少出错的情形。
模块化的指标:耦合度和内聚度
耦合度 耦合度是指软件模块之间的依赖程度,可分类为紧密耦合、松散耦合和无耦合
一般在软件设计中我们追求松散耦合。
内聚度 内聚度是指一个软件模块内部各种元素之间互相依赖的紧密程度。
理想的内聚是功能内聚,也就是一个软件模块只做一件事,只完成一个主要功能点或者一个软件特性。
基本方法 1.KISS原则
  • 一行代码只做一件事
  • 一个块代码只做一件事
  • 一个函数只做一件事
  • 一个软件模块只做一件事
2.使用本地化外部接口来提高代码的适应能力
3.不要和陌生人说话原则
4.先写伪代码的代码结构更好一些
[5] 接口
定义 接口就是互相联系的双方共同遵守的一种协议规范,在我们软件系统内部一般的接口方式是通过定义一组API函数来约定软件模块之间的沟通方式。
在面向过程的编程中,接口一般定义了数据结构及操作这些数据结构的函数;而在面向对象的编程中,接口是对象对外开放(public)的一组属性和方法的集合。函数或方法具体包括名称、参数和返回值等。
接口规格五个基本要素
  • 接口的目的;
  • 接口使用前所需要满足的条件,一般称为前置条件或假定条件;
  • 使用接口的双方遵守的协议规范;
  • 接口使用之后的效果,一般称为后置条件;
  • 接口所隐含的质量属性。
微服务和RESTfulAPI 微服务使用模块化的思想,每个微服务单独部署,跑在自己的进程中,每个微服务为独立的业务功能开发,一般每个微服务应分解到最小可变产品,达到功能内聚的理想状态。
RESTfulAPI
?GET用来获取资源;
?POST用来新建资源(也可以用于更新资源);
?PUT用来更新资源;
?DELETE用来删除资源。
通用接口定义的基本方法 ?参数化上下文:使用参数传递信息,不依赖上下文环境
?移除前置条件
?简化后置条件
可重入函数基本要求 ? 所有数据都由函数的调用者提供;
? 使用局部变量,或者通过制作全局数据的局部变量拷贝来保护全局数据;
? 使用静态数据或全局变量时做周密的并行时序分析,通过临界区互斥避免临界区冲突;
? 绝不调用任何不可重入函数。
软件质量的三个角度
  • 产品的角度,也就是软件产品本身内在的质量特点;
  • 用户的角度,也就是软件产品从外部来看是不是对用户有帮助,是不是有良好的用户体验;
  • 商业的角度,也就是商业环境下软件产品的商业价值,比如投资回报或开发软件产品的其他驱 动因素。
[6] 需求分析
需求分析定义 需求就是对用户期望的软件行为的表述;
获取需求就是需求分析师通过关注用户的期望和需要,从而获得用户期望的软件行为,然后对其进行表述的工作;
需求分析是在获取需求的基础上进一步对软件涉及的对象或实体的状态、特征和行为进行准确描述或建模的工作。
需求的分类
  • 功能需求:根据所需的活动描述所需的行为
  • 质量需求或非功能需求:描述软件必须具备的一些质量特性
  • 设计约束(设计约束): 设计决策,例如选择平台或接口组件
  • 过程约束(过程约束): 对可用于构建系统的技术或资源的限制
高质量需求
  • 需求可测试
  • 解决冲突
  • 需求有特点(前后一致性、无二义性、可行性、可追溯、相关性)
需求分析的两种方法 1.原型化方法
原型化方法可以很好地整理出用户接口方式(UI,User Interface),比如界面布局和交互操作过程。
2.建模的方法
建模的方法可以快速给出有关事件发生顺序或活动同步约束的问题,能够在逻辑上形成模型来 整顿繁杂的需求细节。
[7] 用例
用例是经过逻辑整理抽象出来的一个业务过程。
什么是业务过程?在待开发软件所处的业务领域内完成特定业务任务的一系列活动就是业务过程。
用例的三个抽象层级
  • 抽象用例(Abstract use case)。只要用一个干什么、做什么或完成什么业务任务的动名词短 语,就可以非常精简地指明一个用例。
  • 高层用例(High level use case)。需要给用例的范围划定一个边界,也就是用例在什么时候 什么地方开始,以及在什么时候什么地方结束;
  • 扩展用例(Expanded use case)。需要将参与者和待开发软件系统之间从用例开始到用例结束的所有交互步骤都列举出来。
用例需要满足的四个条件
  • 它是不是一个业务过程?
  • 它是不是由某个参与者触发开始?
  • 它是不是显式地或隐式地终止于某个参与者?
  • 它是不是为某个参与者完成了有用的业务工作?
[8] 统一过程
核心要义 统一过程是用例驱动、以架构为中心、增量且迭代的过程。
【软件工程|高级软件工程课程总结】用例驱动就是我们前文中用例建模得到的用例作为驱动软件开发的目标;
以架构为中心的架构是后续软件设计的结果,就是保持软件架构相对稳定,减小软件架构层面的重构造成的混乱;
敏捷统一过程的四个关键步骤
  • 第一,确定需求;
  • 第二,通过用例的方式来满足这些需求;
  • 第三,分配这些用例到各增量阶段;
  • 第四,具体完成各增量阶段所计划的任务。
敏捷统一过程将增量阶段分为五个步骤:
  • 用例建模(Use case modeling
  • 业务领域建模(Domain modeling);
  • 对象交互建模(Object Interaction modeling),使用剧情描述来建模,最后转换为剧情描述表;
  • 形成设计类图(design class diagram);
  • 软件的编码实现和软件应用部署;
[9] 三种系统类别
  • S系统:有规范定义,可从规范派生————矩阵操纵矩阵运算
  • P系统:需求基于问题的近似解,但现实世界保持稳定————象棋程序
  • E系统:嵌入现实世界并随着世界的变化而变化(大多数软件都属于这个类型)————预测经济运行方式的软件(但经济尚未被完全理解)
软件工程|高级软件工程课程总结
文章图片

[10] 软件中的特殊机制
闭包 闭包一般用在将函数作为返回值时,该函数执行所需的上下文环境也作为返回的函数对象的一部分。
function makeFunc() { var name = "Mozilla"; function displayName() { alert(name); } return displayName; }var myFunc = makeFunc(); myFunc();

异步调用 Promise对象实际上是对回调函数机制的封装,也就是通过then方法定义的函数与resolve/reject函数绑定,简化了回调函数传入的接口实现,在逻辑上也更加通顺,看起来像是个同步接口。
var promise = new Promise(function(resolve, reject) { if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } }); promise.then(function(value) { // resolve(value) // success }, function(value) { // reject(error) // failure });

[11] 设计模式
设计模式的本质是面向对象设计原则的实际运用总结出的经验模型。
目的是包容变化,即通过使用设计模式和多态等特殊机制,将变化的部分和不变的部分进行适当隔离。
正确使用设计模式具有以下优点:
  • 可以提高程序员的思维能力、编程能力和设计能力。
  • 使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
  • 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。
设计模式由四个部分组成:
  • 该设计模式的名称;
  • 该设计模式的目的;
  • 该设计模式的解决方案;
  • 该设计模式的解决方案有哪些约束和限制条件。
根据作用对象分两类:
  • 类模式:用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时刻便确定下来了。比如模板方法模式等属于类模式。
  • 对象模式:用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时刻是可以 变化的,更具动态性。由于组合关系或聚合关系比继承关系耦合度低,因此多数设计模式都是对象模式。
设计模式七大原则
  • 单一职责原则 (Single Responsibility Principle)
  • 开放-关闭原则 (Open-Closed Principle)
  • 里氏替换原则 (Liskov Substitution Principle)
  • 依赖倒转原则 (Dependence Inversion Principle) 高层模块不应该依赖低层模块,两者都应该依赖其抽象;
  • 接口隔离原则 (Interface Segregation Principle)不考
  • 迪米特法则(Law Of Demeter)
  • 组合/聚合复用原则 (Composite/Aggregate Reuse Principle)
[12] MVC与MVVM
执行过程
  • 在MVC中,用户对于M的操作是通过C传递的,然后C将改变传给V,并且M将在发生变化时通知V,然后V通过C获取变化?
在MVVM中,用户直接与V交互,通过VM将变化传递给M,然后M改变之后通过VM将数据传递给V,从而实现解耦。
耦合:
  • MVC模式中M的数据要经过C解析后V才能使用,使得程序臃肿
  • 在MVVM中,VM层承担了数据解析的工作,这时C就只需要持有VM,而不需要直接持有M了。从而完成了数据的解耦。
[13] 软件架构复用
  • 克隆,完整地借鉴相似项目的设计方案,甚至代码,只需要完成一些细枝末节处的修改适配工作。
  • 重构,构建软件架构模型的基本方法,在参考已有的软件架构模型的基础上逐步形成系统软件架构的一种基本建模方法。
几种架构的分解方法
  • 面向功能的分解方法,
  • 面向特征的分解方法
  • 面向数据的分解方法
  • 面向并发的分解方法
  • 面向事件的分解方法.
  • 面向对象的分解方法.
架构的描述方法
  • 分解视图
  • 依赖视图
  • 泛化视图
  • 执行视图
  • 实现视图
  • 部署视图
  • 工作任务分配视图
[14] 没有银弹的意义
工程专家们所找到的各种方法都是舍本逐末,它们解决不了软件中的根本困难,即软件概念结构(conceptual structure)的复杂性,无法达成软件概念的完整性和一致性,自然无法从根本上解决软件危机带来的困境
[15] 软件的生命周期
分析、设计、实现、交付和维护五个阶段
  1. 分析阶段的任务是需求分析和定义,分析阶段一般会在深入理解业务的情况下,形成业务概念原 型
  2. 设计阶段分为软件架构设计和软件详细设计,前者一般和分析阶段联系紧密,一般合称为“分析 与设计”;后者一般和实现阶段联系紧密,一般合称为“设计与实现”。
  3. 实现阶段分为编码和测试,其中测试又涉及到单元测试、集成测试、系统测试等。
  4. 交付阶段主要是部署、交付测试和用户培训等。
  5. 维护阶段一般是软件生命周期中持续时间最长的一个阶段,而且在维护阶段很可能会形成单独 的项目,从而经历分析、设计、实现、交付几个阶段,最终又合并进维护阶段。
[16] 软件过程
软件过程又分为描述性的过程和说明性的过程。
  • 描述性的过程试图客观陈述在软件开发过程中实际发生什么。
  • 说明性的过程试图主观陈述在软件开发过程中应该会发生什么。
[17] V模型
V模型也是在瀑布模型基础上发展出来的,我们发现单元测试、集成测试和系统测试是为了在不同层面验证设计,而交付测试则是确认需求是否得到满足。
也就是瀑布模型中前后两端的过程活动具有内在的紧密联系,如果将模块化设计的思想拿到软件开发过程活动的组织中来,可以发现通过将瀑布模型前后两端的过程活动结合起来,可以提高过程活动的内聚度,从而改善软件开发效率。这就是V模型。
V模型是开始一个特定过程活动和评估该特定过程的过程活动成对出现,从而便于软件开发过程的组织和管理。
软件工程|高级软件工程课程总结
文章图片

[18] 团队
团队基本要素
  • 团队的规模
  • 团队的凝聚力
  • 团队协作的基本条件
评价团队的方法 CMM/CMMI用于评价软件生产能力并帮助其改善软件质量的方法,成为了评估软件能力与成熟度的 一套标准,它侧重于软件开发过程的管理及工程能力的提高与评估,是国际软件业的质量管理标准。
  • 一级,初始级,软件组织对项目的目标与要做的努力很清晰,项目的目标可以实现。但主要取决 于实施人员。
  • 二级,管理级,软件组织在项目实施上能够遵守既定的计划与流程,有资源准备,权责到人,对项目相关的实施人员进行了相应的培训,对整个流程进行监测与控制,并联合上级单位对项目 与流程进行审查。这级能保证项目的成功率。
  • 三级,已定义级,软件组织能够根据自身的特殊情况及自己的标准流程,将这套管理体系与流程 予以制度化。科学管理成为软件组织的文化与财富。
  • 四级,量化管理级,软件组织的项目管理实现了数字化,降低了项目实施在质量上的波动。
  • 五级,持续优化级,软件组织能够充分利用信息资料,对软件组织在项目实施的过程中可能出现 的问题予以预防。能够主动地改善流程,运用新技术,实现流程的优化。
[19] 敏捷方法的敏捷宣言
  • 个体和互动高于流程和工具
  • 工作的软件高于详尽的文档
  • 客户合作高于合同谈判
  • 响应变化高于遵循计划
  • 尽管右项有其价值,我们更重视左项的价值。

    推荐阅读