《代码中的软件工程》学习总结

吖!查無此人 2023-07-08 22:28:47

什么叫软件工程

软件工程就是要用工程化的方法去规范软件开发,让项目可以按时完成,成本可控,指令有保证。

工欲善其事必先利其器

Typing

https://www.typingclub.com

VSCode

一个轻量且强大的代码编辑器,支持Windows,OS X和Linux。内置JavaScript、TypeScript和Node.js支持,而且拥有丰富的插件生态系统,可通过安装插件来支持C++、C#、Python、PHP等其他语言。

快捷键举例:

Ctrl/⌘+O打开文件夹、Ctrl/⌘+K F关闭文件夹工作区、 Ctrl/⌘+N新建文件、Ctrl/⌘+W关闭文件、Ctrl/⌘+S编辑文件和保存文件、Ctrl/⌘+F文件内搜索、Ctrl/⌘+K W关闭所有文件、Ctrl/⌘+K U关闭已保存的文件、Ctrl+/用于单行代码注释和取消注释,Ctrl+Shift+A用于代码块注释和取消注释。Ctrl+Shift+P调出VS Code命令行,Ctrl+~ 调出VS Code的终端,Ctrl/⌘+Shift+E 文件资源管理器,Ctrl/⌘+Shift+G 源代码管理,Ctrl/⌘+Shift+F 跨文件搜索,Ctrl/⌘+Shift+D 启动和调试,Ctrl/⌘+Shift+M 查看错误和警告,Ctrl/⌘+Shift+X 管理扩展插件。

无鼠标操作:https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf   OR  https://code.visualstudio.com/shortcuts/keyboard-shortcuts-windows.pdf

Git

基本操作逻辑

常用命令:
• 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的头几个字符 # 回退
• git reflog # 可以查看当前HEAD之后的提交记录,便于回到未来
• git reset —hard commit-id/commit- id的头几个字符 # 回退

• git clone命令官方的解释是“Clone a repository into a new directory”,即克隆一个存储库到一个新的目录下。
• git fetch命令官方的解释是“Download objects and refs from another repository”,即下载一个远程存储库数据对象等信息到本地存储库。     
• git push命令官方的解释是“Update remote refs along with associated objects”,即将本地存储库的相关数据对象更新到远程存储库。
• git merge命令官方的解释是“Join two or more development histories together”,即合并两个或多个开发历史记录。--no-ff取消快进式合并
• git pull命令官方的解释是“Fetch from and integrate with another repository or a local branch”,即从其他存储库或分支抓取并合并到当前存储库的当前分支。

• git checkout 分支名 切换分支
• git rebase -i  [startpoint]  [endpoint]  其中-i的意思是--interactive,即弹出交互式的界面让用户编辑完成合并操作,[startpoint]  [endpoint]则指定了一个编辑区间,如果不指定[endpoint],则该区间的终点默认是当前分支的HEAD。一般只指定[startpoint] ,即指定从某一个commit节点开始,可以使用HEAD^^、HEAD~100、commit ID或者commit ID的头几个字符来指定一个commit节点,比如下面的代码指定重新整理HEAD之前的三个commit节点。

Vim

• 命令模式(Command mode),用户刚刚启动vi /vim,便进入了命令模式。此状态下敲击键盘动作会被vim识别为命令,而非输入字符。
• 输入模式(Insert mode), 在命令模式下按下i就进入了输入模式,按ESC退出输入模式,切换到命令模式 。
• 底线命令模式(Last line mode),在命令模式下按下 :(英文冒号)就进入了底线命令模式。底线命令模式可以输入单个或多个字符的命令,可用的命令非常多。基本的命令有q(退出程序)、w(保存文件)等。按ESC键可随时退出底线命令模式 。
• 光标移动:h (左)、j (下)、k (上)、l (右),数字加动作键可多次移动

• n<space>    那个 n 表示『数字』,例如 20 。按下数字后再按空格键,光标会向右移动这一行的 n 个字符。例如 20<space> 则光标会向后面移动 20 个字符距离。
• 0 或功能键[Home]    这是数字『 0 』:移动到这一行的最前面字符处 (常用)
• $ 或功能键[End]    移动到这一行的最后面字符处(常用)
• H    光标移动到这个屏幕的最上方那一行的第一个字符
• M    光标移动到这个屏幕的中央那一行的第一个字符
• L    光标移动到这个屏幕的最下方那一行的第一个字符
• G    移动到这个档案的最后一行(常用)
• nG     n为数字。移动到这个档案的第 n 行。例如 20G 则会移动到这个档案的第 20 行
• gg    移动到这个档案的第一行,相当于 1G 啊! (常用)
• n<Enter>    n 为数字。光标向下移动 n 行(常用)

