从需求分析到软件设计
需求分析就是需求分析师对用户期望的软件行为进行表述,并进一步用对象或实体的状态、属性和行为来定义需求。
需求分析相关人员:客户 买主 使用者 领域专家 市场研究人员 律师和审计员 软件工程师和其他技术专家
获取需求的主要方法:找stake holder、找现有文档、观察现行系统、采访使用者、领域特有技术、找现有和潜在使用者头脑风暴
对象 属性 继承 聚合 关联
业务领域建模是开发团队获取业务领域知识,一般包括收集业务领域相关信息、执行团队头脑风暴、对业务领域相关的知识概念惊醒分类,最后用UML类图讲业务领域知识图形化展示。
瀑布模型 统一过程(用例驱动,架构中心,增量,迭代) 敏捷统一过程
敏捷统一过程的四个关键步骤:
第一,确定需求;
第二,通过用例的方式来满足这些需求;
第三,分配这些用例到各增量阶段;
第四,具体完成各增量阶段所计划的任务。
显然,第一到第三步主要是计划阶段的工作,第四步是接下来要进一步详述的增量阶段的工作。
敏捷统一过程
-
计划阶段
首先明确项目的动机、业务上的实际需求,以及对项目动机和业务需求可供替代选择的多种可能性;
然后充分调研获取需求并明确定义需求规格;
在明确需求规格的基础上进行项目的可行性研究;
如果项目可行,接下来接着进行用例建模并给出用例图;
同时明确需求和用例之间的可跟踪矩阵;从而形成项目的概念模型草案;
以及项目可能的日程安排、需要的资源以及大致的预算范围。
-
增量阶段
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JIe7Shaq-1688828464393)(%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.assets/敏捷统一过程增量阶段的工作流程.png)]
-
用例建模(Use case modeling)
-
业务领域建模(Domain modeling)
-
对象交互建模(Object Interaction modeling)
在扩展用例的基础上完成如下步骤:
- 第一步,在扩展用例中右侧一列中找出关键步骤(nontrivial steps)。关键步骤是那些需要在背后进行业务过程处理的步骤,而不是仅仅在表现层(presentation layer, i.e., the Graphical User Interface or GUI)与参与者进行用户接口层面交互的琐碎步骤。
- 第二步,对于每一个关键步骤,从关键步骤在扩展用例两列表格中的左侧作为开始,完成剧情描述(scenario),描述一步一步的对象交互过程,直到执行完该关键步骤。
- 第三步,如果需要的话,将剧情描述(scenario)进一步转换成剧情描述表(scenario table)。
- 第四步,将剧情描述(scenario)或剧情描述表(scenario table)转换成序列图。
- 情形一:主体(Subject)是一个参与者(Actor)
- 情形二:主体(Subject)是一个对象(Object)
- 情形三:主体(Subject)需要接收返回值的情形
- 情形四:主体(Subject)和主体行为的作用对象(object acted upon)是同一个对象的情形
对象交互建模的四个基本步骤以某个用例的扩展用例为输入,中间借助业务领域知识及业务领域建模中的相关对象、属性等,最终产出结果为序列图。
-
形成设计类图(design class diagram)
- Identify all classes used in each of the sequence diagrams and put them down in the DCD
- Identify methods belonging to each class and fill them in the DCD
- Identify and fill in attributes from sequence diagrams and domain model
- Identify and fill in relationships from sequence diagram and domain model
-
软件的编码实现和软件应用部署;
-
形成软件设计方案的基本方法:
- 分析是分解大问题变成易于理解的小问题。比如用例建模是将错综复杂的需求分解成一个一个的用例。在分析的过程中除了“分而治之”的切分分解的方法外,抽象方法的运用是一个关键。
- 综合是将一个个小问题的解决方案组合起来构建软件的整体解决方案。我们对每一个用例的关键步骤进行对象交互建模逐步形成了用例对应的解决方案,如何将多个用例的小解决方案组合起来构建软件整体设计方案?这在软件设计中是一个非常有挑战性的问题,一般我们通过参考已有的软件设计模式提供一个思路从而综合出一个软件整体解决方案。
工程化编程实战——代码中的软件工程
编写高质量代码的基本方法
-
通过控制结构简化代码
-
通过数据结构简化代码
-
一定要有错误处理
参数处理的基本原则:Debug版本中所有的参数都要验证是否正确;Release版本中从外部(用户或别的模块)传递进来的参数要验证正确性。肯定如何时用断言;可能发生时用错误处理。
-
性能优先策略背后隐藏的代价
-
拒绝修修补补,要不断重构代码
-
极限编程中不同的两类参与者的合作
- customers: who define the features using stories, describe detailed tests and assign priorities
- programmers: who implement the stories
-
结对编程中同类参与者的合作
- The driver or pilot: controlling the computer and writing the code
- The navigator: reviewing the driver’s code and providing feedback
可重用软件设计,消费者和生产者是为了实现代码重用,在不同时机需要注意的点
-
消费者重用是指软件开发者在项目中重用已有的一些软件模块代码,以加快项目工作进度。
软件开发者在重用已有的软件模块代码时一般会重点考虑如下四个关键因素:
- 该软件模块是否能满足项目所要求的功能;
- 采用该软件模块代码是否比从头构建一个需要更少的工作量,包括构建软件模块和集成软件模块等相关的工作;
- 该软件模块是否有完善的文档说明;
- 该软件模块是否有完整的测试及修订记录;
如上四个关键因素需要按照顺序依次评估。
-
我们清楚了消费者重用时考虑的因素,那么生产者在进行可重用软件设计时需要重点考虑的因素也就清楚了,但是除此之外还有一些事项在进行可重用软件设计时牢记在心,我们简要列举如下:
- 通用的模块才有更多重用的机会;
- 给软件模块设计通用的接口,并对接口进行清晰完善的定义描述;
- 记录下发现的缺陷及修订缺陷的情况;使用清晰一致的命名规则;
- 对用到的数据结构和算法要给出清晰的文档描述;
- 与外部的参数传递及错误处理部分要单独存放易于修改;
微服务接口
-
微服务接口一般使用RESTful API来定义接口。RESTful API是目前最流行的一种互联网软件接口定义方式。它结构清晰、符合标准、易于理解、扩展方便,得到了越来越多网站的采用。
-
在模块化思想的指导下目前主要有两种软件架构模式,即传统单体集中式(Monolithic)架构与微服务(Microservice)架构。传统单体集中式架构是相对于新型的微服务架构而言的
-
微服务这个概念是2012年出现的,作为加快Web和移动应用程序(App)开发效率的一种方法提出,2014年开始受到各方的关注,而2015年,可以说是微服务的元年得到了广泛的关注。
-
微服务:
- 由一系列独立的微服务共同组成软件系统的一种架构模式;
- 每个微服务单独部署,跑在自己的进程中,也就是说每个微服务可以有一个自己独立的运行环境和软件堆栈;
- 每个微服务为独立的业务功能开发,一般每个微服务应分解到最小可变产品(MVP),达到功能内聚的理想状态。微服务一般通过RESTful API接口方式进行封装;
- 系统中的各微服务是分布式管理的,各微服务之间非常强调隔离性,互相之间无耦合或者极为松散的耦合,系统通过前端应用或API网关来聚合各微服务完成整体系统的业务功能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ziwwvKUS-1688828464394)(%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.assets/传统单体集中式架构.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGF5q82C-1688828464395)(%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.assets/微服务架构.png)]
传统单体集中式架构是适应大型机、小型机单体服务器环境的软件架构模式;微服务架构则是为了适应PC服务器的大规模集群及基于虚拟化技术和分布式计算的云计算环境的架构模式。
-
RESTful API
- REpresentational State Transfer,表现层状态转化,有表现层就有背后的信息实体,信息实体就是URI代表的资源,也可以是一种服务,状态转化就是通过HTTP协议里定义的四个表示操作方式的动词:
- GET用来获取资源;
- POST用来新建资源(也可以用于更新资源);
- PUT用来更新资源;
- DELETE用来删除资源。
- REpresentational State Transfer,表现层状态转化,有表现层就有背后的信息实体,信息实体就是URI代表的资源,也可以是一种服务,状态转化就是通过HTTP协议里定义的四个表示操作方式的动词:
接口与耦合度之间的关系
-
公共耦合
当软件模块之间共享数据区或变量名的软件模块之间即是公共耦合,显然两个软件模块之间的接口定义不是通过显式的调用方式,而是隐式的共享了共享了数据区或变量名。
-
数据耦合
在软件模块之间仅通过显式的调用传递基本数据类型即为数据耦合。
-
标记耦合
在软件模块之间仅通过显式的调用传递复杂的数据结构(结构化数据)即为标记耦合,这时数据的结构成为调用双方软件模块隐含的规格约定,因此耦合度要比数据耦合高。但相比公共耦合没有经过显式的调用传递数据的方式耦合度要低。
可重入(reentrant)函数可以由多于一个任务并发使用,而不必担心数据错误。相反,不可重入(non-reentrant)函数不能由超过一个任务所共享,除非能确保函数的互斥(或者使用信号量,或者在代码的关键部分禁用中断)。可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据。可重入函数要么使用局部变量,要么在使用全局变量时保护自己的数据。
可重入函数的基本要求
- 不为连续的调用持有静态数据;
- 不返回指向静态数据的指针;
- 所有数据都由函数的调用者提供;
- 使用局部变量,或者通过制作全局数据的局部变量拷贝来保护全局数据;
- 使用静态数据或全局变量时做周密的并行时序分析,通过临界区互斥避免临界区冲突;
- 绝不调用任何不可重入函数。
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行读写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
可重入的函数不一定是线程安全的;可重入的函数在多个线程中并发使用时是线程安全的,但不同的可重入函数(共享全局变量及静态变量)在多个线程中并发使用时会有线程安全问题; 不可重入的函数一定不是线程安全的。
构建软件产品
驱动代码(Driver)是调用或触发一个特定软件模块执行的测试程序,一般也称为测试驱动,它通过传递一些测试用例(Test Case)来模拟该软件模块的执行上下文环境。
桩代码(Stub)是一种模拟缺失的软件模块的特殊程序,它的主要目的是为了让依赖它的上层软件模块能正常测试执行,一般也称为测试桩。
软件工程-码农的自我修养
软件科学基础概论
指令和操作数-变量-控制结构-函数、函数调用框架-对象-对象继承和组合,多态、回调函数、闭包、异步调用、匿名函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VIgTkOUQ-1688828464395)(%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.assets/image-20230708110208725.png)]
从低地址到高地址分别内存区分别为代码段、已初始化数据段、未初始化数据段(BSS)、堆、栈和命令行参数和环境变量
C语言中:
- 全局常量(const)、字符串常量、函数以及编译时可决定的某些东西一般存储在代码段(text);
- 初始化的全局变量、初始化的静态变量(包括全局的和局部的)存储在已初始化数据段;
- 未初始化的全局变量、未初始化的静态变量(包括全局的和局部的)存储在未初始化数据段(BSS);
- 动态内存分配(malloc、new等)存储在堆(heap)中;
- 局部变量(初始化以及未初始化的,但不包含静态变量)、局部常量(const)存储在栈(stack)中;
- 命令行参数和环境变量存储在与栈底紧挨着的位置。
指令(instruction)是由 CPU 加载和执行的软件基本单元。一条指令有四个组成部分:标号、指令助记符、操作数、注释,其中标号和注释是辅助性的,不是指令的核心要素。一般指令可以表述为指令码+操作数。
指令码可以是二进制的机器指令编码,也可以是八进制的编码,程序员更喜欢用汇编语言指令助记符,如 mov、add 和 sub,给出了指令执行操作的线索。
操作数有 3 种基本类型:立即数。用数字文本表示的数值;寄存器操作数。使用 CPU 内已命名的寄存器;内存操作数。引用内存位置。
回调函数是一个面向过程的概念,是代码执行过程的一种特殊流程。回调函数就是一个通过函数指针调用的函数。把函数的指针(地址)作为参数传递给另一个函数,当这个指针调用其所指向的函数时,就称这是回调函数。回调函数不是该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
闭包是变量作用域的一种特殊情形,一般用在将函数作为返回值时,该函数执行所需的上下文环境也作为返回的函数对象的一部分,这样该函数对象就是一个闭包。更严谨的定义是,函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在JavaScript中,每当函数被创建,就会在函数生成时生成闭包。
匿名函数就是lambda
软件的复杂性和软件易变性这两个本质属性结合起来,使得我们在抽象的基础上建立逻辑模型的努力,永远达不到终点,难以达成软件概念上的完整性和一致性。因为当我们付出极大的努力为复杂的软件建立起概念模型时,与此同时需求或环境已经发生了些许变化,或者发现建立概念模型的抽象有些许偏差,结果永远追不上那个完整的、一致的软件概念模型。
类模式/对象模式
创建型模式/结构型模式/行为型模式
设计模式 | 例子 | |
---|---|---|
单例模式Singleton | 数据库实例 | |
原型模式Prototype | ||
建造者模式Builder | 复杂对象各部分分别创建 | |
代理模式Proxy | ||
适配器模式Adapter | ||
装饰器模式Decorator | ||
外观模式Facade | 为复杂的子系统提供一个一致的接口 | |
享元模式Flyweight | 线程池、固定分配存储空间的消息队列 | |
策略模式Strategy | ||
命令模式Command | ||
模板方法TemplateMethod | 定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。模版方法是继承和重载机制的应用,属于类模式。 | |
职责链模式Chain of Responsibility | ||
中介者模式Mediator | C是M和V的中介者 | 简化复杂的交互关系 |
观察者模式Observer/发布-订阅模式 |
设计原则 | |
---|---|
开闭原则 | |
依赖倒置原则 | |
单一职责原则 | |
迪米特法则 | Talk only to your immediate friends and not to strangers |
合成复用原则 | 在软件复用时,要尽量先使用组合或者聚合关系来实现,其次才考虑使用继承关系来实现。如果要使用继承关系,则必须严格遵循Liskov替换原则。 |
软件架构 | |
---|---|
三层架构 | 界面层-业务逻辑层-数据访问层 |
MVC架构 | 控制器创建模型;控制器创建一个或多个视图,并将它们与模型相关联;控制器负责改变模型的状态;当模型的状态发生改变时,模型会通知与之相关的视图进行更新。可以看到这与抽象简化的MVC设计模式已经有了明显的区别,变得更为复杂,但这与实际软件结构相比还是极其简化的模型,实际情况可能会有更多合理的和不合理的复杂联系,要保持软件结构在概念上的完整性极为困难。 |
MVVM | Model-View-ViewModel 随着前端页面越来越复杂,用户对于交互性要求也越来越高,jQuery是远远不够的,于是MVVM被引入到Javascript前端开发中。 |
两种不同层级的软件架构复用方法:克隆、重构
分解的常见方法
- 面向特征的分解方法,根据数量众多的某种系统显著特征在不同抽象层次上划分模块的方法;
- 面向数据的分解方法,在业务领域建模中形成概念业务数据模型即应用了面向数据的分解方法;
- 面向并发的分解方法,在一些系统中具有多种并发任务的特点,那么我们可以将系统分解到不同的并发任务中(进程或线程),并描述并发任务的时序交互过程;
- 面向事件的分解方法,当系统中需要处理大量的事件,而且往往事件会触发复杂的状态转换关系,这时系统就要考虑面向事件的分解方法,并内在状态转换关系进行清晰的描述;
- 面向对象的分解方法,是一种通用的分析设计范式,是基于系统中抽象的对象元素在不同抽象层次上分解的系统的方法。
软件架构风格与策略 | |
---|---|
管道-过滤器 | 编译器,面相数据流 |
客户-服务器 | |
P2P | |
发布-订阅 | |
CRUD Create Read Update Delete | 各种信息系统 |
层次化 | OSI |
软件架构的描述方法 | |
---|---|
分解视图 Decomposition View | 子系统 包 类 组件 库 软件模块 软件单元 |
依赖视图 Dependencies View | |
泛化视图 Generalization View | |
执行视图 Execution View | 流程图 时序图 组件 |
实现视图 Implementation View | 软件项目的源文件目录树 |
部署视图 Deployment View | |
工作任务分配视图 Work-assignment View |
几种重要的软件质量属性
易于修改维护(Modifiability)
良好的性能表现(Performance)
安全性(Security)
可靠性(Reliability)
健壮性(Robustness)
易用性(Usability)
商业目标(Business goals)
软件危机和软件过程
瀑布模型[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B8GkikPn-1688828464396)(%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.assets/image-20230708222608769.png)]
原型化的瀑布模型[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ajKwgjMw-1688828464397)(%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.assets/image-20230708222603777.png)]
V模型[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J9DmAqbe-1688828464397)(%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.assets/image-20230708222555531.png)]
分阶段的增量和迭代开发[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EgXP81aR-1688828464398)(%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.assets/image-20230708222702552.png)]
螺旋模型将每一次迭代过程分为四个主要阶段
- Plan
- Determine goals, alternatives and constraints
- Evaluate alternatives and risks
- Develop and test
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zbqju0IS-1688828464398)(%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.assets/image-20230708222747732.png)]
个人软件过程PSP(Personal Software Process)和团队软件过程TSP(Team Software Process)是Watts S.Humphrey(1927—2010)继软件成熟度模型CMM之后推出的两个软件过程模型。CMM已经成为事实上的软件过程工业标准。但是CMM虽然提供了一个有力的软件过程改进框架,却只告诉我们"应该做什么",而没有告诉我们"应该怎样做",PSP和TSP通过具体知识和技能弥补这个欠缺。
软件项目中大多数软件模块是由一个人进行独立开发和维护的,一般来说一个人独立进行开发和维护软件模块时大致会经历如下过程:
- 了解当前情况和需要解决的问题
- 找出解决方案
- 估算需要完成哪些工作
- 与客户或利益相关方沟通建议方案(proposal)
- 开始行动完成工作
- 对产出结果的质量负责
PSP0
- 计划阶段
- 项目评估
- 开发阶段
- 设计
- 编码
- 测试
- 开发完成后进行总结分析
PSP0.1
- 计划阶段
- 项目评估
- 开发阶段
- 编码标准规范
- 设计
- 编码
- 测试
- 程序规模度量
- 开发完成后进行总结分析
- 过程改进计划
PSP1
- 计划阶段
- 项目评估
- 开发阶段
- 编码标准规范
- 设计
- 编码
- 测试
- 项目测试报告
- 程序规模度量
- 开发完成后进行总结分析
- 过程改进计划
PSP1.1
- 计划阶段
- 项目评估
- 开发阶段
- 编码标准规范
- 设计
- 编码
- 测试
- 统计记录各项工作用了多少时间
- 项目测试报告
- 程序规模度量
- 开发完成后进行总结分析
- 过程改进计划
PSP2
- 计划阶段
- 项目评估
- 开发阶段
- 编码标准规范
- 设计
- 设计评审
- 编码
- 代码评审
- 测试
- 统计记录各项工作用了多少时间
- 项目测试报告
- 程序规模度量
- 开发完成后进行总结分析
- 过程改进计划
PSP2.1
- 计划阶段
- 项目评估
- 开发阶段
- 分析
- 设计规格
- 编码标准规范
- 设计
- 设计评审
- 编码
- 代码评审
- 测试
- 统计记录各项工作用了多少时间
- 项目测试报告
- 程序规模度量
- 开发完成后进行总结分析
- 过程改进计划
PSP3的重点是个体循环过程,目标是把个体开发小规模程序所能达到的生产效率和生产质量,扩展到大型程序中。主要是采用螺旋式上升的方法,即增量和迭代开发方法,首先把大型程序分解成小的模块,然后对每个模块按照PSP2.1所描述的过程进行开发,最后把这些模块逐步集成为完整的软件产品。
应用PSP3开发大型软件系统,必须采用增量式开发方法,并要求每一个增量都是高质量的。在这样的前提下,在新一轮个体循环过程中,可以采用回归测试的方法,重点考察新的增量是否符合要求。因此,要求在PSP2中进行严格的设计评审和代码评审,并在PSP2.1中努力遵循设计规格。
软件团队的组织
Highly structured | Loosely structured |
---|---|
High certainty | Uncertainty |
Repetition | New techniques or technology |
Large projects | Small projects |
哪些常见的团队问题容易导致项目失败?
- 缺乏有效的领导和管理;
- 不能做出妥协、安排或不善于合作;
- 缺少参与;
- 拖拉与缺乏信心;
- 质量低劣;
- 功能多余;
- 无效的组员互评;
如何建设高效团队?
- 建设具有凝聚力的团队
- 设定有挑战性的目标
- 反馈
- 共同遵守的工作流程和框架
如何开始一个团队项目?
- 设定团队目标
- 设定团队成员目标,包括各个角色的目标
- 团队领导角色
- 开发经理角色
- 计划经理角色
- 质量和过程经理角色
- 支持经理角色
- 项目筹备及第一次项目会议
团队项目的基本策略
- 计划先行,也就是做出承诺之前先计划
- 完成概念设计
- 选择开发策略
- 完成初步规模估算
- 完成初步时间估算
- 评估风险
- 建立策略文档
- 制定配置管理计划
开发计划
- 制定计划
- 实现计划
- 对照计划跟踪进展
- 质量管理
定义需求
- 软件需求规格说明书
- 需求任务分配
- 系统测试计划
- 需求变更和追溯管理
与团队一起设计
- 利用所有团队成员的才智
- 产生精确的设计
- 复用性设计
- 易用性设计
- 可测试性设计
- 设计规格说明书
- 设计评审和审查
产品实现
- 编码标准
- 缺陷预防
- 详细设计与设计评审
- 编码及代码评审
- 单元测试
集成与系统测试
- 构建和集成策略
- 测试计划
- 跟踪缺陷
- 系统测试
- 回归测试
结项总结
- 过程改进建议
在Scrum中将团队角色分为:
- 项目经理(Scrum Master),一般也称为project manager,负责项目的开发过程。
- 产品经理(Product Owner),代表业务需求方及利益相关方,比如定义产品功能和特性。
- 团队(Team),是一个跨职能小组进行实际分析、设计、实现、测试等工作。
DevOps(Development和Operations的组合)是一组过程、方法与系统的统称,用于促进软件开发、技术运营和质量保障(QA)部门之间的沟通、协作与整合。它的出现是由于软件行业日益清晰地认识到:为了按时交付软件产品和服务,开发和运营工作必须紧密合作。
可以把DevOps看作开发(软件工程)、技术运营和质量保障(QA)三者的交集。
传统的软件组织将开发、IT运营和质量保障设为各自分离的部门。DevOps是一套针对这几个部门间沟通与协作问题的流程、方法和系统。
学术界和软件工程实践者并没有对DevOps给出统一的定义,但是从学术的角度看,计算机科学研究人员建议将DevOps定义为“一套旨在缩短从提交变更到变更后的系统投入正常生产之间的时间,同时确保产品高质量的实践方法”
当从企业业务周期的角度回顾整个开发到运维的过程,开发和运维往往分别按照不同的节奏进行,导致产品部署的时间间隔过长使得一个开发团队的敏捷工作变成了一直试图避免的瀑布生命周期。这时无论开发团队有多么敏捷,从总体上改变企业业务缓慢和迟钝的表现都是极其困难的。
因此可以将DevOps看成是敏捷方法从技术开发领域扩展到业务运维领域,也就是实现业务上全周期的敏捷性,在业务运营者作出决策、开发者进行响应和IT运维上线部署之间能够紧密互动和快速反馈,从而形成与业务需求始终努力保持一致的持续改进过程。
DevOps使得敏捷方法的优势可以体现在整个企业业务组织机构层面。通过实现反应灵敏且稳定部署持续交付的业务运维,使其能够与开发过程的创新保持同步,DevOps可以做到整个业务实现过程的敏捷性。
精益原则是衍生自丰田生产方式的一种管理哲学。精益生产(Lean Production)是美国麻省理工学院的专家对日本丰田准时化生产JIT(Just In Time)生产方式的赞誉称呼。精益生产是在需要的时候、按需要的量、生产所需的产品。精益生产的主要特点:
- 追求零库存。精益生产是一种追求无库存生产,或使库存达到极小的生产系统,为此而开发了包括“看板”在内的一系列具体方式,并逐渐形成了一套独具特色的生产经营体系。
- 追求快速反应,即快速应对市场的变化。
- 把企业的内部活动和外部的市场(顾客)需求和谐地统一于企业的发展目标。
- 强调人力资源的重要性,把员工的智慧和创造力视为企业的宝贵财富和未来发展的原动力。
最小可行产品(MVP,Minimum Viable Product),又称为最小功能集(Minimal Feature Set),把产品最核心的功能用最小的成本实现出来(或者描绘出来),然后快速征求用户意见获得反馈进行改进优化。
中科大软件学院高软期末试题回忆版
-
高质量需求的特点
- 需求可测试,提出一个solution可以判断它是否满足需求,可量化的需求容易设定标准,主观质量需求难以设定标准。副词动词加上定量描述,代词替换成实体名字,确保每个名词只在一处定义
- 解决冲突,不同stakeholder有不同的需求,做需求需要解决冲突,需要对各种需求排essential、desirable、optional三个优先级
- 需求的特性:正确 一致 清晰 完整 可行 相关 可测试 可追溯
-
有哪些需求类型
- 功能需求:根据所需的活动描述所需的行为
- 质量需求或非功能需求:描述软件必须具备的一些质量特性
- 设计约束:设计决策,例如选择平台或接口组件
- 过程约束:对可用于构建系统的技术或资源的限制
-
需求分析的两类基本方法
- 原型化方法,可以很好地整理出用户接口方式,比如界面布局和交互操作过程
- 建模的方法,可以快速给出有关事件活动同步约束的问题,能够在逻辑上形成模型来整顿繁杂的需求细节
-
用例满足的四个必要条件
- 是一个业务过程
- 由某个参与者触发开始
- 显式或隐式地终止于某个参与者
- 为某个完成者完成了有用的业务工作
-
统一过程的核心要义是什么
用例驱动、以架构为中心、增量和迭代的过程
以架构为中心:保持软件架构相对稳定,减小软件架构层面的重构造成的混乱
增量:模块的逐渐增加
迭代:模块的逐渐增强
-
模块化的基本原理
模块化是在软件系统设计时保持系统内部各部分相对独立,以便每个部分可以被独立地进行设计和开发。这个做法背后的基本原理是”关注点的分离“,分解成易解决的小问题,降低思考负担。
-
本地化外部接口是什么含义
使用本地化外部接口,本质上是一种设计模式,代理模式,即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性,能够有效降低模块与外部的耦合度
-
接口的5个基本要素
- 目的
- 前置条件
- 协议规范(HTTP, png, json)
- 后置条件
- 质量属性(响应时间)
-
通用接口定义的基本方法
int a = 1; int b = 2; int c = 3; int sum() { return a + b + c; }
参数化上下文
int sum(int a, int b, int c);
移除前置条件
int sum(int numbers[], int len);
简化后置条件
int sum(int numbers[]); //如果编程语言支持获得数组长度
-
依赖倒置原则的含义及其应用价值
含义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象
应用价值:在软件设计中,细节具有多变性,而抽象层则相对稳定,因此,以抽象为基础搭建起来的架构比以西结为基础搭建起来的架构要稳定得多。
依赖倒置原则在模块化设计中降低模块之间的耦合度和加强模块的抽象封装提高模块的内聚度上具有普遍的指导意义
-
MVC架构为什么更灵活以及MVVM架构为什么更智能(10分)
MVVM即 Model-View-ViewModel,最早由微软提出来,借鉴了桌面应用程序的MVC模式的思想,是一种针对WPF、Silverlight、Windows Phone的设计模式,目前广泛应用于复杂的Javacript前端项目中。随着前端页面越来越复杂,用户对于交互性要求也越来越高,jQuery是远远不够的,于是MVVM被引入到Javascript前端开发中。
在前端页面中,把Model用纯JavaScript对象表示,View负责显示,两者做到了最大限度的分离。把Model和View关联起来的就是ViewModel。ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model。以比较流行的Vue.js框架为例,MVVM架构示意图如下:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q0HrRtVd-1688828464399)(%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.assets/MVVM架构示意图.png)]
MVC架构允许更多的自定义:MVC架构将应用程序分为三个独立的组件(Model、View、Controller),这种划分使得开发人员可以根据需求自由地设计和组织代码。每个组件都可以独立地开发、测试和维护,因此可以根据实际情况进行更灵活的定制。
MVVM架构引入了数据绑定的概念,它允许开发人员将数据模型(Model)与用户界面(View)进行绑定,从而实现数据的自动更新。这种机制可以减少代码的编写量,并确保界面与数据的同步性。
-
执行视图、部署视图、分解视图
软件架构模型是通过一组关键视图来描述的,同一个软件架构,由于选取的视角(Perspective)和抽象层次不同可以得到不同的视图,这样一组关键视图搭配起来可以完整地描述一个逻辑自洽的软件架构模型。一般来说,我们常用的几种视图有分解视图、依赖视图、泛化视图、执行视图、实现视图、部署视图和工作任务分配视图。
- 分解是构建软件架构模型的关键步骤,分解视图也是描述软件架构模型的关键视图,一般分解视图呈现为较为明晰的分解结构(breakdown structure)特点。分解视图用软件模块勾划出系统结构,往往会通过不同抽象层级的软件模块形成层次化的结构。由于前述分解方法中已经明确呈现出了分解视图的特征,我们这里简要了解一下分解视图中常见的软件模块术语。
- 子系统(Subsystem),一个系统可能有一些列子系统组成;
- 包(Package),子系统又由包组成;
- 类(Class),包又由类组成;
- 组件(Component),一般用来表示一个运行时的单元;
- 库(Library)是具有明确定义的接口的共享软件代码的集合,可以是代码库,也可以是由代码库编译打包后的静态库,还可以构建成动态链接库;
- 软件模块(Module)用来指软件代码的结构化单元,模块化(modular)是在软件架构中各部分都被明确定义的接口所描述时使用,也就是可以明确无误地指定各部分的外部可见行为。
- 软件单元(Software unit)是在不明确该部分的类型时使用。
- 依赖视图展现了软件模块之间的依赖关系。比如一个软件模块A调用了另一个软件模块B,那么我们说软件模块A直接依赖软件模块B。如果一个软件模块依赖另一个软件模块产生的数据,那么这两个软件模块也具有一定的依赖关系。
- 泛化视图展现了软件模块之间的一般化或具体化的关系,典型的例子就是面向对象分析和设计方法中类之间的继承关系。值得注意的是,采用对象组合替代继承关系,并不会改变类之间的泛化特征。因此泛化是指软件模块之间的一般化或具体化的关系,不能局限于继承概念的应用。
- 执行视图展示了系统运行时的时序结构特点,比如流程图、时序图等。执行视图中的每一个执行实体,一般称为组件(Component),都是不同于其他组件的执行实体。如果有相同或相似的执行实体那么就把它们合并成一个。执行实体可以最终分解到软件的基本元素和软件的基本结构,因而与软件代码具有比较直接的映射关系。在设计与实现过程中,我们一般将执行视图转换为伪代码之后,再进一步转换为实现代码。
- 实现视图是描述软件架构与源文件之间的映射关系。比如软件架构的静态结构以包图或设计类图的方式来描述,但是这些包和类都是在哪些目录的哪些源文件中具体实现的呢?一般我们通过目录和源文件的命名来对应软件架构中的包、类等静态结构单元,这样典型的实现视图就可以由软件项目的源文件目录树来呈现。实现视图有助于码农在海量源代码文件中找到具体的某个软件单元的实现。实现视图与软件架构的静态结构之间映射关系越是对应的一致性高,越有利于软件的维护,因此实现视图是一种非常关键的架构视图。
- 部署视图是将执行实体和计算机资源建立映射关系。这里的执行实体的粒度要与所部署的计算机资源相匹配,比如以进程作为执行实体那么对应的计算机资源就是主机,这时应该描述进程对应主机所组成的网络拓扑结构,这样可以清晰地呈现进程间的网络通信和部署环境的网络结构特点。当然也可以用细粒度的执行实体对应处理器、存储器等。部署视图有助于设计人员分析一个设计的质量属性,比如软件处理网络高并发的能力、软件对处理器的计算需求等。
- 工作分配视图将系统分解成可独立完成的工作任务,以便分配给各项目团队和成员。工作分配视图有利于跟踪不同项目团队和成员的工作任务的进度,也有利于在个项目团队和成员之间合理地分配和调整项目资源,甚至在项目计划阶段工作分配视图对于进度规划、项目评估和经费预算都能起到有益的作用。
每个视图都是从不同的角度对软件架构进行描述和建模,比如从功能的角度、从代码结构的角度、从运行时结构的角度、从目录文件的角度,或者从项目团队组织结构的角度。软件架构代表了软件系统的整体设计结构,它应该是所有这些视图的集合。但我们不会将不同角度的这些视图整合起来,因为不便于阅读和更新。不过我们会有意识地将不同角度的视图之间的映射关系和重叠部分了然于胸,从而深刻理解软件架构内在的一致性和完整性,这就是系统概念原型。
- 分解是构建软件架构模型的关键步骤,分解视图也是描述软件架构模型的关键视图,一般分解视图呈现为较为明晰的分解结构(breakdown structure)特点。分解视图用软件模块勾划出系统结构,往往会通过不同抽象层级的软件模块形成层次化的结构。由于前述分解方法中已经明确呈现出了分解视图的特征,我们这里简要了解一下分解视图中常见的软件模块术语。
-
没有银弹的含义
在10年内无法找到解决软件危机的杀手锏(银弹)。
软件中的根本困难,即软件概念结构(conceptual structure)的复杂性,无法达成软件概念的完整性和一致性,自然无法从根本上解决软件危机带来的困境。
-
简述v模型
V模型也是在瀑布模型基础上发展出来的,我们发现单元测试、集成测试和系统测试是为了在不同层面验证设计,而交付测试则是确认需求是否得到满足。 也就是瀑布模型中前后两端的过程活动具有内在的紧密联系,如果将模块化设计的思想拿到软件开发过程活动的组织中来, 可以发现通过将瀑布模型前后两端的过程活动结合起来,可以提高过程活动的内聚度,从而改善软件开发效率。 这就是V模型。V模型是开始一个特定过程活动和评估该特定过程的过程活动成对出现,从而便于软件开发过程的组织和管理。
-
团队强度和项目特点的关系
CMM/CMMI用于评价软件生产能力并帮助其改善软件质量的方法,成为了评估软件能力与成熟度的一套标准,它侧重于软件开发过程的管理及工程能力的提高与评估,是国际软件业的质量管理标准。
CMMI共有5个级别,代表软件团队能力成熟度的5个等级,数字越大,成熟度越高,高成熟度等级表示有比较强的软件综合开发能力。
CMMI一级,初始级。在初始级水平上,软件组织对项目的目标与要做的努力很清晰,项目的目标可以实现。但是由于任务的完成带有很大的偶然性,软件组织无法保证在实施同类项目时仍然能够完成任务。项目实施能否成功主要取决于实施人员。
CMMI二级,管理级。在管理级水平上,所有第一级的要求都已经达到,另外,软件组织在项目实施上能够遵守既定的计划与流程,有资源准备,权责到人,对项目相关的实施人员进行了相应的培训,对整个流程进行监测与控制,并联合上级单位对项目与流程进行审查。二级水平的软件组织对项目有一系列管理程序,避免了软件组织完成任务的偶然性,保证了软件组织实施项目的成功率。
CMMl三级,已定义级。在已定义级水平上,所有第二级的要求都已经达到,另外,软件组织能够根据自身的特殊情况及自己的标准流程,将这套管理体系与流程予以制度化。这样,软件组织不仅能够在同类项目上成功,也可以在其他项目上成功。科学管理成为软件组织的一种文化,成为软件组织的财富。
CMMI四级,量化管理级。在量化管理级水平上,所有第三级的要求都已经达到,另外,软件组织的项目管理实现了数字化。通过数字化技术来实现流程的稳定性,实现管理的精度,降低项目实施在质量上的波动。
CMMI五级,持续优化级。在持续优化级水平上,所有第四级的要求都已经达到,另外,软件组织能够充分利用信息资料,对软件组织在项目实施的过程中可能出现的问题予以预防。能够主动地改善流程,运用新技术,实现流程的优化。
由上述的5个级别可以看出,每一个级别都是更高一级的基石。要上高层台阶必须首先踏上所有下层的台阶。
CMM模型基于众多软件专家的实践经验,是组织进行软件过程改善和软件过程评估的一个有效的指导框架。CMMI更是为工业界和政府部门提供了一个集成的产品集,其主要目的是消除不同模型之间的不一致和重复,降低基于模型改善的成本。CMMI将以更加系统和一致的框架来指导组织改善软件过程,提高产品和服务的开发、获取和维护能力。CMM/CMMI不仅是一个模型,一个工具,它更代表了一种管理哲学在软件工业中的应用。
-
简述敏捷宣言的核心思想
-
个体和互动 高于 流程和工具
-
工作的软件 高于 详尽的文档
-
客户合作 高于 合同谈判
-
响应变化 高于 遵循计划
尽管右项有其价值,我们更重视左项的价值。
-
-
编程大题:写一个menu里面自定义查找结点的测试代码(20分)
期末复习资料.docx
-
VS Code快捷键
跨文件搜索(Ctrl+Shift+F)
-
文件操作
-
新建文件: Ctrl + N
-
打开文件: Ctrl + O
-
保存文件: Ctrl + S
-
另存为: Ctrl + Shift + S
-
关闭文件: Ctrl + W
-
关闭所有文件: Ctrl + K Ctrl + W
-
编辑操作
- 撤销: Ctrl + Z
- 重做: Ctrl + Shift + Z
- 替换: Ctrl + H
-
导航操作
- 跳转到定义: F12
- 跳转到声明: Ctrl + 左键
- 后退: Alt + 左箭头
- 前进: Alt + 右箭头
- 跳转到行: Ctrl + G
-
调试操作
- 启动调试: F5
- 停止调试: Shift + F5
- 单步执行: F10
- 单步跳过: F11
- 运行到光标: F9
-
终端操作
- 打开终端: Ctrl + `
- 清除终端: Ctrl + K
-
-
其他操作
- 命令面板: Ctrl + Shift + P
- 切换全屏模式: F11
- 切换侧边栏: Ctrl + B
- 切换资源管理器: Ctrl + Shift + E
- 命令面板: Ctrl + Shift + P
-
-
用例建模的基本步骤
用例的三个抽象层级:抽象用例(动名词短语) 高层用例(划定时间地点边界) 扩展用例(详细描述交互过程)
第一步,从需求表述中找出用例,往往是动名词短语表示的抽象用例;
第二步,描述用例开始和结束的状态,用TUCBW和TUCEW表示的高层用例;
第三步,对用例按照子系统或不同的方面进行分类,描述用例与用例、用例与参与者之间的上下文关系,并画出用例图;
第四步,进一步逐一分析用例与参与者的详细交互过程,完成一个两列的表格将参与者和待开发软件系统之间从用例开始到用例结束的所有交互步骤都列举出来扩展用例。
其中第一步到第三步是计划阶段,第四步是增量实现阶段。
-
准确提取用例的基本方法
第一步,从需求中寻找业务领域相关的动名词和动名词短语,比如做什么事、什么事情必须被完成,或者执行某任务等;
第二步,验证这些业务领域相关的动名词和动名词短语到底是不是用例。验证业务领域相关的动名词或动名词短语是不是用例的标准是满足四个必要条件:
-
必要条件一:它是不是一个业务过程?
-
必要条件二:它是不是由某个参与者触发开始?
-
必要条件三:它是不是显式地或隐式地终止于某个参与者?
-
必要条件四:它是不是为某个参与者完成了有用的业务工作?
如果以上四个必要条件都满足的话,那么该业务领域相关的动名词或动名词短语就是一个用例。
第三步:在需求中识别出参与者、系统或子系统。
-
参与者会触发某个用例开始,用例也会显式地或隐式地终止于某个参与者;
-
用例会属于系统或子系统。
-
-
git merge和git merge -no-ff的区别
git merge –no-ff 可以保存你之前的分支历史。能够更好的查看 merge历史,以及branch 状态。
git merge 则不会显示 feature,只保留单条分支记录。
-
正则表达式
-
性能优先策略带来的隐藏代价
传统上由于CPU计算资源和存储资源较为昂贵,在编写代码时往往更多地考虑最大限度地高效利用计算机资源,因此在编写代码的习惯上追求性能优先的策略。但是随着计算资源的硬件成本逐步降低,尤其是云计算技术的发展计算资源的价格大幅度下降,性能优先的策略背后隐藏的代价逐步显露。
cost to write the code faster。当软件工程师的人力成本远大于所消耗的计算资源成本时,提高代码编写的工作效率将更有价值;
cost to test the code。质量保证的人力成本和质量保证的成效也比所消耗的计算资源成本更有价值;
cost to understand the code。性能优先的策略往往会让代码很难理解,结果需要消耗更多的工时;
cost to modify the code。面向机器的代码修改起来更困难,可扩展性差,同样会消耗更多工时。
因此,我们在具体编程实现过程中已经不再需要考虑代码性能问题,将更多精力放在提高工作效率、质量保证、代码的可读性、可扩展性等方面,让性能问题在更高层的软件架构设计层面考虑更加合理有效。