高级软件工程学习总结

一、工欲善其事必先利其器

VsCode

VsCode 近年来获得了爆炸式增长,成为广大开发者工具库中的必备神器。其成功之处主要在于设计者简洁而聚焦的产品定位、进程隔离的插件模型、LSP 和 DAP 两大协议。

VsCode专注于开发者“最常用”的功能:编辑器+代码理解+版本控制+远程开发+调试。这是一个非常节制而平衡的选择,专注于开发者“最常用”的功能,同时在产品的形式上力求简洁高效。从结果来看,这个定位是相当成功的。

稳定性对于 VsCode 来说尤为重要。都知道 VsCode 基于 Electron.js,实质上是个 Node.js 环境,Node.js是单线程的,任何代码崩了都是灾难性的后果。所以 VsCode 干脆不信任任何人,把插件们放到单独的进程里,插件进程怎么折腾也无法干扰主进程代码的执行,主程序的稳定性得到了保障

代码理解和调试,绝大部分功能都是由第三方插件来实现的,这些用于代码理解和调试的第三方插件与 VsCode 主进程之间的桥梁就是两大协议—— Language Server Protocol(LSP) 和 Debug Adapter Protocol(DAP) 。

LSP 显然把小巧作为设计目标之一,它选择做最小子集,贯彻了团队一贯节制的作风。它关心的是用户在编辑代码时最经常处理的物理实体(比如文件、目录)和状态(光标位置)。它根本没有试图去理解语言的特性,编译也不是它所关心的问题,所以自然不会涉及语法树一类的复杂概念。
小归小,功能可不能少,所以抽象就非常关键了。LSP 最重要的概念是动作和位置,LSP 的大部分请求都是在表达"在指定位置执行规定动作"。
其次这是一个基于 JSON 的协议,JSON 可以说是最易读的结构化数据格式了。

一些常用的快捷键用法