• x, X    在一行字当中,x 为向后删除一个字符 (相当于 [del] 按键), X 为向前删除一个字符(相当于 [backspace] 亦即是退格键) (常用)
• nx    n 为数字,连续向后删除 n 个字符。举例来说,我要连续删除 10 个字符, 『10x』。
• dd    删除游标所在的那一整行(常用)
• ndd    n 为数字。删除光标所在的向下 n 行,例如 20dd 则是删除 20 行 (常用)
• d1G    删除光标所在到第一行的所有数据
• dG    删除光标所在到最后一行的所有数据
• d$    删除游标所在处,到该行的最后一个字符
• d0    那个是数字的0 ,删除游标所在处,到该行的最前面一个字符

• yy    复制游标所在的那一行(常用)
• p, P     p为将已复制的数据在光标下一行贴上,P则为贴在游标上一行! 举例来说,我目前光标在第 20 行,且已经复制了 10 行数据。则按下 p 后, 那 10 行数据会贴在原本的 20 行之后,亦即由 21 行开始贴。但如果是按下 P 呢? 那么原本的第 20 行会被推到变成 30 行。 (常用)
• nyy      n 为数字。复制光标所在的向下 n 行,例如 20yy 则是复制 20 行(常用)
• y1G    复制游标所在行到第一行的所有数据
• yG    复制游标所在行到最后一行的所有数据
• y0    复制光标所在的那个字符到该行行首的所有数据
• y$    复制光标所在的那个字符到该行行尾的所有数据

• u    复原前一个动作。(常用)
• [Ctrl]+r    重做上一个动作。(常用)
• J    将光标所在行与下一行的数据结合成同一行,2Jj则把下面的2行合并为一行并将光标下移一行
• 在normal mode下q[a-z]开始录制宏命令,再次按q结束宏命令定义。 qa2Jjq,q-开始录制宏;a-宏的编号是a,最后一个q-结束宏定义;3@a,执行三次a宏

• /word    向光标之下寻找一个名称为 word 的字符串。例如要在档案内搜寻 vbird 这个字符串,就输入 /vbird 即可! (常用)
• ?word    向光标之上寻找一个字符串名称为 word 的字符串。
• n    这个 n 是英文按键。代表重复前一个搜寻的动作。举例来说, 如果刚刚我们执行 /vbird 去向下搜寻 vbird 这个字符串,则按下 n 后,会向下继续搜寻下一个名称为 vbird 的字符串。如果是执行 ?vbird 的话,那么按下 n 则会向上继续搜寻名称为 vbird 的字符串!
• N    这个 N 是英文按键。与 n 刚好相反,为『反向』进行前一个搜寻动作。 例如 /vbird 后,按下 N 则表示『向上』搜寻 vbird 。

• :n1,n2s/word1/word2/g    n1 与 n2 为数字。在第 n1 与 n2 行之间寻找 word1 这个字符串,并将该字符串取代为 word2 !举例来说,在 100 到 200 行之间搜寻 vbird 并取代为 VBIRD 则:『:100,200s/vbird/VBIRD/g』。(常用) s是substitute的简写,表示执行替换字符串操作 g(global)表示全局替换;c(comfirm)表示操作时需要确认;i(ignorecase)表示不区分大小写 :1,$s/word1/word2/g 或:%s/word1/word2/g 从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2 !(常用) :1,$s/word1/word2/gc 或 :%s/word1/word2/gc 从第一行到最后一行寻找 word1 字符串,并将该字符串取代为 word2 !且在取代前显示提示字符给用户确认 (confirm) 是否需要取代!(常用)

• i, I    进入输入模式(Insert mode): i 为『从目前光标所在处输入』, I 为『在目前所在行的第一个非空格符处开始输入』。 (常用)
• a, A    进入输入模式(Insert mode): a 为『从目前光标所在的下一个字符处开始输入』, A 为『从光标所在行的最后一个字符处开始输入』。(常用)
• o, O    进入输入模式(Insert mode): 这是英文字母 o 的大小写。o 为『在目前光标所在的下一行处输入新的一行』; O 为在目前光标所在处的上一行输入新的一行!(常用)
• r, R    进入取代模式(Replace mode): r 只会取代光标所在的那一个字符一次;R会一直取代光标所在的文字,直到按下 ESC 为止;(常用)
• [Esc]    退出编辑模式,回到一般模式中(常用) 编辑模式在vi画面的左下角处会出现『--INSERT--』或『--REPLACE--』的字样

