优点:
简洁(专注于编辑器,代码理解,版本控制,远程开发,debug)
进程隔离的插件模型 把插件放到单独的进程里,无法干扰主进程代码的执行,保障稳定性。
UI 渲染与业务逻辑隔离 VSCode 统管所有用户界面交互,制定用户界面交互的标准,插件能做的就是响应请求,专注于业务逻辑处理。
代码理解的基础 LSP和DAP协议
- 用于代码理解和调试的第三方插件与VS Code主进程之间的桥梁就是两大协议
- 多语言支持的基础就是Language Server Protocol(LSP)
- 节制的设计 关注物理实体(比如文件、目录)和状态(光标位置)。不关心语言特性,编译
- 基于 JSONRPC的协议 易读,各大语言都支持
远程开发
Remote Development(VSCRD) 响应迅速,沿用本地设置,数据传输开销小(UI在本地,数据请求服务器)
(避免环境配置,本机性能太差)
常用命令
- 打开文件夹( Ctrl+O)
- 新建文件(Ctrl+N)
- 关闭文件(Ctrl+W)
- 编辑文件和保存文件(Ctrl+S)
- 文件内搜索(Ctrl+F)
- 关闭所有文件(Ctrl+K W)
- 关闭已保存的文件(Ctrl+K U)
- 单行代码注释和取消注释Ctrl+/ (//)
- 代码块注释和取消注释Alt+Shift+A()
- Ctrl+Shift+E 文件资源管理器
- Ctrl+Shift+G 源代码管理
- Ctrl+Shift+F 跨文件搜索
- Ctrl+Shift+H 跨文件替换
- Ctrl+Shift+D 启动和调试
- Ctrl +Shift+P调出VS Code命令行
- Ctrl+Shift+M查看错误和警告
- Ctrl+Shift+X 管理扩展插件
- Ctrl+~打开终端
基本设置和原理
VSCode自带git
sudo apt install git # 在Linux上安装Git
git init # 在一个新建的目录下创建版本库
git clone https://github.com/YOUR_NAME/REPO_NAME.git # 通过clone远端的版本库从而在本地创建一个版本库
原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xIxBrcIq-1657440974364)(C:UserslanAppDataRoamingTypora ypora-user-imagesimage-20220706225040495.png)]
git pull = git fetch + git merge
常用命令
- git init # 初始化一个本地版本库
- git status # 查看当前工作区(workspace)的状态
- git add [FILES] # 把文件添加到暂存区(Index)
- git commit -m "wrote a commit log infro” # 把暂存区里的文件提交到仓库
- git log # 查看当前HEAD之前的提交记录,便于回到过去
- git reset —hard HEAD^^/HEAD~100/commit-id/commit-id的头几个字符 # 回退(/分隔几种标识commit方式)
- git reflog # 可以查看当前HEAD之后的提交记录,便于回到未来
- git reset —hard commit-id/commit-id的头几个字符 # 回退
几个概念
过去和未来之间的分界点就是HEAD,即当前工作区所依赖的版本。
line diff 增量补丁,按行对比(line diff)将差异的部分制作成一个增量补丁。
commit是存储到仓库里的一个版本,是整个项目范围内的一个或多个文件的增量补丁合并起来,形成项目的增量补丁,是一次提交记录。每个提交(commit)都生成一个唯一的commit ID。
branch是按时间线依次排列的一组提交记录(commit),理论上可以通过当前branch上最初的提交(commit)依次打补丁直到HEAD得到当前工作区里的源代码。
tag标签就是某次提交(commit)的commit ID的别名。
默认merge为快进式合并,将分支的commit合并到主分支,–no-ff关闭
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QOMlxlZG-1657440974365)(C:UserslanAppDataRoamingTypora ypora-user-imagesimage-20220706230448846.png)]
合作流程
pull/clone下来后新建分支 commit后
切换到master后pull,然后git merge --no-ff mybranch(另一种方式:fork+push分支,然后在仓库中提pull request即可)
git rebase整理一下自己的提交记录,注意不要通过rebase对任何已经提交到远程仓库中的commit进行修改。
(公司合作一般禁用,会将提交记录打乱)
- git rebase -i [startpoint] [endpoint]
- -i 为弹出交互界面(在里面可以设置提交信息,忽略某次提交等)
- [startpoint] [endpoint]则指定了一个编辑区间,如果不指定[endpoint],则该区间的终点默认是当前分支的HEAD。一旦指定, 则表示 [endPoint]后面的commit全部不要了!
- 一般只指定[startpoint] ,可以使用HEAD^^、HEAD~100、commit ID或者commit ID的头几个字符来指定一个commit节点
- 重新整理HEAD之前的两个commit节点 git rebase -i HEAD^^
rebase另一种用法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oEAQlODi-1657440974365)(C:UserslanAppDataRoamingTypora ypora-user-imagesimage-20220706235006143.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q94v3dNn-1657440974366)(C:UserslanAppDataRoamingTypora ypora-user-imagesimage-20220707000214838.png)]
如果先feature rebase develop,再merge develop,这样就相当于直接在a上进行开发,不会有多余记录
git rebase的两种用法(最全)_小垚尧的博客-CSDN博客_git rebase
vim是一个程序开发工具,由文本编辑器vi发展而来。拥有代码补完、编译及错误跳转等功能。以字体颜色辨别语法的正确性。
三种模式
命令模式(Command mode)
输入模式(Insert mode)在命令模式下按下i就进入了输入模式,按ESC退出输入模式
c忽略大小写 C大小写敏感 示例:/wordc (vscode不支持此语法,默认忽略,Alt+C区分大小写)
通配符
- .将匹配任意一个字符。
- x+将匹配一个或多个字符,例如hahhhhh,hah+
- x*将匹配零个或多个字符
- x?将匹配零个或一个字符 如colou?r、favou?rite
- x{num1, num2} 将匹配 num1到 num2 个字符,可缺省
- [aiu] 匹配 a或 i或 u(指定字符集匹配) 连字符-表示区间 如 0-5,a-z
- [^12345] 否定字符集, 不匹配字符集内元素
字符集快捷方式
- w 匹配大小写字母加数字和下划线,等同于[A-Za-z0-9_]
- W 否定字符集 [^A-Za-z0-9_]
- d 匹配数字 [0-9]
- D 否定字符集 匹配非数字
- s 匹配空格(包括回车等) [ f v]
- S 匹配非空格
贪婪匹配(默认)和懒惰匹配(一般只有匹配多个字符才有这个概念)
- 符合正则表达式模式的字符串的最长可能部分,t[a-z]*i应用于"titanic"返回titani
- 最小可能部分 t[a-z]*?i 懒惰匹配 返回 ti(此时?指懒惰匹配)
查找开头和结尾 /^head /tail$
在方括号之外的正则表达式中 ^用于表示字符串的开头。$表示字符串的末尾。
捕获组复用模式capture groups
某些模式在字符串中多次出现, 可复用
用括号(xxx)定义捕获组, um来匹配前面通过括号定义的第num个捕获组。
示例:字符串中连续出现三次的数字,每个数字由空格分隔,即(d+)s1s1。
搜索替换中使用 $访问替换字符串中的捕获组
示例:HTML标题标签中h改为H为 :1,$s/<h(d)>/<H$1>/g
代码风格
- 基本要求: 简明、易读、无二义性
- 遵守常规语言规范,合理使用空格、空行、缩进、注释等。
- 逻辑清晰。没有代码冗余、重复,清晰的命名规则。选用合适的设计模式、软件架构风格。
- 优雅
注释风格
- 最精简的是无注释,理想的状态是即便没有注释,也能通过函数、变量等的命名直接理解代码。
- 糟糕的状态是代码本身很难理解,而作者又“惜字如金”。
- 还有一种就是将函数功能、各参数的含义和输入/输出用途等一一列举,这往往是模块的对外接口。
具体风格
- 缩进:4个空格
- 行宽:< 100个字符
- 代码行内要适当多留空格
- 在一个函数体内,逻辑上密切相关的语句之间不加空行,逻辑上不相关的代码块之间要适当留有空行以示区隔
- 复杂的表达式中要用括号来清楚的表示逻辑优先级
- 所有 ‘{’ 和 ‘}’ 应独占一行且成对对齐
- 不要把多条语句和多个变量的定义放在同一行
- 变量命名和驼峰式
通过控制结构简化代码(if else/while/switch)
通过数据结构简化代码
一定要有错误处理 (Debug版本都要验证所有参数;Release版本验证外部参数)
注意性能优先的代价 (软件工程师的人力成本—目前硬件成本越来越低—理解成本,扩展成本)
拒绝修修补补要不断重构代码
模块化(Modularity)是在软件系统设计时保持系统内各部分相对独立,以便每一个部分可以被独立地进行设计和开发。这个做法背后的基本原理是关注点的分离 (SoC, Separation of Concerns),分解成易解决的小问题,降低思考负担。
每个模块只有一个功能,易于开发,且bug会集中在少数几个模块内,容易定位软件缺陷,更加容易维护。 模块化程度成是软件设计的一个重要指标,使用耦合度 (Coupling)和内聚度(Cohesion)来衡量软件模块化的程度。
耦合度
耦合度是指软件模块之间的依赖程度,一般可以分为紧密耦合(Tightly Coupled)、松散耦合(Loosely Coupled)和无耦合(Uncoupled)。一般在软件设计中追求松散耦合。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RNclGyrm-1657440974366)(C:UserslanAppDataRoamingTypora ypora-user-imagesimage-20220708163224759.png)]
内聚度(Cohesion)
内聚度是指软件模块内部各种元素之间的依赖程度
理想的内聚是功能内聚,即一个软件模块只做一件事,只完成一个软件特性(Feather)
-
KISS(keep it simple&stupid)原则
- 一行代码只做一件事
- 一个块代码只做一件事
- 一个函数只做一件事
- 一个软件模块只做一件事
消费者重用和生产者重用
- 消费者重用:重用已有的一些软件模块代码(取决于功能,工作量,文档和测试完善程度)
- 生产者重用:如何生产可重用代码(通用接口,命名清晰,外部交互单独存放易于修改,其它同上)
接口
基本概念
接口就是互相联系的双方共同遵守的一种协议规范,即定 义一组API函数来约定软件模块之间的沟通方式。
- 在面向过程的编程中,接口一般定义了数据结构及操作这些数据结构的函数;
- 在面向对象的编程 中,接口是对象对外开放(public)的一组属性和方法的集合。函数或方法具体包括名称、参数和 返回值等
- 隐藏软件模块内部的实现细节
接口规格的基本要素
- 接口的目的
- 接口的前置条件
- 接口的协议规范(如http协议,png图片格式,json数据格式定义etc…)
- 接口的后置条件 (达成的效果)
- 接口的质量属性(如响应时间)
示例
微服务
- 由一系列独立的微服务共同组成软件系统的一种架构模式
- 每个微服务单独部署,跑在自己的进程中
- 每个微服务为独立的业务功能开发,一般每个微服务应分解到最小可变产品(MVP),达到功能内聚的理想状态。微服务一般通过RESTful API接口方式进行封装;
- 系统中的各微服务是分布式管理的,强调隔离性,互相之间无耦合或者极为松散的耦合,系统通过前端应用或API网关来聚合各微服务完成整体系统的业务功能。
- 传统单体集中式架构是适应单体服务器环境的软件架构模式;微服务架构则是为了适应大规模集群及基于虚拟化技术和分布式计算的云计算环境的架构模式。
RESTful API
REpresentational State Transfer 即表现层状态转化
- GET用来获取资源;
- POST用来新建资源(也可以用于更新资源);
- PUT用来更新资源;
- DELETE用来删除资源。
使用回调函数提高接口通用性
作为参数的函数就是callback函数,作用:
- 调用函数在处理相似事件的时候可以灵活的使用不同的方法。
- 异步通知
接口划分耦合度
无耦合、数据耦合、标记耦合、控制耦合、公共耦合和内容耦合
公共耦合
软件模块之间共享数据区或变量名(而非调用)
数据耦合
软件模块之间仅通过显式的调用传递基本数据类型
标记耦合
软件模块之间通过显式的调用传递复杂的数据结构(结构化数据)(数据结构成为调用双方软件模块隐含的规格约定)(耦合度要高于数据耦合。低于公共耦合)
通用接口定义的基本方法
- 参数化上下文(使用参数传递信息,不依赖上下文环境,不使用闭包函数)
- 移除前置条件(使用args数组传递参数,不限定参数个数,传入数组长度len)
- 简化后置条件(移除len,动态获取args长度) (len影响结果)
线程安全
指令乱序问题
- 多线程的函数可重入性和线程安全问题
- 编译器编译优化造成的指令乱序
- CPU乱序执行指令
基本概念
- 线程
- 线程堆栈(共享进程资源)
- 可重入函数(多于一个任务并发使用)要么使用局部变量,要么在使用全局变量时加锁。
- 不为连续的调用持有静态数据
- 不返回指向静态数据的指针;
- 所有数据都由函数的调用者提供;
- 使用局部变量,或者通过制作全局数据的局部变量拷贝来保护全局数据;
- 使用静态数据或全局变量时做周密的并行时序分析,通过临界区互斥避免临界区冲突;
- 绝不调用任何不可重入函数。
可重入函数与线程安全
- 可重入的函数不一定是线程安全的,可重入的函数在多个线程中并发使用时是线程安全的,不同的可重入函数(共享全局变量及静态变量)在多个线程中并发使用时会有线程安全问题;
- 不可重入的函数一定不是线程安全的。
cpu乱序执行指令
单核CPU只要将结果顺序地提交到ISA寄存器,就可以保证顺序一致性(Sequential consistency)
多核CPU核和 Cache以及内存之间,存在着Store Buffer为保证多核之间的修改可见性,需要加上内存屏障
ARM64是弱内存序模型,因为精简指令集把访存指令和运算指令分开了,为了性能允许几乎所有的指令乱序,但前提是不影响程序的正确性。因此ARM64架构的指令乱序问题需要引入不同类型的barrier来保证程序的正确性。
barrier()就是常说的编译器屏障(compiler barriers),它的主要用途就是告诉编译器不要优化重排指令顺序。(告诉编译器内存中的值已经改变,之前对内存的缓存(缓存到寄存器)都需要抛弃)
CPU仅能看到机器指令或汇编指令序列中的数据依赖、控制依赖和地址依赖等依赖关系,并不能理解高级语言中定义的逻辑关系,因此CPU指令乱序执行和编译优化指令乱序都可能会破坏高级语言中定义的逻辑关系
编译器指令乱序
编译器进行指令重排优化只能保证是单线程安全。对函数的可重入问题是没有感知的。
makefile
用于自动生成目标文件
.c.o 表示表示所有的 .o文件都是依赖于相应的.c文件的。
Makefile有三个非常有用的变量。分别是$@、$^和 $<, $@ 表示目标文件;$^ 表示所有的依赖文件;$< 表示第一个依赖文件
.c.o和 $<结合,表示要生成一个.o目标文件就自动使用对应的.c文件来编译生成
- 产品的角度,软件产品本身内在的质量特点;
- 用户的角度,软件产品是不是对用户有帮助,是不是有良好的用户体验;
- 商业的角度,软件产品的商业价值,比如投资回报或开发软件产品的其他驱动因素。
- 重构
- 模块化 Modularity
- 接口 Interfaces
- 隐藏实现 Information hiding
- 渐进发展 Incremental development
- 抽象Abstraction
- 通用Generality
需求分析就是需求分析师对用户期望的软件行为进行表述,并进一步用对象或实体的状态、属性和行为来定义需求(建模)
绘图工具draw.io(有VSCode插件 文件后缀 .drawio.svg或.drawio或.dio)
- 功能需求:根据所需的活动描述所需的行为
- 质量需求或非功能需求:描述软件必须具备的一些质量特性
- 设计约束: 设计决策,例如选择平台或接口组件
- 过程约束: 对可用于构建系统的技术或资源的限制
客户:为要开发的软件付费
客户:软件开发后购买
用户:使用系统
领域专家:熟悉软件
市场研究人员:调查以确定未来趋势和潜在客户
律师或审计师:熟悉政府、安全或法律要求
软件工程师或其他技术专家
- 有客观标准,用于判断是否满足需求
- 指定具体数量描述
- 使用实体名称而非代词
- 需求文档中每个名词都有定义
- 解决冲突
- 按需求重要程度分类:必要的,可取的,可选的
- 需求特点
- Correct 正确
- Consistent 一致
- Unambigious无二义
- Complete 完整
- Feasible 可行
- Relevant相关
- Testable 可量化
- Traceable 可追溯
需求分析的两类基本方法
- 原型化方法(Prototyping)整理出用户接口方式(UI,User Interface),比如界面布局和交互操作过程。
- 建模的方法(Modeling)给出有关事件发生顺序或活动同步约束的问题,能够在逻辑上形成模型来整顿繁杂的需求细节。
用例
- 用例的四个必要条件
- 是一个业务过程
- 由参与者触发(参与者可以是用户,也可以是一个其它模块)
- 为特定的参与者完成一个特定的业务任务
- 终止于某个特定参与者(得到业务任务完成的结果)
- 抽象用例(Abstract use case)完成一个业务任务如打电话
- 高层用例(High level use case)给用例的范围划定一个边界,始于准备拨号,终于铃声响起
- 扩展用例(Expanded use case)。参与者和软件在用例过程中的全部交互过程。如 tcp三次握手,client和server按何顺序分别做了什么,分两列列出。
- 用例建模的步骤
- 抽象用例
- 高层用例
- 对用例按照子系统或不同的方面进行分类,描述用例与用例、用例与参与者之间的上下文关系,画出用例图
- 扩展用例。
- 用例图
- 关联关系用直线表示 1表示1 *表示多
- 单向关联关系用直线加箭头表示。比如在用例图中参与者和用例就是一种单向关联关系,参与者总是“知道”用例,而用例“不知道”参与者,所以箭头可以从参与者指向用例。
- 包含关系是用带箭头的虚线加<>来表示。
- 扩展关系是用带箭头的虚线加<>来表示的。
面向对象分析涉及的基本概念
继承关系(Inheritance Relationship)
一般关系,比如教师与课程
业务领域建模(Domain Modeling)
- 收集应用业务领域的信息。聚焦在功能需求层面
- 列出重要的应用业务领域概念,给出这些概念的属性,以及这些概念之间的关系
- 给这些应用业务领域概念分类。列出类,属性和值、以及继承关系、聚合关系和关联关系
- 画UML 类图
通用的、基于文档的、分布式的数据库,用类似JSON格式的文档来存储数据。
一对多关系建模的三种基础方案
- One-to-Few
- 内嵌 子数据结构(人的直系亲属)
- One-to-Many
- 子引用 存储对应的 id (数组)(商品的数百个零件)
- One-to-Squillions
- 父引用 存储主机id,主机存储大量数据(日志文件)
- 如果 one 端只有少量信息,可以直接冗余到多端,合并两个对象
双向关联(反范式化)
- 一对多的多也要保存one端的id
- 易于反向统计,但修改时要改多个对象,可能无法保证操作的原子性
- 反范式化在节省读的代价的同时会带来更新的代价(取决于读和更新的频率)
总结
- 优先考虑内嵌
- 数组不应该无限制增长,过大则考虑子引用和父引用
- 不要害怕应用层级别的join:如果索引建的正确并且通过投影条件限制返回的结果,那么应用层级别的join并不会比关系数据库中join开销大多少。
- 反范式设计时请先确认读写比
瀑布模型
瀑布模型是最基本的过程模型,它把整个软件过程按顺序划分成了需求、设计、编码、测试和部署五个阶段。瀑布模型的根本特点是按顺序划分阶段。
统一过程(Unified Process)
统一过程(UP,Unified Process)的核心要义是用例驱动(Use case driven)、以架构为中心(Architecture centric)、增量且迭代(Incremental and Iterative)的过程
敏捷统一过程(Agile Unified Process)进一步将软件过程中每一次迭代过程划分为计划阶段和增量阶段。
敏捷统一过程的计划阶段
- 明确业务上的实际需求
- 充分调研获取需求并明确定义需求规格;
- 进行项目的可行性研究;
- 如果项目可行,用例建模并给出用例图;
- 明确需求和用例之间的可跟踪矩阵;
- 项目的概念模型草案;
- 日程安排、需要的资源以及大致的预算范围。
敏捷统一过程的四个关键步骤
- 确定需求;
- 通过用例的方式来满足需求;
- 分配用例到各增量阶段;
- 具体完成各增量阶段所计划的任务。
敏捷统一过程的增量阶段
- 用例建模(Use case modeling)
- 业务领域建模(Domain modeling)
- 对象交互建模(Object Interaction modeling)
- 形成设计类图(design class diagram)
- 软件的编码实现和软件应用部署
对象交互建模(Object Interaction Modeling)
- 找出关键步骤进行剧情描述(scenario)
- 将剧情描述(scenario)转换成剧情描述表(scenario table)
- 将剧情描述表转换成序列图的基本方法
- 从分析序列图到设计序列图
- 一个完整用例的对象交互建模
设计类图
- DCD 可能包含设计类,如控制器、命令、GUI 类。
- 依次填充类,方法,属性,关系
形成软件设计方案的基本方法
- 分析(analysis)和综合(synthesis)。
- 分析是分解大问题变成易于理解的小问题。比如用例建模是将错综复杂的需求分解成一个一个的用例。
- 综合是将一个个小问题的解决方案组合起来构建软件的整体解决方案。
软件的基本构成元素
对象
是类的实例,是属性和方法的集合
函数和变量/常量
常量和函数等放在代码段 初始化的全局变量,静态变量放在数据段 未初始化放在bss段 动态内存分配放在堆 局部变量 常量放在栈 命令行参数和环境变量存储在与栈底紧挨着的位置
指令和操作数
指令码+操作数(立即数或寄存器操作数或内存操作数)
软件的基本结构
顺序结构
分支结构
利用标志寄存器上标志位的指令(判断是否跳转)和跳转指令组合实现
循环结构
函数调用框架 (函数调用时堆栈的处理过程)
继承和对象组合 (继承会破坏封装,使用组合更好)
软件中的一些特殊机制
回调函数
函数(地址)作为参数
多态
允许将不同的子类类型的对象动态赋值给父类类型的变量,通过父类的变量调用方法在执行时实际执行的可能是不同的子类对象方法,因而表现出不同的执行效果。
闭包
将函数作为返回值时,该函数执行所需的上下文环境也作为返回的函数对象的一部分。允许从内部函数访问外部函数作用域。
异步调用
匿名函数 如lamda函数
软件的三种系统类型
S系统:有规范定义,可从规范派生
矩阵操纵矩阵运算
P系统:需求基于问题的近似解,但现实世界保持稳定
象棋程序
E系统:嵌入现实世界并随着世界的变化而变化(大多数软件都属于这个类型)
预测经济运行方式的软件(但经济尚未被完全理解)
软件具有复杂性和易变性,从而难以达成概念的完整性与一致性。(需求的达成永远赶不上需求的变
化)
设计模式的本质是面向对象设计原则的实际运用总结出的经验模型。彰显对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解
设计模式优点:
- 提高思维能力
- 使程序设计更加标准化
- 代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。
设计模式组成:
- 名称
- 目的,解决什么问题
- 解决方案
- 约束和限制条件。
设计模式分类
- 类模式:用于处理类与子类之间的关系,继承实现,是静态的,编译时确定。如模板方法模式
- 对象模式:用于处理对象之间的关系,组合或聚合实现,运行时确定,耦合度低(应用于多数设计模式)
使用完成的任务类型来划分
- 创建型模式:怎样创建对象,“将对象的创建与使用分离”。如单例模式、原型模式、建造者模式等。
- 结构型模式:如何将类或对象按某种布局组成更大的结构,如代理模式、适配器模式、桥接模式、装饰模式、外观模式、享元模式、组合模式。结构型模式分为类结构型模式和对象结构型模式。
- 行为型模式:用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成任务,它涉及算法与对象间职责的分配。如模板方法模式、策略模式、命令模式、职责链模式、观察者模式等。同分为类行为模式和对象行为模式
单例(Singleton)模式
原型(Prototype)模式
建造者(Builder)模式
代理(Proxy)模式
适配器(Adapter)模式:
装饰(Decorator)模式
外观(Facade)模式
享元(Flyweight)模式
策略(Strategy)模式
命令(Command)模式
模板方法(TemplateMethod)
职责链(Chain of Responsibility)
中介者(Mediator)
观察者模式observer
开闭原则(Open Closed Principle,OCP)
软件应当对扩展开放,对修改关闭Liskov替换原则(Liskov Substitution Principle,LSP)
子类可以扩展父类的功能,但最好不要改变父类原有的功能(重载)。依赖倒置原则(Dependence Inversion Principle,DIP)
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。即要面向接口(抽象)编程,不要面向实现(细节)编程。(降低耦合,细节变化,抽象不变则不必修改)单一职责原则(Single Responsibility Principle,SRP)
字面意思,可以提高类的内聚度,符合模块化设计的高内聚低耦合的设计原则。迪米特法则(Law of Demeter,LoD)
只与直接朋友交谈,如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。
合成复用原则(Composite Reuse Principle,CRP)
又叫组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP)。在软件复用时,要尽量先使用组合或者聚合关系来实现(维持封装,耦合度低,灵活性高),其次才考虑使用继承关系来实现。如果要使用继承关系,则必须严格遵循Liskov替换原则。
三层架构
层次化架构是利用面向接口编程的原则将层次化的结构型设计模式作为软件的主体,三层架构是层次化架构中比较典型的代表,界面层—>业务逻辑层—>数据访问层
MVC架构
MVC即为Model-View-Controller(模型-视图-控制器)
Model(模型)存取数据的对象及其数据模型。
View(视图)可视化的界面接口。
Controller(控制器)控制数据流向模型对象,并在数据变化时更新视图
与三层架构对比:
- 设计模式—软件架构
- Model — 业务逻辑+数据访问
优点
多个视图共享一个模型,大大提高代码的可重用性
控制器可以用来连接不同的模型和视图去完成用户的需求
面向数据流的软件体系结构,最典型的应用是编译系统。一个普通的编译系统包括词法分析器、语法分析器、语义分析与中间代码生成器、目标代码生成器等一系列对源代码进行处理的过程。对源代码处理的过滤器通过管道连接起来。
客户-服务
Client/Server(C/S)和Browser/Server(B/S)
通过请求和应答的方式访问或者调用服务代码。包括函数调用和返回,TCP 的send和recv,HTTP的GET请求和响应。P2P
P2P(peer-to-peer)架构是客户-服务模式的一种特殊情形,P2P架构中每一个构件既是客户端又是服务端。
发布-订阅
见观察者模式
CRUD
中心化管理系统关键数据的软件架构风格,四种持久化操作。
层次化
每一层为它的上一层提供服务,同时又作为下一层的客户,如osi
软件架构的描述方法
- 分解视图 Decomposition View 分成哪些部分
- 依赖视图 Dependencies View 软件模块之间的依赖关系
- 泛化视图 Generalization View 软件模块之间的一般化或具体化的关系(组合继承)
- 执行视图 Execution View 系统运行时的时序结构特点,比如流程图、时序图等
- 实现视图 Implementation View 软件架构与源文件之间的映射关系(给源文件合理命名)
- 部署视图 Deployment View 执行实体和计算机资源建立映射关系
- 工作任务分配视图 Work-assignment View 系统分解成可独立完成的工作任务,以便分配给各项目团队和成员
软件质量标准
符合标准规范,满足用户期望
- 易于修改维护(Modifiability) 高内聚低耦合
- 良好的性能表现(Performance) 系统的速度和容量
- 安全性(Security)防御攻击和从攻击恢复的能力
- 可靠性(Reliability)正确执行功能
- 健壮性(Robustness)基于可靠性,能适应异常环境
- 易用性(Usability)
- 商业目标(Business goals)
“在10年内无法找到解决软件危机的杀手锏(银弹)。 软件中的根本困难,即软件概念结构(conceptual structure)的复杂性,无法达成软件概念的完整性 和一致性,自然无法从根本上解决软件危机带来的困境。
基于组件的软件工程方法,将软件组件内的复杂结构包装起来(模块化设计),使得软件组件简单易用,组合成大型软件。产生基于组件的软件供应链。
- 分析阶段 需求分析和定义,形成业务概念原型
- 设计阶段 软件架构设计和软件详细设计,又称“分析与设计”和“设计与实现”。
- 实现阶段 编码和测试,测试又涉及到单元测试、集成测试、系统测试等。
- 交付阶段 部署、交付测试和用户培训等。
- 维护阶段 软件生命周期中最长的阶段
描述性的过程试图客观陈述在软件开发过程中实际发生什么。
说明性的过程试图主观陈述在软件开发过程中应该会发生什么。
瀑布模型
瀑布模型是一个过程活动的顺序结构,没有任何迭代(假定需求不会发生任何变化)
需求分析—>概要设计—>详细设计—>编码实现—>单元测试+集成测试—>系统测试—>验收测试—>维护
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D2F3hW4r-1657440974367)(C:UserslanAppDataRoamingTypora ypora-user-imagesimage-20220710150501397.png)]
原型化的瀑布模型
原型就是根据需要完成的软件的一部分如用户接口原型和软件架构原型(将风险前移,判断是否符合需求)
V模型
V模型也是在瀑布模型基础上发展出来的,单元测试、集成测试和系统测试是为了在不同层面验证设 计,而交付测试则是确认需求是否得到满足。 通过将瀑布模型前后两端的过程活动结合起来,提高过程活动的内聚度,改善软件开发效率。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tewBLBBA-1657440974367)(C:UserslanAppDataRoamingTypora ypora-user-imagesimage-20220710150844593.png)]
生死相依原则: 特定过程活动和评估该特定过程的过程活动成对出现
分阶段的增量和迭代开发,每次交付系统的一小部分,从而缩短开发迭代的周期。
- 增量开发就是从一个功能子系统开始交付,每次交付会增加一些功能,这样逐步扩展功能最终完成整个系统功能的开发。
- 迭代开发是首先完成一个完整的系统或者完整系统的框架,然后每次交付会升级其中的某个功能子系统,这样反复迭代逐步细化最终完成系统开发。
螺旋模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wlwu02QJ-1657440974367)(C:UserslanAppDataRoamingTypora ypora-user-imagesimage-20220710152034779.png)]
团队的基本要素
- 团队规模
- 团队的凝聚力
- 团队协作的基本条件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ai5mYVX-1657440974376)(C:UserslanAppDataRoamingTypora ypora-user-imagesimage-20220710152346087.png)]
团队项目的基本策略
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4IkShlnF-1657440974377)(C:UserslanAppDataRoamingTypora ypora-user-imagesimage-20220710152423655.png)]
CMM/CMMI用于评价软件生产能力并帮助其改善软件质量,侧重于软件开发过程的管理及工程能力的提高与评估。
- 一级,初始级,目标清晰,可实现。无法保证同类项目成功率。
- 二级,管理级,能遵守既定的计划与流程,有资源准备,权责到人,对整个流程进行监测与控制,并联合上级单位进行审查。保证同类项目的成功率。
- 三级,已定义级,将上述标准流程予以制度化。保证各类项目成功率。
- 四级,量化管理级,项目管理实现数字化,降低质量波动。
- 五级,持续优化级,充分利用信息资料,对可能出现的问题予以预防。主动改善流程。
CMM/CMMI主要应用在两大方面:
- 能力评估 如软件过程评估和软件能力评价
- 过程改进 上述级别反映了过程改进活动的轻重缓急和先后顺序
- 个体和互动 高于 流程和工具
- 工作的软件 高于 详尽的文档
- 客户合作 高于 合同谈判
- 响应变化 高于 遵循计划
- 尽管右项有其价值,我们更重视左项的价值。
- 项目经理(Scrum Master),负责项目的开发过程。
- 产品经理(Product Owner),比如定义产品功能和特性。
- 团队(Team)
在Scrum中每一轮迭代称为一个冲刺(Sprint)得到软件的一个增量版本,每个冲刺包括如下活动形式
- 冲刺规划会议(Sprint Plan Meeting)决定当前的冲刺(Sprint)需要解决的事情
- 每日站立会议(Scrum Daily Meeting)日报
- 冲刺评审会议(Sprint Review Meeting)跨团队演示,注重功能而非细节
- 冲刺回顾会议(Sprint Retrospective Meeting)改进
开发(软件工程)、技术运营和质量保障(QA)三者的交集
可看成是敏捷方法从技术开发领域扩展到业务运维领域实现业务上全周期的敏捷性
最小可行产品(MVP,Minimum Viable Product),又称为最小功能集(Minimal Feature Set),把产品最核心的功能用最小的成本实现出来(或者描绘出来),然后快速征求用户意见获得反馈进行改进优化。