打开文件夹(Ctrl + O)和关闭文件夹工作区(Ctrl + K F)
新建文件(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 + D 启动和调试
Ctrl + Shift + P 查找并运行所有命令
Ctrl + Shift + M 查看错误和警告
Ctrl + Shift +  X 管理扩展插件
Ctrl + ` 切换集成终端

Git

分布式版本控制系统 —— Git 是目前世界上最先进的分布式版本控制系统。

# 克隆或同步最新的代码到本地存储库
git clone https://DOMAIN_NAME/YOUR_NAME/REPO_NAME.git
git pull 
# 为自己的工作创建一个分支,该分支应该只负责单一功能模块或代码模块的版本控制
git checkout -b mybranch
git branch
# 在该分支上完成某单一功能模块或代码模块的开发工作;多次进行如下操作:
git add FILES
git commit -m "commit log"
# 最后,先切换回master分支,将远程origin/master同步最新到本地存储库,再合并mybranch到master分支,推送到远程origin/master之后即完成了一项开发工作。
git checkout master
git pull
git merge --no-ff mybranch
git push

vim

vim 是从 vi 发展出来的一个文本编辑器。在代码补完、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。

正则表达式

正则表达式 (regular expression) 描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。

正则表达式应用广泛,在绝大多数的编程语言都可以完美应用。在 Linux 中,也有着极大的用处。

使用正则表达式,可以有效的筛选出需要的文本,然后结合相应的支持的工具或语言,完成任务需求。

介绍一些常用的通配符及一些用法:

  • 通配符 "." 将匹配任意一个字符。通配符也可称为 dot 和 period。你可以像正则表达式中的任何其他字符一样使用通配符。例如,如果你想匹配 "hug","huh","hut" 和 "hum" ,可以使用正则表达式 hu. 来匹配这所有四个字符串。
  • 通配符 "+" 用来查找出现一次或多次的字符。例如 hahhhhh ,可以使用正则表达式 hah+ 来匹配。
  • 通配符 "*" 匹配零次或多次出现的字符。使用正则表达式 hah* 来匹配,还可以匹配 ha 字符串。
  • 通配符 "?" 指定可能存在的元素,也就是检查前一个元素存在与否。如正则表达式 colou?r 、favou?rite 中通配符 "?" 前面的 u 字符存在和不存在两种情况的字符串都会匹配。
  • 数量说明符使用大括号 {and} 。将两个数字放在大括号之间用逗号 "," 隔开表示上限和下限数。要匹配字符串 "aaah" 中出现 3 到 5 次的 a,你的正则表达式将是 a{3,5}h 。
  • 用方括号 [and] 中来定义一组你希望匹配的字符。例如,你要匹配 "bag" ,"big" 和 "bug",你可以创建正则表达式 /b[aiu]g 来执行此操作。
  • 插入字符 "^" 用于表示字符串的开头。美元字符 "$" 表示字符串的末尾。例如在 "Ricky is first and can be found" 中查找开头的 "Ricky" 则为 ^Ricky ,查找结尾的 "found" 则为 found$ 。
  • 使用 capture groups 捕获组来匹配字符串中连续出现三次的数字,每个数字由空格分隔,如(\d+)\s\1\s\1。

二、代码中的软件工程-工程化编程实战

代码规范和代码风格

一个项目代码的风格就如同一个人给人的印象,代码风格之所以那么重要,是因为它往往决定了代码是否规范、是否易于阅读。
我们把代码的风格分成三重境界:

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


编写高质量代码的方法

  • 通过控制结构简化代码(if else / switch / while)
  • 通过数据结构简化代码
  • 一定要有错误处理
  • 注意性能优先的代价
  • 拒绝修修补补,要不断重构代码

模块化软件设计


模块化(Modularity)是在软件系统设计时保持系统内各部分相对独立,以便每一个部分可以被独立地进行设计和开发。

这个做法背后的基本原理是关注点的分离 (SoC, Separation of Concerns)。每个模块只有一个功能,易于开发,并且 bug 会集中在少数几个模块内,容易定位软件缺陷,也更加容易维护。
软件设计中的模块化程度便成为了软件设计有多好的一个重要指标,一般我们使用耦合度(Coupling)和内聚度(Cohesion)来衡量软件模块化的程度。一般在软件设计中我们追求松散耦合。

内聚度是指一个软件模块内部各种元素之间互相依赖的紧密程度。
理想的内聚是功能内聚,也就是一个软件模块只做一件事,只完成一个主要功能点或者一个软件特性(Feather)。

基本方法

KISS(keep it simple & stupid)原则

  • 一行代码只做一件事
  • 一个块代码只做一件事
  • 一个函数只做一件事
  • 一个软件模块只做一件事

使用本地化外部接口,本质上是一种设计模式,代理模式,即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。能够有效降低模块与外部的耦合度。

先写伪代码的代码结构。

可重用软件设计-接口

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

接口的五个基本要素
  • 接口的目的
  • 接口的前置条件
  • 接口的协议规范(如http协议,png图片格式,json数据格式定义etc…)
  • 接口的后置条件
  • 接口的质量属性(如响应时间)
RESTful API
  • GET用来获取资源。
  • POST用来新建资源(也可以用于更新资源)。
  • PUT用来更新资源。
  • DELETE用来删除资源。
耦合方式
  • 公共耦合: 当软件模块之间 共享数据区或 变量名的软件模块之间即是公共耦合,显然两个软件模块之间的接口定义不是通过显式的调用方式,而是隐式的共享了共享了数据区或变量名。
  • 数据耦合:在软件模块之间仅通过显式的调用传递基本数据类型即为数据耦合。
  • 标记耦合:在软件模块之间仅通过显式的调用传递复杂的数据结构(结构化数据)即为标记耦合,这时数据的结构成为调用双方软件模块隐含的规格约定,因此耦合度要比数据耦合高。但相比公共耦合没有经过显式的调用传递数据的方式耦合度要低。
通用接口定义的基本方法
  • 参数化上下文(使用参数传递信息,不依赖上下文环境,即不使用闭包函数)。
  • 移除前置条件(sum函数中使用数组传递参数,不再限定参数个数)。
  • 简化后置条件(移除参数之间的关系,使sum返回的是数组全部元素的和)。

三、从需求分析到软件设计

需求的类型

需求的类型划分如下:

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

高质量需求的特点:

  • Making Requirements Testable(需求可测试)
  • Resolving Conflicts(解决冲突)
  • Characteristics of RequirementsCorrect:Consistent、Unambigious、Complete、Feasible、Relevant、Testable、Traceable

需求分析和建模

需求分析的两种基本方法:

  • 原型化方法:原型化方法可以很好地整理出用户接口方式(UI,User Interface),比如界面布局和交互操作过程。
  • 建模的方法:建模的方法可以快速给出有关事件发生顺序或活动同步约束的问题,能够在逻辑上形成模型来整顿繁杂的需求细节。
用例

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

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

三个抽象层级

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

从需求分析到软件设计

我们所遵循的软件过程 —— 敏捷统一过程。为了理解敏捷统一过程,我们先从瀑布模型(Waterfall Process)说起。
瀑布模型是最基本的过程模型,它把整个软件过程按顺序划分成了需求、设计、编码、测试和部署五个阶段。瀑布模型的根本特点是按顺序划分阶段。

统一过程

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

敏捷统一过程的四个关键步骤:

第一,确定需求;
第二,通过用例的方式来满足这些需求;
第三,分配这些用例到各增量阶段;
第四,具体完成各增量阶段所计划的任务。
显然,第一到第三步主要是计划阶段的工作,第四步是接下来要进一步详述的增量阶段的工作。
在每一次增量阶段的迭代过程中,都要进行从需求分析到软件设计实现的过程,具体敏捷统一过程
将增量阶段分为五个步骤:

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

四、软件科学基础概论

三种系统类型

  • S系统:有规范定义,可从规范派生。如矩阵运算。
  • P系统:需求基于问题的近似解,但现实世界保持稳定。如象棋程序。
  • E系统:嵌入现实世界并随着世界的变化而变化(大多数软件都属于这个类型)。如预测经济运行的软件。

设计模式

设计模式的本质是面向对象设计原则的实际运用总结出的经验模型。目的是包容变化,即通过使用设计模式和多态等特殊机制,将变化的部分和不变的部分进行适当隔离。

正确使用设计模式具有以下优点:

  • 可以提高程序员的思维能力、编程能力和设计能力。
  • 使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开
  • 发周期。
  • 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。

设计模式由四个部分组成:

  • 该设计模式的名称。
  • 该设计模式的目的,即该设计模式要解决什么样的问题。
  • 该设计模式的解决方案。
  • 该设计模式的解决方案有哪些约束和限制条件。

根据作用对象分两类:

  • 类模式:用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时刻便确定下来了。比如模板方法模式等属于类模式。
  • 对象模式:用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时刻是可以变化的,更具动态性。由于组合关系或聚合关系比继承关系耦合度低,因此多数设计模式都是对象模式。
七大原则
  • 单一职责原则 (Single Responsibility Principle)
  • 开放关闭原则 (OpenClosed Principle)
  • 里氏替换原则 (Liskov Substitution Principle)
  • 依赖倒转原则 (Dependence Inversion Principle)
  • 接口隔离原则 (Interface Segregation Principle)
  • 迪米特法则(Law Of Demeter)
  • 组合/聚合复用原则 (Composite/Aggregate Reuse Principle)

软件架构复用

软件架构复用:

  • 克隆,完整地借鉴相似项目的设计方案,甚至代码,只需要完成一些细枝末节处的修改适配工作。
  • 重构,构建软件架构模型的基本方法,通过指引我们如何进行系统分解,并在参考已有的软件架构模型的基础上逐步形成系统软件架构的一种基本建模方法。
几种架构的分解方法
  • 面向功能的分解方法,用例建模即是一种面向功能的分解方法;
  • 面向特征的分解方法,根据数量众多的某种系统显著特征在不同抽象层次上划分模块的方法;
  • 面向数据的分解方法,在业务领域建模中形成概念业务数据模型即应用了面向数据的分解方法;
  • 面向并发的分解方法,在一些系统中具有多种并发任务的特点,那么我们可以将系统分解到不同的并发任务中(进程或线程),并描述并发任务的时序交互过程;
  • 面向事件的分解方法,当系统中需要处理大量的事件,而且往往事件会触发复杂的状态转换关系,这时系统就要考虑面向事件的分解方法,并内在状态转换关系进行清晰的描述;
  • 面向对象的分解方法,是一种通用的分析设计范式,是基于系统中抽象的对象元素在不同抽象层次上分解的系统的方法。
架构的描述方法
  • 分解视图 Decomposition View
  • 依赖视图 Dependencies View
  • 泛化视图 Generalization View
  • 执行视图 Execution View
  • 实现视图 Implementation View
  • 部署视图 Deployment View
  • 工作任务分配视图 Workassignment View

mvc 和 mvvm

主要区别在于:MVC 中,用户对于 M 的操作是通过 C 传递的,然后 C 将改变传给 V ,并且 M 将在发生变化时通知 V ,然后 V 通过 C 获取变化;在 MVVM 中,用户直接与 V 交互,通过 VM 将变化传递给 M ,然后 M 改变之后通过 VM 将数据传递给 V ,从而实现解耦。另一个区别是,当 M 的数据需要进行解析后 V 才能使用时,C 若承担解析的任务,就会变得很臃肿;在 MVVM 中,VM 层承担了数据解析的工作,这时 C 就只需要持有 VM ,而不需要直接持有 M 了,从而完成了数据的解耦。

五、软件危机和软件过程

没有银弹的含义

在10年内无法找到解决软件危机的杀手锏(银弹)。
软件中的根本困难,即软件概念结构(conceptual structure)的复杂性,无法达成软件概念的完整性
和一致性,自然无法从根本上解决软件危机带来的困境。

软件的生命周期

分为分析、设计、实现、交付和维护五个阶段。

  • 分析阶段的任务是需求分析和定义,分析阶段一般会在深入理解业务的情况下,形成业务概念原型。
  • 设计阶段分为软件架构设计和软件详细设计。前者一般和分析阶段联系紧密,一般合称为“分析与设计”;后者一般和实现阶段联系紧密,一般合称为“设计与实现”。
  • 实现阶段分为编码和测试,其中测试又涉及到单元测试、集成测试、系统测试等。
  • 交付阶段主要是部署、交付测试和用户培训等。
  • 维护阶段一般是软件生命周期中持续时间最长的一个阶段,而且在维护阶段很可能会形成单独的项目,从而经历分析、设计、实现、交付几个阶段,最终又合并进维护阶段。

软件过程

软件过程又分为描述性的(descriptive)过程和说明性的(prescriptive)过程。

  • 描述性的过程试图客观陈述在软件开发过程中实际发生什么。
  • 说明性的过程试图主观陈述在软件开发过程中应该会发生什么。

采用不同的过程模型时应该能反映出要达到的过程目标,比如构建高质量软件、早发现缺陷、满足
预算和日程约束等。不同的模型适用于不同的情况,我们常见的过程模型,比如瀑布模型、V模
型、原型化模型等都有它们所能达到的过程目标和适用的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值