• :w    将编辑的数据写入硬盘档案中(常用)
• :w!    若文件属性为『只读』时,强制写入该档案。不过,到底能不能写入, 还是跟你对该档案的档案权限有关啊!
• :w [filename]    将编辑的数据储存成另一个档案(类似另存新档)
• :q    离开 vi (常用)
• :q!    若曾修改过档案,又不想储存,使用 ! 为强制离开不储存档案。
• :wq    储存后离开,若为 :wq! 则为强制储存后离开 (常用)

• 批量注释:Ctrl + v 进入块选择模式,然后移动光标选中你要注释的行(VSCode可以鼠标选择代码块),再按大写的 I 进入行首插入模式输入注释符号如 // 或 #,输入完毕之后,按两下 ESC,Vim 会自动将你选中的所有行首都加上注释,保存退出完成注释。
• 取消注释:Ctrl + v 进入块选择模式,选中你要删除的行首的注释符号,注意 // 要选中两个,选好之后按 d 即可删除注释,ESC 保存退出。
• 批量注释:使用下面命令在指定的行首添加注释。使用命令格式: :起始行号,结束行号s/^/注释符/g (注意冒号)如:10,20s#^#//#g,:10,20s/^/#/g
• 取消注释:使用名命令格式: :起始行号,结束行号s/^注释符//g(注意冒号),如:10,20s#^//##g,:10,20s/#//g

• :set nu    显示行号,设定之后,会在每一行的前缀显示该行的行号
• :set nonu    与 set nu 相反,为取消行号!

RegEX

1、作用(正则表达式是一种字符串匹配的模式)
数据验证:比如电话号码、邮箱等
替换文本:快速找到特定文本,用于替换
快速提取字符串:基于匹配原则,快速从文档中查找或提取子字符串

2、语法(普通字符+特殊字符)
普通字符
[abc] 匹配[...]的所有字符
[^abc] 取反,除了[...]的其他字符
[A-Z] 区间字母A到Z

. 匹配除(\n换行符 \r 回车符)的任何单个字符
\s \S 匹配所有,\s所有空白符,包括换行 \S非空白符,不包括换行
\w 匹配字母、数字、下划线

特殊字符
$ 结尾位置 (匹配$字符----\$)
^ 开始位置(匹配$字符----\^)
() 子表达式开始和结束(匹配字符----\(   和  \))
* 匹配零次或多次(匹配字符----\*)
+ 匹配一次或多次(匹配字符----\+)
? 匹配零次或一次(匹配字符----\?)
{downlim, uplim} 匹配次数上下限
[words] 匹配一组字符。例如,你要匹配"bag","big"和"bug",而不是"bog"。你可以创建正则表达式/b[aiu]g 来执行此操作。
- 匹配字符范围
^ 定义不想要匹配的字符。否定字符集,你可以在方括号的开括号之后放置一个插入字符“^”。例如[^aeiou]排除元音的所有字符。

在正则表达式中,greedy 贪婪匹配找到符合正则表达式模式的字符串的最长可能部分,并将其作为匹配返回。相反还有 lazy 懒惰匹配,是找到符合正则表达式模式的字符串的最小可能部分。 你可以将正则表达式t[a-z]*i应用于字符串"titanic"。这个正则表达式基本上是以 t 开始的模式,以 i 结尾,并且之间有0个、1个或多个字母。 正则表达式是默认的是 greedy 贪婪匹配,所以匹配将返回"titani"。它可以找到最大的子字符串,以符合该模式。 但是可以使用?字符将其更改为 lazy 懒惰匹配。“titanic”匹配调整后的t[a-z]*?i正则表达式会返回["ti"]。注意这时字符“?”表示 lazy 懒惰匹配,字符“?”还可以作为通配符表示检查前一个元素存在与否。

正则表达式可用于查找匹配字符串开头和末尾位置的模式。
在前面你使用 character sets 字符集中的插入字符“^”创建一[^thingsThatWillNotBeMatched]形式的 negated character set 否定字符集。在方括号之外的正则表达式中插入字符“^”用于表示字符串的开头。美元字符“$”表示字符串的末尾。     
• 插入字符“^”用于表示字符串的开头。     
• 美元字符“$”表示字符串的末尾。 如在"Ricky is first and can be found”查找开头的 Ricky 则为^Ricky,查找结尾的 found 则为/found$。

