中科大-高级软件工程(孟宁)-学习总结
一、课程感想
这个学期选择了孟宁老师的高级软件工程课程,孟宁老师风趣独特的讲课方式和科学合理的传授知识的方法让我受益匪浅。如今,一学期的课程即将结束,来总结一下学习这门课程的一些感想和内容。
孟老师对于这门的讲授方式有非常独特的理解,在开学的第一节课就讲述了传统的高级软件工程是什么样的,以及他认为的高级软件工程该如何学习。
这是孟老师ppt中的内容:
并且,孟老师举了一个非常贴切的例子来向我们说明了为什么这门课程有非常多的动手练习和实验内容。这是一个陶艺课的故事,一群学习陶艺课程的学生分为两组,一组以制作陶艺的质量作为评分标准,二另一组以制作的数量作为评分标准。一个学期之后,真正好的陶艺作品在那一组?很多人都认为会出现在以质量作为评分标准那一组,但实际上其实出现在以数量作为标准的那一组,这个答案非常出乎我的意料。但是老师解释道,以质量为准的反而有可能会畏手畏脚不敢开始,而且优秀的质量往往是以巨大的数量作为基础的;而以量为准却可以鼓励学生开始制作,所谓千里之行始于足下,只有开始了并且不断地尝试才能不断地提升自己,哪怕刚开始不停的失败,但是在一次次失败中会逐渐停止恐惧、树立起自信,最终获得成功。
这个例子引起了我的思考,给我带来了一种新的思路。就这样,我们带着一丝新奇的心情开始了软件工程课程的学习。
课程一共由以下几个部分组成:
1、工欲善其事必先利其器——Typing、VSCode、Git、Vim、RegEx
2、代码中的软件工程——一个工程化C语言项目范例
3、需求分析与设计——从分析到设计的基本方法
4、软件系统设计——代码的结构、特性和描述方法
5、工程过程与项目管理——软件危机的前生后世
二、课程笔记
工具
先做再学
用不到软件工程中所学的知识,因为做的项目太过于简单
课本:
构建之法
软件工程-理论与实践
推荐书目:
梦断代码、人月神话
Typing
VS code
-
LSP(language server protocol)
-
Git
本地版本库
-
git init 在一个新建目录下初始化一个本地版本库
-
git status 查看当前工作区
-
git add [FILES] 把文件添加到暂存区
-
git commit -m “message” 提交
-
git reset 回退版本
-
git log 查看日志(head之前)
-
git reflog 查看日志
远程版本库
-
git clone
-
git fetch
-
git push
-
git merge
-
git pull
团队项目中的分叉合并
-
git clone、git pull
-
git chechout -b mybranch 创建并切换分支
git branch 查看分支情况
-
git merge --no-ff mybranch 合并分支
merge后要快速pull到远端
-
git rebase
-
团队流程、使用熟悉一下vim
git rebase
-
$git rebase -i HEAD^^^
-
git rebase --abort
-
git rebase --continue
fork + pull request
正则表达式
-
/:vim中开启正则表达式
-
.、*、?、|
-
{3,5}
-
[a-z]、[abc]、[^]
-
/d /D /w
-
greedy贪婪匹配(默认):最长的
-
lazy懒惰匹配:最短的。加‘*?’
-
模块化
耦合度:软件模块之间的依赖程度
内聚度:一个软件模块内部各元素互相依赖的紧密程度
使用本地化外部接口提高代码的适应能力:
-
内部代码(API)→外部代码 ==》 内部代码(API)→API→外部代码
设计→代码 ==》 设计→伪代码→代码
可重用软件设计
消费者重用
生产者重用
接口
-
接口的规格(要素)
-
接口的目的
-
使用前需要满足的条件,前置条件
-
双方遵守的协议规范
-
使用后的效果,后置条件
-
接口所隐含的质量属性
-
-
RESTful API
-
Callback
-
底层定义数据类型及其对应的一些方法(例如search),上层可以给数据类型添加一些属性。上层调用底层方法时,由于新增了属性,对新增属性的操作无法进行。于是,底层方法添加一个形参,在上层自定义对新属性的操作方法,并作为参数传入底层方法。
// Serach a LinkTableNode from LinkTable
// 用户在上层自定义方法,处理新增属性的操作。args传递数据,使紧密耦合变为松散耦合
int Condition(tLinkTableNode * pNode, void * args);
// 顶层接口中的方法
tLinkTableNode * SearchLinkTableNode(tLinkTable * pLinkTable, int Condition(tLinkTableNode * pNode, void *args), void *args);
-
-
接口与耦合之间的关系
-
公共耦合(紧密)
-
软件之间共享数据区或变量名,两软件之间的接口定义不是通过显式的调用方式,而是隐式的共享了数据区或变量名
-
-
数据耦合(松散)
-
软件模块间仅通过显式的调用传递基本数据类型
-
-
标记耦合(松散)
-
软件模块间仅通过显式的调用传递复杂的数据结构。数据结构成为调用双方软件模块隐含的规格约定
-
-
-
通用化接口
-
参数化上下文
-
移除前置条件
-
-
需求分析的两类基本方法
-
原型化方法
-
建模方法
用例建模、业务领域建模、业务数据建模
用例建模
-
抽象用例
-
高层用例
-
扩展用例
基本步骤
-
提取抽象用例
-
寻找业务领域的动名词,验证这些动名词是不是用例,是否满足条件
-
条件1:是不是一个业务过程
-
2:是不是由某个参与者出发开始
-
3:是不是显式或隐式地终止于某个参与者
-
4:是不是为某个参与者完成了有用的业务工作
-
-
-
定义范围,即高层用例
-
根据关系画出用例图
-
根据具体细节扩展用例
*取钱用例分析(写在感想中)
面向对象分析基本概念
-
对象、属性
-
继承关系:概括化/具体化
-
聚合关系:一个对象是另一个对象的一部分
-
关联关系:两个概念之间的关系
业务领域建模
-
收集业务领域信息
-
头脑风暴
-
识别业务领域相关的概念
-
名词和名词短语
-
“Y 的 X”(X of Y)表达方法,比如汽车的颜色
-
及物动词
-
形容词
-
数量词
-
所有关系的表达方法,如具有、拥有
-
构成关系的表达方法
-
包含关系的表达方法
-
”X 是一种/类 Y“表达方法
-
-
对象可以独立存在,属性不可以
-
-
给出分类
-
将分类结果用UML图画出
关联类
-
关系表
关系数据模型的MongoDB设计与实现
范式:在尽量减少冗余的情况下,追求数据的一致性
one-to-few
-
嵌入
one-to-many
-
间接/子引用
one-to-squillions
-
父级引用
反范式化
-
读写比高时适用,无法原子更新
-
如双向关联
业务概念原型
概念原型=用例+数据模型
软件设计
敏捷统一过程
-
瀑布模型
-
统一过程
-
统一过程的核心要义是用例驱动、以架构为中心、增量且迭代的过程
-
售前计划
开工后计划
增量阶段
-
用例建模
-
业务领域建模
-
对象交互建模
-
形成设计类图
-
软件的编码实现和部署
对象交互建模
深入到功能内部的具体实现
剧情描述、剧情描述表
-
在扩展用例中右侧一列中找出关键步骤
-
对于每一个关键步骤,完成剧情描述,描述一步一步的对象交互过程
-
将剧情描述进一步转换成剧情描述表
-
设计模式
描述了软件系统设计过程中常见问题的一些解决方案,通常是从大量的成功实践中总结出来的且被广泛公认的实践和知识。
-
软件框架:软件框架是由开发人员定制的应用系统的骨架,是整个或部分系统的可重用设计,由一组抽象构件实例间的交互方式组成。
-
框架和体系结构的关系:体系结构的呈现形式是一个设计规约,而框架是“半成品”的软件;体系结构的目的是指导软件系统的开发,而框架的目的是设计复用。
-
MVC框架的实现:前端有ANGULARJS、BACKBONE.JS,后端有Python的django框架。
-
框架和设计模式的关系:
-
框架给出的是整个应用的体系结构;而设计模式则给出了单一设计问题的解决方案,且可以在不同的应用程序或者框架中进行应用。
-
设计模式的目标是改善代码结构,提高程序的结构质量;框架强调的是设计的重用性和系统的可扩展性,以缩短开发周期,提高开发质量。
-
软件设计原则
设计原则是系统分解和模块设计的基本标准,应用这些原则可以是代码更加灵活、易于维护和扩展。
-
抽象
-
关注事物中与问题相关部分而忽略其他无关部分的一种思考方法
-
-
封装和信息隐藏
-
每个软件单元对其他所有单元都隐藏自己的设计决策,各个单元的特性通过其外部可见的接口来描述。
-
-
模块化
-
逻辑和物理上将整个系统分解成多个更小的部分,其实质是“分而治之”,即将一个复杂问题分解成若干简单问题,然后逐个解决。
-
系统分解的原则
-
目标:高内聚,低耦合。
-
内聚性:一个模块或子系统内部的依赖程度。
-
如果一个模块或子系统含有许多彼此相关的元素,并且它们执行类似任务,那么其内聚性比较高;如果一个模块或子系统含有许多彼此不相关的元素,其内聚性就比较低。
-
-
耦合性:两个模块或子系统之间依赖关系的强度。
-
如果两个模块或子系统是松散耦合的,二者相互独立,那么当其中一个发生变化时对另一个产生的影响就很小;如果两个模块或子系统是紧密耦合的,其中一个发生变化就可能对另一个产生较大影响。
-
-
层次化
-
分层(Layering):每一层可以访问下层,不能访问上层
-
封闭式结构:每一层只能访问与其相邻的下一层
-
开放式结构:每一层还可以访问下面更低的层次 层数不应超过7 +2层
-
-
划分(Partitioning):系统被分解成相互对等的若干模块单元,每个模块之间依赖较少,可以独立运行
-
模块单元增加了处理开销,过度分层或划分会增加复杂性。
-
-
复用(reuse):是利用某些已开发的、对建立新系统有用的软件元素来生成新的软件系统,其好处在于提高生产效率,提高软件质量。
-
源代码复用:对构件库中的源代码=构件进行复用
-
软件体系结构复用:对已有的软件体系结构进行复用
-
框架复用:对特定领域中存在的一个公共体系结构及其构件进行复用
-
设计模式:通过为对象协作提供思想和范例来强调方法的复用
-
软件体系结构风格
软件体系结构风格(Architectural Styles)是描述特定系统组织方式的惯用范例强调了软件系统中通用的组织结构。
主程序-子程序
主程序-子程序风格是结构化程序设计额一种典型风格,从功能的观点设计系统,通过逐步分解和细化,形成整个系统的体系结构。
-
构件:主程序、子程序
-
连接器:调用-返回机制
-
拓扑结构:层次化结构
面向对象风格
系统被看作是对象的集合,每个对象都有一个它自己的功能集合;数据及作用在数据上的操作被封装成抽象数据类型;只通过接口与外界交互,内部的设计决策则被封装起来。
-
构件:类和对象
-
连接器:对象之间通过调用和消息传递实现交互
管道-过滤器风格
把系统任务分成若干连续的处理步骤,这些步骤由通过系统的数据流连接,一个步骤的输出时下一个步骤的输入。
以数据为中心的风格
-
仓库体系结构(repository architecture) 是一种以数据为中心的体系结构,适合于数据由一个模块产生而由其他模块使用的情形。
客户机/服务器结构(client/server)
是一种分布式系统模型,作为服务器的子系统为其他客户机的子系统提供服务,作为客户机的子系统负责与用户的交互。
-
两层C/S结构
-
胖客户端模型:服务器只负责数据的管理
-
客户机实现应用逻辑和用户的交互
-
-
胖客户端与瘦客户端
-
胖客户端:客户端执行大部分的数据处理操作
-
瘦客户端:客户端具有很少或没有业务逻辑
-
-
-
三层C/S结构
-
表示层:包括所有与客户机交互的边界对象,如窗口、表单、网页等。
-
功能层(业务逻辑层):包括所有的控制和实体对象,实现应用程序的处理逻辑和规则。
-
数据层:实现对数据库的存储、查询和更新。
-
B/S结构 浏览器/服务器结构是三层C/S风格的一种实现方式。
-
集群结构
集群内各服务器上的内容保持一致(通过冗余提高可靠性与可用性) 集群内各服务器上的内容之和构成系统完整的功能/数据(通过分布式提高速度与并发性)
MVC结构
客户机-服务器结构
-
许多应用系统的用途都是从数据库中检索数据,并将其显示给用户。
-
在用户更改数据之后,系统在将更新内容存储到数据存储中。
-
因为关键的信息流发生在数据存储和用户界面之间,所以一般倾向于将这两部分捆绑在一起,以减少编码量并提高应用程序性能。
-
模型-视图-控制器(MVC)结构将应用程序的数据模型、业务逻辑和用户界面分别放在独立构件中,这样对用户界面的修改不会对数据模型/业务逻辑造成太大影响。
-
模型(model):封装应用程序状态、响应状态查询、应用程序功能、通知视图改变;
-
视图(view):解释模型、模型更新请求、发送用户输入给控制器、允许控制器选择视图;
-
控制器(controller):定义应用程序行为、用户动作映射成模型更新、选择响应的视图;
参考资料 代码中的软件工程 https://gitee.com/mengning997/se