可以使用\s 搜索空格,这是一个小写的 s 即 space 之意。此模式不仅匹配空格,还包括回车、制表符、换页和新行字符。你可以将其看作与字符集[\r\t\f\n\v]类似。
使用\S 搜索非空格,这是一个大写的 S。此模式将不匹配空格、回车符、制表符、换页和新行字符。你可以想象它类似于字符类[^\r\t\f\n\v]。     
• \n:换行(光标到下行行首);   
• \r:回车(光标到本行行首);   
• \f:换页;     
• \t:水平跳格(水平制表);     
• \v:垂直跳格(垂直制表)。

工程化的编程实践

代码风格原则:简明、易读、无二义性

三重境界:一是规范整洁。遵守常规语言规范,合理使用空格、空行、缩进、注释等;二是逻辑清晰。没有代码冗余、重复,让人清晰明了的命名规则。做到逻辑清晰不仅要求程序员的编程能力,更重要的是提高设计能力,选用合适的设计模式、软件架构风格可以有效改善代码的逻辑结构,会让代码简洁清晰;三是优雅。优雅的代码是设计的艺术,是编码的艺术,是编程的最高追求

编写高质量代码的基本方法:
通过控制结构简化代码;通过数据结构简化代码;一定要有错误处理

模块化软件设计

模块化的基本原理

模块化(Modularity)是在软件系统设计时保持系统内各部分相对独立,以便每一个部分可以被独立地进行设计和开发。
基本原理是关注点的分离 (SoC, Separation of Concerns),每一个软件模块都将只有一个单一的功能目标,并相对独立于其他软件模块,使得每一个软件模块都容易理解容易开发,从而整个软件系统也更容易定位软件缺陷bug,整个系统的变更和维护也更容易
一般使用耦合度(Coupling)和内聚度(Cohesion)来衡量软件模块化的程度。耦合度是指软件模块之间的依赖程度,一般可以分为紧密耦合(Tightly Coupled)、松散耦合(Loosely Coupled)和无耦合(Uncoupled),一般在软件设计中我们追求松散耦合。;内聚度是指一个软件模块内部各种元素之间互相依赖的紧密程度。理想的内聚是功能内聚,也就是一个软件模块只做一件事,只完成一个主要功能点或者一个软件特性(Feather)。

软件设计中的一些基本方法

KISS原则:一个函数或方法只做一件事
使用本地化外部接口来提高代码的适应能力:我们的代码不是通过API直接调用外部的代码,而是在我们的代码中调用本地的外部接口,本地的外部接口再去调用外部代码
先写伪代码,设计通常为程序提供了一个框架,程序员需要用自己的专业知识和创造性来编写代码实现设计。在从设计到编码的过程中加入伪代码阶段要好于直接将设计翻译成实现代码。

可重用软件设计

接口基本概念

接口就是互相联系的双方共同遵守的一种协议规范,在我们软件系统内部一般的接口方式是通过定义一组API函数来约定软件模块之间的沟通方式。
在面向过程的编程中,接口一般定义了数据结构及操作这些数据结构的函数;而在面向对象的编程中,接口是对象对外开放(public)的一组属性和方法的集合。函数或方法具体包括名称、参数和返回值等。

基本要素

1. 接口的目的
2. 接口的前置条件
3. 接口的协议规范(如
http协议,png图片格式,json数据格式定义etc..
4. 接口的后置条件
5. 接口的质量属性(如响应时间)

RESTful API

在模块化思想的指导下目前主要有两种软件架构模式,即传统单体集中式(Monolithic)架构与微服务(Microservice)架构。微服务接口一般使用RESTful API来定义接口。RESTful API是目前最流行的一种互联网软件接口定义方式。

 

REST即REpresentational State Transfer的缩写,可以翻译为”表现层状态转化”。有表现层就有背后的信息实体,信息实体就是URI代表的资源,也可以是一种服务,状态转化就是通过HTTP协议里定义的四个表示操作方式的动词:GET、POST、PUT、DELETE,分别对应四种基本操作:

  • GET用来获取资源;
  • POST用来新建资源(也可以用于更新资源);
  • PUT用来更新资源;
  • DELETE用来删除资源。

耦合方式

对于软件模块之间的耦合度,前文中提到,耦合度是指软件模块之间的依赖程度,一般可以分为紧密耦合(Tightly Coupled)、松散耦合(Loosely Coupled)和无耦合(Uncoupled)。一般在软件设计中我们追求松散耦合。 更细致地对耦合度进一步划分的话,耦合度依次递增可以分为无耦合、数据耦合、标记耦合、控制耦合、公共耦合和内容耦合。这些耦合度划分的依据就是接口的定义方式,我们接下来重点分析一下公共耦合、数据耦合和标记耦合。

1. 公共耦合
当软件模块之间
共享数据区 变量名 的软件模块之间即是公共耦合,显然两个软件模块之间的接口定义不是通过显式的调用方式,而是 隐式 的共享了共享了数据区或变量名。

2. 数据耦合
在软件模块之间仅通过显式的调用传递
基本数据类型 即为数据耦合。

3. 标记耦合
在软件模块之间仅通过显式的调用传递复杂的数据结构(
结构化数据)即为标记耦合,这时数据的结构成为调用双方软件模块隐含的规格约定,因此耦合度要比数据耦合高。但相比公共耦合没有经过显式的调用传递数据的方式耦合度要低。

通用接口定义的基本方法

1. 参数化上下文(使用参数传递信息,不依赖上下文环境,即不使用闭包函数)

2. 移除前置条件(sum函数中使用数组传递参数,不再限定参数个数)

3. 简化后置条件(移除参数之间的关系,使sum返回的是数组全部元素的和)

可重入函数与线程安全

线程的基本概念-略、函数调用堆栈框架-略

可重入函数
可重入(reentrant)函数可以由多于一个任务并发使用,而不必担心数据错误。相反,不可重入(non-reentrant)函数不能由超过一各任务所共享,除非能确保函数的互斥(或者使用信号量,或者在代码的关键部分禁用中断)。可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据。可重入函数要么使用局部变量,要么在使用全局变量时保护自己的数据。

可重入函数的基本要求
不为连续的调用持有静态数据;不返回指向静态数据的指针;所有数据都由函数的调用者提供;使用局部变量,或者通过制作全局数据的局部变量拷贝来保护全局数据;使用静态数据或全局变量时做周密的并行时序分析,通过临界区互斥避免临界区冲突;绝不调用任何不可重入函数。

什么是线程安全?
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行读写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

函数的可重入性与线程安全之间的关系
可重入的函数不一定是线程安全的,可能是线程安全的也可能不是线程安全的;可重入的函数在多个线程中并发使用时是线程安全的,但不同的可重入函数(共享全局变量及静态变量)在多个线程中并发使用时会有线程安全问题;不可重入的函数一定不是线程安全的。

从需求分析到软件设计

定义
需求就是对用户期望的软件行为的表述;需求分析是在获取需求的基础上进一步对软件涉及的对象或实体的状态、特征和行为进行准确描述或建模的工作

需求的类型
1. 功能需求:根据所需的活动描述所需的行为
2. 质量需求或非功能需求:描述软件必须具备的一些质量特性
3. 设计约束
(设计约束): 设计决策,例如选择平台或接口组件
4. 过程约束
(过程约束): 对可用于构建系统的技术或资源的限制

获取高质量需求的方法
采访利益相关者、回顾文档、研究当前系统、了解用户的任务、使用特定领域的策略、与当前和潜在用户进行头脑风暴

高质量需求的特点
Correct正确的、Consistent一致的、Unambigious无二义性的、Complete完整的、Feasible可行的、Relevant和主要目标相关、Testable可测试的、Traceable可追踪的

需求分析的两类基本方法
原型化方法:很好地整理出用户接口方式
建模的方法:快速给出有关事件发生顺序或活动同步约束的问题,能够在逻辑上形成模型来整顿繁杂的需求细节

用例

基本概念
用例(Use Case
)的核心概念中首先它是一个业务过程(business process),经过逻辑整理抽象出来的一个业务过程,这是用例的实质。什么是业务过程?在待开发软件所处的业务领域内完成特定业务任务(business task)的一系列活动就是业务过程。

四个必要条件

必要条件一:它是不是一个业务过程?
必要条件二:
它是不是由某个参与者触发开始?
必要条件三:
它是不是显式地或隐式地终止于某个参与者?
必要条件四:
它是不是为某个参与者完成了有用的业务工作?

三个抽象层级

1. 抽象用例(Abstract use case)。只要用一个干什么、做什么或完成什么业务任务的动名词短语,就可以非常精简地指明一个用例。2. 高层用例(High level use case)。需要给用例的范围划定一个边界,也就是用例在什么时候,什么地方开始,以及在什么时候什么地方结束;
3. 扩展用例(
Expanded use case)。需要将参与者和待开发软件系统为了完成用例所规定的业务任务的交互过程一步一步详细地描述出来,一般我们使用一个两列的表格将参与者和待开发软件系统之间从用例开始到用例结束的所有交互步骤都列举出来。扩展用例最后可以用两列表格描述。

统一过程

核心要义

统一过程(UPUnified Process)的核心要义是 用例驱动 Use case driven)、 以架构为中心 (Architecture centric)、 增量且迭代 (Incremental and Iterative)的过程。用例驱动就是我们前文中用例建模得到的用例作为驱动软件开发的目标;以架构为中心的架构是后续软件设计的结果,就是保持软件架构相对稳定,减小软件架构层面的重构造成的混乱;增量且迭代体现在下图中。

 

敏捷统一过程的四个关键步骤
第一,确定需求;
第二,通过用例的方式来满足这些需求;
第三,分配这些用例到各增量阶段;
第四,具体完成各增量阶段所计划的任务。

显然,第一到第三步主要是计划阶段的工作,第四步是接下来要进一步详述的增量阶段的工作。 在每一次增量阶段的迭代过程中,都要进行从需求分析到软件设计实现的过程,具体敏捷统一过程

将增量阶段分为五个步骤:
• 用例建模(
Use case modeling);
• 业务领域建模(
Domain modeling);
• 对象交互建模(
Object Interaction modeling,使用剧情描述来建模,最后转换为剧情描述表;
• 形成设计类图(design class diagram);
• 软件的编码实现和软件应用部署;

形成软件设计方案的基本方法
分析是分解大问题变成易于理解的小问题 综合是将小问题的解决方案组合起来构建软件的整体解决方案

软件科学基础概论

软件中的一些特殊机制
回调函数
回调函数就是一个通过函数指针调用的函数。把函数的指针(地址)作为参数传递给另一个函数,当这个指针调用其所指向的函数时,就称这是回调函数。回调函数不是该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应

继承和组合
继承可以重用代码,但是破坏了代码的封装特性,增加了父类与子类之间的代码模块耦合,因此我们需要避免使用继承,在大多数情况下,应该使用对象组合替代继承来实现相同的目标

多态
允许将不同的子类类型的对象动态赋值给父类类型的变量,通过父类的变量调用方法在执行时实际执行的可能是不同的子类对象方法,因而表现出不同的执行效果

闭包
闭包是变量作用域的一种特殊情形,一般用在将函数作为返回值时,该函数执行所需的上下文环境也作为返回的函数对象的一部分,这样该函数对象就是一个闭包 函数和对其周围状态的引用捆绑在一起构成闭包,在JavaScript中,每当函数被创建,就会在函数生成时生成闭包

异步调用
Promise对象实际上是对回调函数机制的封装,也就是通过then方法定义的函数与resolve/reject函数绑定,简化了回调函数传入的接口实现,在逻辑上也更加通顺,看起来像是个同步接口

匿名函数
lamda函数是函数式编程中的高阶函数,在我们常见的命令式编程语言中常常以匿名函数的形式出现,比如无参数的代码块{ code },有参数的匿名函数往往会使用箭头函数 { x => code };

设计模式
本质是面向对象设计原则的实际运用总结出的经验模型,要解决的问题是用模块化来包容变化,使用模块化封装的方法,按照模块化追求的高内聚低耦合目标,借助于抽象思维对模块内部信息的隐藏并使用封装接口对外只暴露必要的可见信息

常见的设计模式
 •  单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,典型的应用如数据库实例 。
•  原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例,原型模式的应用场景非常多,几乎所有通过复制的方式创建新实例的场景都有原型模式。
•  建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。主要应用于复杂对象中的各部分的建造顺序相对固定或者创建复杂对象的算法独立于各组成部分。
设计原则
开闭原则(Open Closed Principle,OCP)
软件应当对扩展开放,对修改关闭(Software entities should be open for extension,but closed for modification)

Liskov替换原则(Liskov Substitution Principle,LSP)
继承必须确保超类所拥有的性质在子类中仍然成立(Inheritance should ensure that any property proved about supertype objects also holds for subtype objects)。

依赖倒置原则(Dependence Inversion Principle,DIP)
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象(High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions)。其核心思想是:要面向接口编程,不要面向实现编程。

单一职责原则(Single Responsibility Principle,SRP)
单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分(There should never be more than one reason for a class to change)

迪米特法则(Law of Demeter,LoD)
如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性

合成复用原则(Composite Reuse Principle,CRP)
它要求在软件复用时,要尽量先使用组合或者聚合关系来实现,其次才考虑使用继承关系来实现

创建型模式
单例模式
某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例

原型模式
将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例,原型模式的应用场景非常多,几乎所有通过复制的方式创建新实例的场景都有原型模式

建造者模式
将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象

结构型模式
代理模式
为某对象提供一种代理以控制对该对象的访问,从而限制、增强或修改该对象的一些特性。典型的应用如外部接口本地化将外部的输入和输出封装成本地接口,有效降低模块与外部的耦合度。

适配器模式
将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作,对象组合方式的适配器模式比较常用

行为型模式
策略模式
定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。策略模式是多态和对象组合的综合应用

命令模式
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开

模板方法模式
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤

职责链模式
将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链

中介者模式
定义一个中介对象来简化原有对象之间的交互关系 降低系统中对象间的耦合度,使原有对象之间不必相互了解。如控制器就是模型和视图的中介者,采用“中介者模式”大大降低了对象之间的耦合性,提高系统的灵活性,改变通知给其他多个对象,从而影响其他对象的行为 这样所有依赖于它的对象都得到通知并被自动更新

常见的软件架构举例
三层架构
表示层:主要对用户的请求接受,以及数据的返回,为客户端提供应用程序的访问。
业务逻辑层:主要负责对数据层的操作。也就是说把一些数据层的操作进行组合。
数据访问层:主要看数据层里面有没有包含逻辑处理,实际上它的各个函数主要完成各个对数据文件的操作。而不必管其他操作。
MVC
Model代表一个存取数据的对象及其数据模型 View代表模型包含的数据的表达方式,一般表达为可视化的界面接口 Controller作用于模型和视图上,控制数据流向模型对象,并在数据变化时更新视图。控制器可以使视图与模型分离开解耦合

MVVM
把Model用纯JavaScript对象表示,View负责显示,两者做到了最大限度的分离。把Model和View关联起来的就是ViewModel。ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model

软件架构的描述方法
分解视图
        分解是构建软件架构模型的关键步骤,分解视图也是描述软件架构模型的关键视图,一般分解视图呈现为较为明晰的分解结构(breakdown structure)特点。分解视图用软件模块勾划出系统结构,往往会通过不同抽象层级的软件模块形成层次化的结构。由于前述分解方法中已经明确呈现出了分解视图的特征,我们这里简要了解一下分解视图中常见的软件模块术语。  

依赖视图      
        依赖视图展现了软件模块之间的依赖关系。比如一个软件模块A调用了另一个软件模块B,那么我们说软件模块A直接依赖软件模块B。如果一个软件模块依赖另一个软件模块产生的数据,那么这两个软件模块也具有一定的依赖关系。

泛化视图
        泛化视图展现了软件模块之间的一般化或具体化的关系,典型的例子就是面向对象分析和设计方法中类之间的继承关系。值得注意的是,采用对象组合替代继承关系,并不会改变类之间的泛化特征。因此泛化是指软件模块之间的一般化或具体化的关系,不能局限于继承概念的应用。

执行视图
       执行视图展示了系统运行时的时序结构特点,比如流程图、时序图等。执行视图中的每一个执行实体,一般称为组件(Component),都是不同于其他组件的执行实体。如果有相同或相似的执行实体那么就把它们合并成一个。

实现视图
        实现视图是描述软件架构与源文件之间的映射关系。

部署视图
        部署视图是将执行实体和计算机资源建立映射关系。

工作分配视图
        工作分配视图将系统分解成可独立完成的工作任务,以便分配给各项目团队和成员。

软件危机和软件过程

软件过程模型
瀑布模型
瀑布模型是一个过程活动的顺序结构,没有任何迭代。瀑布模型不能为处理开发过程中的变更提供任何指导意义,因为瀑布模型假定需求不会发生任何变化

原型化的瀑布模型
原型就是根据需要完成的软件的一部分,完成哪一部分是根据开发原型的目标确定,比较常见的有用户接口原型和软件架构原型

v模型
在瀑布模型基础上将需求分析和接受度测试、系统设计和系统测试、详细设计和单元测试结合起来,最后是产品,提高过程活动的内聚度

生死相依原则:创建一个对象和销毁一个对象的代码成对出现便于代码的组织和管理,V模型就是开始一个特定过程活动和评估该特定过程活动成对出现,从而便于软件开发过程的组织和管理

分阶段开发可以让客户在没有开发完成之前就可以使用部分功能,也就是每次交付系统的一小部分

分阶段开发的优点 在系统没有开发完成之前,开始进行交付和用户培训 频繁的软件发布可以让开发者敏捷的应对始料未及的问题 开发团队可以在不同的版本聚焦与不同的功能领域,从而提高开发效率 有助于提前布局抢占市场

螺旋模型
螺旋模型是一种演化软件开发过程模型,兼顾了快速原型的迭代的特征以及瀑布模型的系统化与严格监控。螺旋模型最大的特点在于引入了其他模型不具备的风险管理,使软件在无法排除重大风险时有机会停止,以减小损失

PSP、TSP
个体软件过程PSP可以帮助软件工程师在运用软件过程的方法和原则,借助于一些度量和分析工具,了解自己的技能水平,控制和管理自己的工作方式,使自己日常工作中的评估、计划和预测更加准确、更加有效,进而改进个人的工作表现

团队强度和项目特点的关系
项目失败最根本的原因是团队问题(缺乏有效的领导和管理、不能做出妥协、安排或不善于合作、缺少参与、拖拉与缺乏信息、质量低劣、功能多余、无效的组员互评)

团队项目的基本策略
计划先行 完成概念设计 选择开发策略 完成规模计算 完成时间计算 评估风险 建立策略文档 指定配置管理计划

CMM/CMMI
CMM/CMMI用于评价软件生成能力并帮助其改善软件质量的方法,成为了评估软件能力与成熟度的一套标准,它侧重于软件开发过程的管理及工程能力的提高与评估 CMM有两种通用的评估方法用以评估组织软件过程的成熟度:软件过程评估和软件能力评价 CMM主要应用在两个方面:能力评估(软件过程评估和软件能力评估)和过程改进

敏捷宣言的核心思想
个体和互动高于流程和工具

工作的软件高于详尽的文档

客户合作高于合同谈判

响应变化高于遵循计划

DevOps
DevOps是一组过程、方法与系统的统称,用于促进软件开发、技术运营和质量保障部门之间的沟通、协作与整合

总结
        以上内容是对一本好书---《代码中的软件工程》的总结,深入浅出地为我们介绍软件工程这一学科,收益匪浅。工欲善其事必先利其器,先给我们介绍了作为一个“码农”需要掌握的工具,VS CODE---被誉为宇宙第一的代码编辑器,轻量级,安装包小的同时还具有丰富的插件和扩展包,VIM,一个UNIX的文本编辑器,还有合作开发必备的git技巧,提高效率的正则表达式等等,正所谓磨刀不误砍柴工,在系统学习软件工程之前先学习工具的使用,才能使得后续的工作更顺利的开展。接着是通过一个menu的小项目来带我们进入代码中的软件工程,软件工程不能只停留在表面功夫,更应该注重实操和编程的能力,所以该章节用一个小项目向我们展示了一个规范的合理的通用的项目从0到1的过程,与此同时熟悉git的用法,了解项目开发的一些模块接口的规范使用。第二章是交给我们如何去开发一个模块,一个实用的小项目,第三章的需求分析阶段则更加倾向于教会我们在实际的生产中如何去确定一个项目的需求,这是至关重要的,我们所开发的代码程序最终是要为客户的需求所服务的,因此一个高质量的需求分析是非常重要的,之后又介绍了软件中的一些特殊函数和机制,还有设计模式,这是对面向对象设计中反复出现的问题的解决方案的总结和凝练,是一套较为成熟的经验模板,供我们借鉴和使用,之后还有常见的架构和软件的过程模型的介绍。总之通过对该课程系统的学习,对软件工程又有了新的更为透彻的理解,这不是一门理论科学而是一门应用科学,尤其对设计模式的理解,这不仅仅是一个模板,更是一种思想,我们要学习的就是这种编程的思想,而不是死记硬背模板。

参考资料

代码中的软件工程 https://gitee.com/mengning997/se
 

...全文
201 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

571

社区成员

发帖
与我相关
我的任务
社区描述
软件工程教学新范式,强化专项技能训练+基于项目的学习PBL。Git仓库:https://gitee.com/mengning997/se
软件工程 高校
社区管理员
  • 码农孟宁
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