开发模式

软件开发模式

ATDD:验收测试驱动开发

(Acceptance Test Driven Development)

通过单元测试用例来驱动功能代码的实现,团队需要定义出期望的质量标准和验收细则,以明确而且达成共识的验收测试计划(包含一系列测试场景)来驱动开发人员的TDD实践和测试人员的测试脚本开发。面向开发人员,强调如何实现系统以及如何检验。

什么是ATDD#

首先,ATDD不是一种测试方法论,而是一种开发方法论。

UTDD涉及的人员仅仅是开发人员,那么ATDD仅仅涉及测试人员吗?不是,产品、开发、测试都需要参与到ATDD中来。

在ATDD活动中团队需要就需求定义出期望的质量标准和验收细则,以明确而且达成共识的验收测试计划(包含一系列测试场景)来驱动产品的代码开发和测试脚本开发。

ATDD一定是基于测试自动化和持续集成的。

ATDD工具

  1. Fit
  1. Fitnesse
  1. Exactor
  1. TextTest
  1. jWebUnit中提供的夹具
Selenium
Robot Framework

Robot Framework(RF)是用于验收测试和验收测试驱动开发(ATDD)的自动化测试框架。 基于 Python 编写,但也可以在 Jython(Java)和 IronPython(.NET) 上运行,提供跨平台支持(Windows、Linux 或 MacOS )。

ATDD的基本流程#

和TDD的“红-绿-重构”类似,ATDD的流程也是类似的思路。

讨论澄清阶段

全组参与的针对需求和方案的讨论

大家产出对需求和方案共同的理解

通过明确验收测试方式澄清我们的实现方案

验收测试方式将被自动化

开发阶段

用明确具体的验收测试方式来指导开发工作

验收测试的自动化和特性的开发可以并行开展

全组成员对验收测试的自动化负责,而不仅仅是测试人员

最终,我们的产品实现能让所有的自动化测试通过

交付阶段

我们要保证之前迭代所有的自动化验收测试能在新交付上通过

给所有利益相关者演示我们的新特性

收集反馈,讨论改进

ATDD的好处#

ATDD自动化测试框架

DDD:领域驱动开发

(Domain Drive Design)

也就是领域驱动开发,DDD实际上也是建立在这个基础之上,因为它关注的是Service层的设计,着重于业务的实现,将分析和设计结合起来,不再使他们处于分裂的状态,建立一个具有业务伸缩性的模型。

概念

实体(Entity)

值对象(Value Object)

服务(Service)

聚合(Aggregate)

聚合根(Aggregate Root)

工厂(Factory)

仓储(Repository)

领域建模

实体、

值对象

服务

生命周期

工厂

仓储

软件系统架构风格

比较传统的常见的分层方式就是分三层:界面层、业务逻辑层以及数据访问层,各层之间会有数据传输对象(DTO)完成数据交互,以此隔离不同层内部的实现细节。领域驱动设计则将应用系统分为四层:用户界面层、应用层、领域层和基础设施层:

经典分层架构(N-Tier Architecture)

用户界面层

就是直接面向用户的前端应用。如果系统仅提供API,那么API这一层也属于用户界面层。

应用层

它主要负责协调下层的执行任务,并隔离领域层与用户界面层。它们不参与任何领域或者业务相关的操作,仅仅负责协调。最常见的一种实现就是在应用层引入事务处理,有时候甚至还会跨资源实现分布式事务

领域层

你的领域模型所涉及的所有对象都会出现在这一层,领域层对象需要尽量避免贫血模型,开发团队与领域专家一起完成领域层的设计与开发任务

基础设施层

所有与技术细节相关的基础设施组件都属于这一层,此外还有面向切面(Aspect-Oriented)的组件,比如异常处理模块、缓存模块、安全模块等等,也都属于基础设施层

事件驱动型架构(Event-Driven Architecture)
微服务架构(Microservices Architecture)

在微服务架构中,各应用服务之间互相独立,它们可以由不同团队采用异构的平台和技术,这些服务可以使用不同的数据存储系统,甚至可以是一个仅进行数据实时处理而不存储任何数据的计算服务,微服务实例之间可以以同步或者异步的方式进行通讯。

TDD(UTDD):测试驱动开发

(Test-Driven Development)

TDD核心可看做一个闭环:RED -> GREEN -> REFACTOR,即运行一个失败的测试 -> 让测试通过 -> 及时重构代码。

测试驱动开发是敏捷开发中的一项核心实践和技术,

也是一种设计方法论,TDD首先考虑使用需求(对象、功能、过程、接口等),主要是编写测试用例框架对功能的过程和接口进行设计,而测试框架可以持续进行验证。

TDD流程

写一个测试用例

运行测试

写刚好能让测试通过的实现

运行测试

识别坏味道,用手法修改代码

运行测试

TDD 的三条规则

除非是为了使一个失败的 unit test 通过,否则不允许修改任何产品代码

在一个单元测试中,只允许编写刚好能够导致失败的内容(编译错误也算失败)

只允许编写刚好能够使一个失败的 unit test 通过的产品代码

好的单元测试应该符合几条原则:

简单,只测试一个需求

符合 Given-When-Then 格式

速度快

包含断言

可以重复执行

TDD 编码方式

先分解任务,分离关注点(后面有演示)

列 Example,用实例化需求,澄清需求细节

写测试,只关注需求,程序的输入输出,不关心中间过程

写实现,不考虑别的需求,用最简单的方式满足当前这个小需求即可

重构,用手法消除代码里的坏味道

写完,手动测试一下,基本没什么问题,有问题补个用例,修复

转测试,小问题,补用例,修复

代码整洁且用例齐全,信心满满地提交

TDD(测试驱动开发)相关测试框架

XUnit:相应于各语言的测试框架

EasyMock:模拟接口或类行为

DBUnit:数据库测试

Spring-test:提供数据库集成测试

基于请求的web作测试

(1)Spring-mock:可以mock浏览器请求等

(2)JspTest:测试jsp页面

基于控件的web作测试

(1)WicketTester

(2)Apache Shale

Apache commons VFS:虚拟文件系统,对文件系统进行模拟

HttpUnit:http测试

Jemmy和Abbot:测试驱动开发Swing

H sqldb:内存数据库,模拟真实数据库

Dbdeploy:数据库结构的增量变动

GSBase:equals和hashcode测试

BeanInject:可以将测试替身强行赋给某个类的私有变量

JFCUnit:JFC类测试

ConTest:Java并发单元测试

XMLUnit:测试xml结构及内容

JUnitPerf:性能测试

测试驱动开发的基本过程

1) 明确当前要完成的功能。可以记录成一个 TODO 列表。 

2) 快速完成针对此功能的测试用例编写。 

3) 测试代码编译不通过。

4) 编写对应的功能代码。

5) 测试通过。 

6) 对代码进行重构,并保证测试通过。

7) 循环完成所有功能的开发。

测试驱动开发的原则

1)测试隔离。不同代码的测试应该相互隔离。对一块代码的测试只考虑此代码的测试,不要考虑其实现细节(比如它使用了其他类的边界条件)。

2)一顶帽子。开发人员开发过程中要做不同的工作,比如:编写测试代码、开发功能代码、对代码重构等。做不同的事,承担不同的角色。开发人员完成对应的工作时应该保持注意力集中在当前工作上,而不要过多的考虑其他方面的细节,保证头上只有一顶帽子。避免考虑无关细节过多,无谓地增加复杂度。

3)测试列表。需要测试的功能点很多。应该在任何阶段想添加功能需求问题时,把相关功能点加到测试列表中,然后继续手头工作。然后不断的完成对应的测试用例、功能代码、重构。一是避免疏漏,也避免干扰当前进行的工作。

4)测试驱动。这个比较核心。完成某个功能,某个类,首先编写测试代码,考虑其如何使用、如何测试。然后在对其进行设计、编码。

5)先写断言。测试代码编写时,应该首先编写对功能代码的判断用的断言语句,然后编写相应的辅助语句。

6)可测试性。功能代码设计、开发时应该具有较强的可测试性。其实遵循比较好的设计原则的代码都具备较好的测试性。比如比较高的内聚性,尽量依赖于接口等。

BDD:行为驱动开发

(Behavior Driven Development)

开发流程

可行性分析

需求分析

《软件需求规格说明书》SRS

1,需要明确项目的背景

  1. 本项目解决了客户的什么问题?
  1. 本项目涉及到什么人、什么单位?
  1. 本项目的目标是什么?
  1. 本项目的范围是怎样的?
  1. 本项目的成功标准是什么?

2,需求规格

功能性需求

功能需求主要说明了系统实际应做到什么。这是用户最直观也是最主要的需求,如系统的输入输出、系统能完成的功能以及其它相关处理等;

非功能性需求

非功能需求又称“约束”,它主要从各个角度对系统起约束和限制作用。如响应时间、存储效率、报表的规格和界面的样式等

领域需求

域需求的来源不是用户,而是系统应用的领域,其主要反映了该领域的基本问题。例如勤工俭学管理系统,其领域需求就涉及到诸如应聘合同书、酬金发放及劳工考核等相关内容,如果这些需求得不到满足,系统就无法正常运行。值得一提的是,领域需求可能是功能需求,也可能是非功能需求。

过程

可行性研究

它指明现有的软件、硬件技术能否实现用户对系统的要求,从业务角度来决定系统开发是否可行以及在预算范围内能否开发出来。可行性研究的结果是清楚的回答:该系统是否值得开发

需求导出和分析

这是一个通过对现有系统分析、与潜在客户讨论、进行任务分析等导出系统需求的过程,也可能需要开发一个或多个不同的系统原型,以帮助分析员了解所要描述的系统。

需求描述

需求描述就是把在分析活动中收集的信息通过分析整理之后以文档的形式确定下来。该文档中有两类需求:用户需求是从客户和最终用户角度对系统需求的抽象描述;系统需求是对系统要提供的功能的详尽描述。

需求有效性验证

主要是通过评审、验证等一系列活动来找出需求文档中的错漏并加以改正。

需求管理

需求管理需求管理是一种系统化方法,可用于获取、组织和记录系统需求并使用户和开发方在系统变更需求上始终保持一致

方法

功能分析方法

功能分析法功能分解法以系统提供的功能为中心来组织系统。首先定义各种功能, 然后把功能分解为子功能, 同时定义功能之间的接口。数据结构是根据功能/子功能的需要设计的。 其基本策略是以分析员的经验为依据, 确定新系统所期望的处理步骤或子步骤, 然后, 将问题空间映射到功能和子功能上。

数据流方法

数据流法也叫结构化分析, 其基本策略是研究问题域中数据如何流动以及在各个环节上进行何种处理, 从而发现数据流和加工。 问题域被映射为由数据流、加工以及文件、端点等成份构成的数据流图(DFD) , 并用数据字典对数据流和加工进行详细说明。这种方法的关键是动态跟踪数据流动。

信息建模方法

信息建模法的核心概念是实体和关系, 主要工具是语义数据模型(实体关系图) , 其基本策略是找出现实世界的对象, 然后用属性来描述对象, 增添对象与对象之间的关系, 定义父类与子类, 用父类型/子类型提炼属性的共性, 用关联对象关系作细化的描述, 最后进行规范化处理。 其实质是将问题空间直接映射成模型中的对象。

面向对象方法

面向对象分析 OOA(Object- Oriented Analysis) 的基本策略是通过信息隐藏将比较容易变化的元素隐藏起来, 分析员基于比较稳定的元素建立其思想和规格说明的总体结构。

面向对象分析的主要特性是加强了对问题域( Problem Domain) 和系统责任( System Responsibili-ties)的理解; 改进与分析有关的各类人员之间的交流; 对需求的变化具有较强的适应性; 支持软件复用

面向本体方法

需求管理需求管理是一种系统化方法,可用于获取、组织和记录系统需求并使用户和开发方在系统变更需求上始终保持一致

形式化方法

形式化方法, 广义上讲, 是应用数学的手段来设计、 模拟和分析, 得到像数学公式那样精确的表示。从狭义上讲, 就是使用一种形式语言进行语言公式的形式推理, 用于检查语法的良构

性并证明某些属性。在需求分析阶段, 利用形式化方法得到需求规格说明书, 可以规范软件开发过程, 为获得更好的系统性能提供重要保证。

需求分析的任务

需求分析的主要任务是借助于当前系统的逻辑模型导出目标系统的逻辑模型,其流程如下:

(1) 确定对系统的综合需求(功能、性能、运行、扩充需求)

(2) 制作产品需求文档 (PRD)

(3) 分析系统的数据需求(概念模型、数据字典、规范化)

(4) 导出目标系统的详细的逻辑模型(数据流图、数据字典、主要功能描述)

(5) 开发原形系统

(6) 从PRD提取编制软件需求规格说明书(SRS)

架构设计

《软件架构设计说明书》

定义

定义 1:软件或计算机系统的软件架构是该系统的一个(或多个)结构,而结构由软件元素、元素的外部可见属性及它们之间的关系组成。 定义 2:软件架构为软件系统提供了一个结构、行为和属性的高级抽象,由构成系统的元素的描述、这些元素的相互作用、指导元素集成的模式及这些模式的约束组成。 定义 3:软件架构是指一个系统的基础组织,它具体体现在:系统的构件,构件之间、构件与环境之间的关系,以及指导其设计和演化的原则上。(IEEE1471- 2000) 前两个定义都是按“元素—结构—架构”这一抽象层次来描述的,它们的基本意义相同,其中定义 1 较通俗,因此,本章采用这一定义。该定义中的“软件元素”是指比“构件” 更一般的抽象,元素的“外部可见属性”是指其他元素对该元素所做的假设,如它所提供的服务、性能特征等。

说明

为了更好地理解软件架构的定义,特作如下说明: (1) 架构是对系统的抽象,它通过描述元素、元素的外部可见属性及元素之间的关系来反映这种抽象。因此,仅与内部具体实现有关的细节是不属于架构的,即定义强调元素的 “外部可见”属性。 (2) 架构由多个结构组成,结构是从功能角度来描述元素之间的关系的,具体的结构传达了架构某方面的信息,但是个别结构一般不能代表大型软件架构。 (3) 任何软件都存在架构,但不一定有对该架构的具体表述文档。即架构可以独立于架构的描述而存在。如文档已过时,则该文档不能反映架构。 (4) 元素及其行为的集合构成架构的内容。体现系统由哪些元素组成,这些元素各有哪些功能(外部可见),以及这些元素间如何连接与互动。即在两个方面进行抽象:在静态方面,关注系统的大粒度(宏观)总体结构(如分层);在动态方面,关注系统内关键行为的共同特征。 (5) 架构具有“基础”性:它通常涉及解决各类关键的重复问题的通用方案(复用性),以及系统设计中影响深远(架构敏感)的各项重要决策(一旦贯彻,更改的代价昂贵)。 (6) 架构隐含有“决策”,即架构是由架构设计师根据关键的功能和非功能性需求(质量属性及项目相关的约束)进行设计与决策的结果。不同的架构设计师设计出来的架构是不一样的,为避免架构设计师考虑不周,重大决策应经过评审。特别是架构设计师自身的水平是一种约束,不断学习和积累经验才是摆脱这种约束走向自由王国的必经之路。

影响因素

(1) 影响架构的因素。软件系统的项目干系人(客户、用户、项目经理、程序员、测试人员、市场人员等)对软件系统有不同的要求开发组织(项目组)有不同的人员知识结构、架构设计师的素质与经验、当前的技术环境等方面都是影响架构的因素。 这些因素通过功能性需求、非功能性需求、约束条件及相互冲突的要求,影响架构设计师的决策,从而影响架构。 (2) 架构对上述诸因素具有反作用,例如,影响开发组织的结构。架构描述了系统的大粒度(宏观)总体结构,因此可以按架构进行分工,将项目组为几个工作组,从而使开发有序;影响开发组织的目标,即成功的架构为开发组织提供了新的商机,这归功于:系统的示范性、架构的可复用性及团队开发经验的提升,同时,成功的系统将影响客户对下一个系统的要求等。这种反馈机制构成了架构的商业周期。

开发质量属性

运行期

性能

安全

易用

可伸缩

互操作

可靠

持续可用

鲁棒

在有些非正常情况下仍然能用

开发期

易理解性

可扩展性

可重用性

可测试性

可维护性

可移植性

模型

结构模型

框架模型

动态模型

过程模型

功能模型

4+1视图

逻辑视图

进程视图

物理视图

场景视图

概设

把软件按照一定的原则分解为模块层次,赋予每个模块一定的任务,并确定模块间调用关系和接口。生成《软件概要设计说明书》。

详设

依据概要设计阶段的分解,设计每个模块内的算法、流程等。《软件详细设计说明书》

编码

代码

测试

黑盒

白盒

验收

《验收报告》

系统架构

定义 1:软件或计算机系统的软件架构是该系统的一个(或多个)结构,而结构由软件元素、元素的外部可见属性及它们之间的关系组成。

定义 2:软件架构为软件系统提供了一个结构、行为和属性的高级抽象,由构成系统的元素的描述、这些元素的相互作用、指导元素集成的模式及这些模式的约束组成。

定义 3:软件架构是指一个系统的基础组织,它具体体现在:系统的构件,构件之间、构件与环境之间的关系,以及指导其设计和演化的原则上。(IEEE1471- 2000)

前两个定义都是按“元素—结构—架构”这一抽象层次来描述的,它们的基本意义相同,其中定义 1 较通俗,因此,本章采用这一定义。该定义中的“软件元素”是指比“构件” 更一般的抽象,元素的“外部可见属性”是指其他元素对该元素所做的假设,如它所提供的服务、性能特征等。

(1) 架构是对系统的抽象,它通过描述元素、元素的外部可见属性及元素之间的关系来反映这种抽象。因此,仅与内部具体实现有关的细节是不属于架构的,即定义强调元素的“外部可见”属性。

(2) 架构由多个结构组成,结构是从功能角度来描述元素之间的关系的,具体的结构传达了架构某方面的信息,但是个别结构一般不能代表大型软件架构。

(3) 任何软件都存在架构,但不一定有对该架构的具体表述文档。即架构可以独立于架构的描述而存在。如文档已过时,则该文档不能反映架构。

(4) 元素及其行为的集合构成架构的内容。体现系统由哪些元素组成,这些元素各有哪些功能(外部可见),以及这些元素间如何连接与互动。即在两个方面进行抽象:在静态方面,关注系统的大粒度(宏观)总体结构(如分层);在动态方面,关注系统内关键行为的共同特征。

(5) 架构具有“基础”性:它通常涉及解决各类关键的重复问题的通用方案(复用性),以及系统设计中影响深远(架构敏感)的各项重要决策(一旦贯彻,更改的代价昂贵)。

(6) 架构隐含有“决策”,即架构是由架构设计师根据关键的功能和非功能性需求(质量属性及项目相关的约束)进行设计与决策的结果。不同的架构设计师设计出来的架构是不一样的,为避免架构设计师考虑不周,重大决策应经过评审。特别是架构设计师自身的水平是一种约束,不断学习和积累经验才是摆脱这种约束走向自由王国的必经之路。

模型

结构模型

框架模型

动态模型

过程模型

功能模型

4+1视图

逻辑视图

进程视图

物理视图

场景视图

开发质量属性

运行期

性能

安全

易用

可伸缩

互操作

可靠

持续可用

鲁棒

在有些非正常情况下仍然能用

开发期

易理解性

可扩展性

可重用性

可测试性

可维护性

可移植性

企业架构成熟度模型(EAMM)

EAMM从以下几个方面来对不同级别进行描述:

Administration – 治理角色与职责

Planning – 企业架构开发路标以及实现计划

Framework – 流程和模板

Blueprint – 实际的标准和规范集合

Communication – 交流与发布EA和详细蓝图

Compliance(一致性) – 遵循发布的标准、流程和其它EA元素,文档化流程并且能够跟踪变化

Integration – touch-points of management processes to the EA

Involvement – 整个组织对EA的支持

分级

EA LEVEL 0 - NO PROGRAM

没有文档化的架构框架,虽然解决方案已经开发并实现了,但是并没有公认的标准和最佳实践的指导,组织完全依赖于独立个人贡献者的知识。

EA LEVEL 1 - INFORMAL PROGRAM

定义了基本的企业架构和标准。大家对这些步骤达成基本一致,但是并不一定会遵守并执行,基本上是在非正式的情况下使用。这个状态下组织仍旧依赖于独立个人贡献者的知识。

EA LEVEL 2 - REPEATABLE PROGRAM

基本架构和标准已经制定并跟踪验证,开发时作为可重用方法,产品和组件遵守标准,需求得到一致认同,对流程绩效也进行了度量。

软件分层

分层原则

1.每一层都应该都是由类或组件组成。

2.只存在上层对下层的依赖,下层不依赖于上层。

3.上层调用下层的api,下层实现细节的变动不会影响到上层的代码。

框架模型

1.可伸缩性:可以把每一层分布在不同机器上,实现分布式应用。

2.可维护性:如果需求变动,只要相应调整某一层的实现即可。

3.可管理性:分层有利用分工。

4.可扩展性:增加功能只需要在相应层上调整即可。

5.可重要性:业务逻辑模块则可供系统的多个模块公共。

微服务

consul

概要设计

把软件按照一定的原则分解为模块层次,赋予每个模块一定的任务,并确定模块间调用关系和接口,模块的调用关系,每个模块的功能等等。

概要设计就是设计软件的结构

包括组成模块

模块的层次结构

设计该项目的应用系统的总体数据结构和数据库结构

每个模块的功能等等。

与详细设计区别

概要设计关注模块间的数据交互和算法,详细设计关注模块内部的数据交互和算法

根据概要设计赋予的局部任务和对外接口,设计并表达出模块的算法、流程、状态转换等内容

概要设计文档相当于机械设计中的装配图,而详细设计文档相当于机械设计中的零件图。

其实,面向对象的分析、设计方法并没有强调结构化方法那样的阶段性,

因此一般不引入概要、详细设计的概念。

如果按照公司的文档体系,非要有这种分工的话,可以将包的划分、类及对象间的关系、类的对外属性、方法及协作设计看做 概要设计;类属性、方法的内部实现看做详细设计。

概要设计中较顶层的部分便是所谓的方案。方案文档的作用是在宏观的角度上保持设计的合理性。

概要设计怎么做

详细阅读需求规格说明书,理解系统建设目标、业务现状、现有系统、客户需求的各功能说明;

分析数据流图,弄清数据流加工的过程;

根据数据流图决定数据处理问题的类型(变换型、事务型、其他型);

通过以上分析,推导出系统的初始结构图;

对初始结构图进行改进完善:

所有的加工都要能对应到相应模块(模块的完整性在于他们完成了需求中的所有加工),消除完全相似或局部相似的重复功能(智者察同),理清模块间的层次、控制关系,减少高扇出结构,随着深度增大扇入,平衡模块大小。

由对数据字典的修改补充完善,导出逻辑数据结构,导出每种数据结构上的操作,这些操作应当属于某个模块。

确定系统包含哪些应用服务系统、客户端、数据库管理系统;

确定每个模块放在哪个应用服务器或客户端的哪个目录、哪个文件(库),或是在数据库内部建立的对象。

对每个筛选后的模块进行列表说明。

对逻辑数据结构进行列表说明。

根据结构化软件设计说明书结构对其他需要说明的问题进行补充说明,形成概要设计说明书。

设计组成部分概述

4.1 简述

这部分要求突出整个设计所采用的方法(是面向对象设计还是结构化设计)、系统的体系结构(例如客户/服务器结构)以及使用到的相应技术和工具(例如OMT、Rose)

4.2 系统结构设计

这部分要求提供高层系统结构(顶层系统结构、各子系统结构)的描述,使用方框图来显示主要的组件及组件间的交互。最好是把逻辑结构同物理结构分离,对前者进行描述。别忘了说明图中用到的俗语和符号。

4.3 系统界面

各种提供给用户的界面以及外部系统在此处要予以说明。如果在需求规格说明书中已经对用户界面有了叙述,此处不用再重复,可以指引读者参考需求说明。如果系统提供了对其它系统的接口,比如说从其它软件系统导入/导出数据,必须在此说明。

4.4 约束和假定

描述系统设计中最主要的约束,这些是由客户强制要求并在需求说明书写明的。说明系统是如何来适应这些约束的。

另外如果本系统跟其它外部系统交互或者依赖其它外部系统提供一些功能辅助,那么系统可能还受到其它的约束。这种情况下,要求清楚地描述与本系统有交互的软件类型以及这样导致的约束。

实现的语言和平台也会对系统有约束,同样在此予以说明。

对于因选择具体的设计实现而导致对系统的约束,简要地描述你的想法思路,经过怎么样的权衡,为什么要采取这样的设计等等。

5 对象模型

提供整个系统的对象模型,如果模型过大,按照可行的标准把它划分成小块,例如可以把客户端和服务器端的对象模型分开成两个图表述。在其中应该包含所有的系统对象。这些对象都是从理解需求后得到的。要明确哪些应该、哪些不应该被放进图中。所有对象之间的关联必须被确定并且必须指明联系的基数。聚合和继承关系必须清楚地确定下来。每个图必须附有简单的说明。

6 对象描述

在这个部分叙述每个对象的细节,它的属性、它的方法。在这之前必须从逻辑上对对象进行组织。你可能需要用结构图把对象按子系统划分好。

为每个对象做一个条目。在系统对象模型中简要的描述它的用途、约束(如只能有一个实例),列出它的属性和方法。如果对象是存储在持久的数据容器中,标明它是持久对象,否则说明它是个临时对象(transient object)。

对每个对象的每个属性详细说明:名字、类型,如果属性不是很直观或者有约束(例如,每个对象的该属性必须有一个唯一的值或者值域是有限正整数等)。

对每个对象的每个方法详细说明:方法名,返回类型,返回值,参数,用途以及使用的算法的简要说明(如果不是特别简单的话)。如果对变量或者返回值由什么假定的话,Pre-conditions和Post-conditions必须在此说明。列出它或者被它调用的方法需要访问或者修改的属性。最后,提供可以验证实现方法的测试案例。

7 动态模型

这部分的作用是描述系统如何响应各种事件。一般使用顺序图和状态图。

顺序图:描述各种事件及事件发生的相对时间顺序。

7.1 场景(Scenarios)

对每个场景做一则条目,包括以下内容:

场景名:给它一个可以望文生义的名字

场景描述:简要叙述场景是干什么的以及发生的动作的顺序。

确定不同的场景(Scenario)是第一步,不需要确定所有可能的场景,但是必须至少要覆盖典型的系统用例。不要自己去想当然地创造场景,通常的策略是描述那些客户可以感受得到的场景。

7.2 状态图

这部分的内容包括系统动态模型重要的部分的状态图。可能你想为每个对象画一个状态图,但事实上会导致太多不期望的细节信息,只需要确定系统中一些重要的对象并为之提供状态图即可。

8 非功能性需求

与功能无关的需求,比如系统性能,执行时间,运行稳定性等。

概要设计的任务

制定规范:代码体系、接口规约、命名规则。这是项目小组今后共同作战的基础,有了开发规范和程序模块之间和项目成员彼此之间的接口规则、方式方法,大家就有了共同的工作语言、共同的工作平台,使整个软件开发工作可以协调有序地进行。

总体结构设计:

功能(加工)->模块:每个功能用那些模块实现,保证每个功能都有相应的模块来实现;

模块层次结构:某个角度的软件框架视图;

模块间的调用关系:模块间的接口的总体描述;

模块间的接口:传递的信息及其结构;

处理方式设计:满足功能和性能的算法

用户界面设计;

数据结构设计:

详细的数据结构:表、索引、文件;

算法相关逻辑数据结构及其操作;

上述操作的程序模块说明(在前台?在后台?用视图?用过程?······)

接口控制表的数据结构和使用规则

其他性能设计。

概要设计的目的

将软件系统需求转换为未来系统的设计;

逐步开发强壮的系统构架;

使设计适合于实施环境,为提高性能而进行设计;

结构应该被分解为模块和库。

问题的提出

概要设计写什么?概要设计怎么做?

如何判断设计的模块是完整的?

为什么说设计阶段过于重视业务流程是个误区?

以需求分析文档还是以概要设计文档来评估开发工作量、指导开发计划准确?

结构化好还是面向对象好?

以上问题的答案请在文章中找。

概要设计的原则

总体原则和方法:由粗到细的原则,互相结合的原则,定性分析和定量分析相结合的方法,分解和协调的方法和模型化方法。

要系统考虑系统的一般性、关联性、整体性和层次性。

分解协调:目的是为了创造更好的系统。系统分解是指将一个复杂的系统分解为若干个子系统,系统协调一是系统内协调,即根据系统的总结构、总功能、总任务和总目标的要求,使各个子系统之间互相协调配合,在各个子系统局部优化基础上,通过内部平衡的协调控制,实现系统的整体优化;

屏蔽抽象:从简单的框架开始,隐含细节;

一致性:统一的规范、统一的标准、统一的文件模式;

每个模块应当有一个统一命名的容易理解的名字;

编码:由外向内(界面->核心);

面向用户:概要设计是对于按钮按下后系统“怎么做”的简要说明;

模块、组件的充分独立性、封闭性;

同时考虑静态结构与动态运行;

每个逻辑对象都应当说明其所处物理对象(非一一对应);

每个物理对象都有合适的开发人员,并且利于分工与组装。(详细说明见本人另一篇文章:系统构架设计应考虑的因素);

确立每个构架视图的整体结构:视图的详细组织结构、元素的分组以及这些主要分组之间的接口;

软件构架与使用的技术平台密切相关,目前常用的平台有J2EE、.NET、CORBA等等,因此具体的软件构架人员应当具备使用这些平台的软件开发经验;

通过需求功能与设计模块之间的列表对应,检查每个需求功能是否都有相应的模块来实现,保证需求功能的可追溯性和需求实现(模块)的完整性,同时可以检查重复和不必要的模块。

在需求调研分析过程中对业务处理过程了解的完整性和准确性非常重要。

概要设计的重要输出

编码规范

信息形式、接口规约、命名规则

物理模型

组件图

配置图

不同角度的构架视图(可选);

用例视图

逻辑视图

进程视图

部署视图

实施视图

数据视图

系统总体布局:

哪些部分组成

各部分在物理上

逻辑上的相互关系

两个不可忽视的输出逻辑与物理位置

每个对象在逻辑上分别落在哪一层、哪个模块、哪个类;

与需求功能的关系:对于需求中的每一个功能,用哪一层、哪个模块、哪个类、哪个对象来实现(一对多关系);

详细设计

发现很多共性的内容,需要提炼为整个程序需要遵循的设计规范

1)用户体验设计;(下一篇再详细介绍)

2)输入合法性判定;

3)批量数据的传输约定;

4)实体类的生命周期;

5)逻辑类的生命周期;

6)并发冲突的处理原则,包括判定办法、提示办法;

7)连接打开、关闭原则;

8)采用事务的原则;

9)异常处理机制;

10)日志记录机制;

目的

对概要设计的进一步细化,一般由各部分的担当人员依据概要设计分别完成,然后在集成,是具体的实现细节。是“程序”的蓝图,确定每个模块采用的算法、数据结构、接口的实现、属性、参数。搞清楚“每个模块怎么做”。并输出《软件详细设计说明书》。

软件需求分析人员组织

软件需求分析其根本性问题是理解用户功能需求,一般我们必须有商务活动人员,项目管理人员,设计技术人员等参加,而且要求组织人员必须明确负责范围,以及明确工作目标,保证实施的有效性。

定义

软件需求分析(Software Reguirement Analysis)是研究用户需求得到的东西,完全理解用户对软件需求的完整功能,确认用户软件功能需求,建立可确认的、可验证的一个基本依据。

软件需求分析理论

一个软件包含了所有功能的集合,同时包含了实现所有功能的所有方法和算法描述。需求分析是依据于用户需求,经过需求问题识别,进行分析、消化与综合,制订规格说明,评审,分为四个阶段,形成用户需求与设计同步,设计满足用户需求目标。

主要实现目

1)对实现软件的功能做全面的描述,帮助用户判断实现功能的正确性、一致性和完整 性,促使用户在软件设计启动之前周密地、全面地思考软件需求;

2)了解和描述软件实现所需的全部信息,为软件设计、确认和验证提供一个基准;

3)为软件成本计价和软件开发计划提供依据;

需求分析具体内容可以归纳为六个方面:

软件的功能需求

软件与硬件或其他外部系统接口

软件的非功能性需求

软件的反向需求

软件设计和实现上的限制

阅读支持信息

软件需求分析应尽量提供软件实现功能需求的全部信息,使得软件设计人员和软件测试人员不再需要需求方的接触。这就要求软件需求分析内容应正确、完整、一致和可验证。此外,为保证软件设计质量,便于软件功能的休整和验证,软件需求表达无岔意性,具有可追踪性和可修改性。

软件功能需求

软件的功能需求是整个需求分析最主要、最关键和最复杂的部分,它描述软件的各种可能的条件下,对所有可能输入的数据信息,应完成那些具体功能,产生什么样的输出。描述软件功能需求是应注意下面几点:

1)功能需求的完整性和一致性,并应具有内在的一致性(即各种描述之间不矛盾、不冲突)。

(1) 给出触发功能的各种条件(如:控制流、运行状态、运行模式等);

(2) 定义各种可能性条件下的所有可能的输入(包括合法的输入空间和非法的输入空间);

(3) 给出各种功能间可能的相互关系(如各个功能间的控制流、数据流、信息流,功能运行关系:顺序、重复、选择、并发、同步);

(4) 给出功能性的主要级别(如:基本功能、可由设计者选择逐步实现的功能、可由设计者改变实现的功能等);

(5) 尽可能不使用“待定”这样的词。所有含有待定内容的需求都不是完整的文件,如果出现待定的部分,必须进行待定部分内容说明,落实负责人员、落实实施日期。

2)功能描述的无岔意性和可追踪性,需求功能描述的无岔意性、可追踪性和规范化:

(1) 功能描述必须清晰地描述出怎样输入到怎样输出,并且输入、输出描述应对应有数据流描述、控制流描述图,这些描述必须与其它地方描述一致;

(2) 可以用语言、方程式、决策表、矩阵或图等对功能的描述。如果选用语言描述必须使用结构化的语言,描述前必须说明该步骤(或子功能)的执行是顺序,选择,重复,还是并发,然后说明步骤逻辑。整个描述必须单入单出。

(3) 描述时,每一个功能名称和参照编号必须唯一,且不要将多个功能混在一起进行描述,这样便于功能的追踪和修改。

(4) 功能描述应注意需求说明和程序设计的区别。需求设计仅仅是软件的功能设计,它给出软件运行的的外部功能描述,以及为了实现这一外部功能必须做哪些事情(采用和种数据结构,定义多个模块,接口间的接口等)是设计阶段的事情,功能描述不应涉及到那些细节问题,以避免给软件设计带来不必要的约束。

2.2、 软件与硬件或其他外部系统接口

(1) 人机接口:说明输入、输出的内容、屏幕安排、格式等要求;

(2) 硬件接口:说明端口号,指令集,输入输出信号的内容与数据类型,初始化信号源,传输通道号和信号处理方式。

(3) 软件接口:说明软件的名称、助记符、规格说明、版本号和来源;

(4) 通讯接口:指定通讯接口和通讯协议等描述。

2.3、软件的非功能性需求,指软件性能指标,容限等功能以外的需求。

(1) 时间需求:输入、输出频率,输入、输出响应时间,各种功能恢复时间等;

(2) 处理容限、精度、采样参数的分辨率,误差处理等;

(3) 可靠性的MTBF要求,可维护性、安全性要求等。(对可能的不正常的输入给以正常响应是可靠性的重要内容,这属于功能性需求。)

2.4、软件反向需求

软件的反向需求描述软件在那些情况下不能做什么。

2.5、软件设计和实现上的限制

软件设计和实现上的限制主要指对软件设计者的限制。如软件运行环境的限制(选择计算机类型,使用配置,操作系统的限制等)、设计工具的限制(使用语言、执行的标准)和保密要求等。

2.6、阅读支持信息

这部分内容是为了更好的帮助我们理解用户需求,也是为了使需求便于修改和追踪。其本身并不是对需求的描述,但它影响到需求分析的可读性,也属于需求分析的一个重要部分。一般目录、需求背景信息、内容索引、交叉引用表、注释等均属于这个部分的内容。

软件需求分析方法

为了保证项目的正常实施,并且能够顺利的完成,我们必须加强项目管理和重视项目分析工作。我们只有从实际出发,切切实实地把握用户需求,把握用户需求目标,把握用户将来功能界定,保证我们开发工作正确性方向。

4.1、重点监控软件需求分析办法

由于软件项目的特殊性和行业覆盖的广阔性,以及需求分析的高风险性,软件需求分析的重要性是不言而喻的,同时需求分析又的的确确难做。其原因基本是由于以下情况造成的。

4.1.1、客户说不清楚需求

有些客户对需求只有朦胧的感觉,当然说不清楚具体的需求。例如全国各地的很多部门、机构、单位在进行应用系统以及网络建设时,客户方的办公人员大多不清楚计算机网络有什么用,更缺乏IT系统建设方面的专家和知识。此时,用户就会要求软件系统分析人员替他们设想需求。工程的需求存在一定的主观性,为项目未来建设埋下了潜在的风险。

4.1.2、需求自身经常变动

根据以往的历史经验,随着客户方对信息化建设的认识和自己业务水平的提高,他们会在不同的阶段和时期对项目的需求提出新的要求和需求变更。事实上,历史上没有一个软件的需求改动少于三次的!所以必须接受“需求会变动”这个事实,在进行需求分析时要懂得防患于未然,尽可能地分析清楚哪些是稳定的需求,哪些是易变的需求,以便在进行系统设计时,将软件的核心建筑在稳定的需求上,同时留出变更空间。咨询监理方在需求分析的功能界定上担任一个中间、公平、公正的角色,所以也必须积极参与到需求分析的准备中来,以便协助客户方和承建方来界定“做什么”、“不做什么”的系统功能界限。

4.1.3、分析人员或客户理解有误

软件系统分析人员不可能都是全才,更不可能是行业方面的专家。客户表达的需求,不同的分析人员可能有不同的理解。如果分析人员理解错了,可能会导致以后的开发工作劳而无功。记得一则笑话,有个外星人间谍潜伏到地球刺探情报,它给上司写了一份报告:“主宰地球的是汽车。它们喝汽油,靠四个轮子滚动前进,嗓门极大,双眼在夜里能射出强光……有趣的是,车里住着一种叫作‘人’的寄生虫,这些寄生虫完全控制了车。”所以分析人员知识的专一性也会造成需求分析的误解和失败。这时,咨询监理公司就必须根据实际的项目需求调研计划,提醒承建方加强业务了解程度和注重沟通技巧。

4.2、有效性软件需求分析三步法

根据以往的工程经验,需求分析工作方法,应该定位在“三个阶段”(也称“三步法”)。

4.2.1、“访谈式Visitation”阶段

这一阶段是和具体用户方的领导层、业务层人员的访谈式沟通,主要目的是从宏观上把握用户的具体需求方向和趋势,了解现有的组织架构、业务流程、硬件环境、软件环境、现有的运行系统等等具体情况、客观的信息。建立起良好的沟通渠道和方式。针对具体的职能部门以及各委办局,最好能指定本次项目的接口人。

###### 实现手段:访谈、调查表格

###### 输出成果:调查报告、业务流程报告

4.2.2、“诱导式Inducement”阶段

这一阶段是在承建方已经了解了具体用户方的组织架构、业务流程、硬件环境、软件环境、现有的运行系统等等具体实际、客观的信息基础上,结合现有的硬件、软件实现方案,做出简单的用户流程页面,同时结合以往的项目经验对用户采用诱导式、启发式的调研方法和手段,和用户一起探讨业务流程设计的合理性、准确性、便易性、习惯性。用户可以操作简单演示的DEMO,来感受一下整个业务流程的设计合理性、准确性等等问题,及时地提出改进意见和方法。

###### 实现手段:拜访(诱导)、原型演示

###### 输出成果:调研分析报告、原型反馈报告、业务流程报告

4.2.3、“确认式Afirm”阶段

这一阶段是在上述两个阶段成果的基础上,进行具体的流程细化、数据项的确认阶段,这个阶段承建方必须提供原型系统和明确的业务流程报告、数据项表,并能清晰地向用户描述系统的业务流设计目标。用户方可以通过审查业务流程报告、数据项表以及操作承建方提供的DEMO系统,来提出反馈意见,并对已经可接受的报告、文档签字确认。
实现手段:拜访(回顾、确认),提交业务流程报告、数据项表;原型演示系统
输出成果:需求分析报告、数据项、业务流程报告、原型系统反馈意见(后三者可以统一归入需求分析报告中,提交用户方、监理方进行确认和存档)
整体来讲,需求分析的三个阶段是需求调研中不可忽视一个重要的部分,三个阶段或者说三步法的实施和采用,对用户和承建方都同样提供了项目成功的保证。当然在系统建设的过程中,特别在采用迭代法的开发模式时,需求分析的工作需一直进行下去,而在后期的需求改进中,工作则基本集中在后两个阶段中。

软件需求分析工具

我们根据用户需求,通过反复讨论、分析,最终明确一个唯一性的用户需求,这个结果其实就是我们的软件需求分析报告。一般我们采用Word、PowerPoint、Visio、ProntPage、Excel等Office工具,同时可能采用一些开发工具,如VC或BC等,同样也会使用一些图形工具,如Potoshop、调色板等画图工具。

使用各种工具表达软件需求分析,其具体表达手段可以分为:

l 效果图描述。主要是用户UI界面的描述反映用户需求功能;

l 逻辑图描述。根据用户需求功能,使用抽象化理论,以及需求分析理论,对用户需求功能进行全面的分析,建立功能性逻辑关系图,流程逻辑关系图等;

l 关系图表描述。主要是对信息关系、数据库表格、接口函数等描述;

l 工程数学描述。分析用户需求,分析用户需求信息,运用工程数学进行算法推导,进行合理化需求分析推导;

l 甘地图描述。主要是软件项目工作安排,开发周期预估;

l 其它方法描述。保证完整性合理性的有效描述。

软件需求分析评估

软件需求分析评估是为了检查我们进行软件需求分析工作,保证软件需求分析工作正确性、完整性、有效性、合理性、可确认性、可实施性,完全保证用户所需求的功能。

6.1、组织结构与责任管理

我们对组织结构与责任管理的评估主要有:参与人员任务和责任界面的明确;安排计划按时完成状况;相互间的协调能力状况。

6.2、满足用户需求的功能

我们进行需求分析的目的是完整、准确地描述用户的需求,跟踪用户需求的变化,将用户的需求准确地反映到系统的分析和设计中,并使系统的分析、设计和用户的需求保持一致。

需求分析的特点是需求的完整性、一致性和可追溯性。完整性:是准确、全面的描述用户的需求。一致性:是通过分析整理,剔除用户需求矛盾的方面,规范用户需求。可追溯性:有两个方面的含义,整理和规范的需求,其一,需要不断的和用户进一步交流,保持和用户最新的需求一致。其二,和系统分析(设计)保持一致。

因此在需求分析之前我们必须建立需求分析技术层面的基本框架,从技术上保证需求分析的要求,在此基础上我们进行的需求分析才能满足项目对需求分析的要求。

6.3、保证可实施性

我们必须以用户软件需求为依据,以求实的态度详细的、准确的、完整的编写软件需求分析,避免空想世界,空中楼阁的想法;避免无逻辑性、无核心的描述;避免无量化思维,无实际空间概念。

6.4、需求分析评价指标

功能性

完整性

正确性

逻辑性

表现性

合理性

可实施性等

6.5、工作周期

评价人员投入,以及费用支出的合理性问题。正确制定工作周期,保证软件项目的顺利完成。

6.6、需求不确定更改与可确认保证

可确认需求功能是实现用户需求的基本保证,如果不可确认的、不确定更改存在,将会阻碍软件实现,或者软件设计存在着不完整性缺陷,或者存在着不可实施性问题,我们必须区分是功能性障碍问题,还是未来性问题。如果不能够明确是未来性问题,则必须调整功能需求,化解不确定更改的问题。因此,判断不确定性更改是一个非常重要的问题

数据分析

数据采集

数据源

开源数据源

日志采集

爬虫抓取

传感器

工具使用

八爪鱼

火车采集器

搜集客

Python爬虫利器

phantomjs

scrapy

lxml

selenium

数据挖掘

数学基础

概率论与数据统计

线性代数

图论

最优化方法

基本流程

商业理解

数据理解

数据准备

模型建立

模型评估

上线发布

十大算法

分类算法

聚类算法

关联分析

连接分析

数据可视化

Python可视化

Matplotlib

Seaborn

第三方工具

微图

DataV

软件测试

系统测试:系统测试是对已经集成好的软件系统进行彻底的测试,

以验证软件系统的正确性和性能等是否满足其规约所指定的要求。

测试种类

功能测试:

功能测试是对产品的各功能进行验证,以检查是否满足需求的要求。

性能测试:

性能测试是通过自动化测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。

安全测试:

安全测试检查系统对非法入侵的防范能力。

兼容测试:

兼容性测试主要是测试系统在不同的软硬件环境下是否能够正常的运行。

验收测试:

验收测试是部署软件之前的最后一个测试操作。 验收测试的目的是确保软件准备就绪, 向软件购买都展示该软件系统满足其用户的需求。

验收测试内容

功能确认测试

安全可靠性测试

易用性测试

可扩充性测试

兼容性测试

资源占用率测试

用户文档资料验收

集成测试:

集成测试是在软件系统集成过程中所进行的测试。 目的是检查软件单位之间的接口是否正确。

关注内容

1. 把各个模块连接起来时,穿越模块接口的数据据是否会丢失。

2. 各个了模块组合起来,能否达到预期要求的功能。

3. 一个模块的功能是否会对另一个模块的功能产生不利影响。

4. 全局数据据结构是否有问题。

5. 单个模块的误差积累起来是否会被放大,从而达到不可接受的程序。

单元测试:

单元测试是对软件中的基本组成单位进行的测试。 目的是检验软件基本组成单位的正确性。

单元测试的好处

(1)单元测试帮助设计

单元测试迫使我们从关注实现转向关注接口,编写单元测试的过程就是设计接口的过程,使单元测试通过的过程是我们编写实现的过程。我一直觉得这是单元测试最重要的好处,让我们关注的重点放在接口上而非实现的细节。

(2)单元测试帮助编码

应用单元测试会使我们主动消除和减少不必要的耦合,虽然出发点可能是为了更方便的完成单元测试,但结果通常是类型的职责更加内聚,类型间的耦合显著降低。这是已知的提升编码质量的有效手段,也是提升开发人员编码水平的有效手段。

(3)单元测试帮助调试

应用了单元测试的代码在调试时可以快速定位问题的出处。

(4)单元测试帮助重构

对于现有项目的重构,从编写单元测试开始是更好的选择。先从局部代码进行重构,提取接口进行单元测试,然后再进行类型和层次级别的重构。
单元测试在设计、编码和调试上的作用足以使其成为软件开发相关人员的必备技能。

基本

单元测试的好处

(1)单元测试帮助设计

###### 单元测试迫使我们从关注实现转向关注接口,编写单元测试的过程就是设计接口的过程,使单元测试通过的过程是我们编写实现的过程。我一直觉得这是单元测试最重要的好处,让我们关注的重点放在接口上而非实现的细节。

(2)单元测试帮助编码

###### 应用单元测试会使我们主动消除和减少不必要的耦合,虽然出发点可能是为了更方便的完成单元测试,但结果通常是类型的职责更加内聚,类型间的耦合显著降低。这是已知的提升编码质量的有效手段,也是提升开发人员编码水平的有效手段。

(3)单元测试帮助调试

###### 应用了单元测试的代码在调试时可以快速定位问题的出处。

(4)单元测试帮助重构

###### 对于现有项目的重构,从编写单元测试开始是更好的选择。先从局部代码进行重构,提取接口进行单元测试,然后再进行类型和层次级别的重构。

###### 单元测试在设计、编码和调试上的作用足以使其成为软件开发相关人员的必备技能。

应用单元测试:

单元测试不是简单的了解使用类似XUnit和Moq这样的测试和模拟框架就可以使用了, 首先必须对我们要编写的代码有足够的了解。 通常我们把代码看成一些静态的互相关联的类型,类型之间的依赖使用接口,实现类实现接口, 在运行时通过自定义工厂或使用依赖注入容器管理。 一个单元测试通常是在一个方法中调用要测试的方法或属性, 通过使用Assert断言对方法或属性的运行结果进行检测,通常我们需要编写的测试代码有以下几种。

(1)测试领域层

###### 领域层由POCO组成,可以直接测试领域模型的公开行为和属性。

(2)测试应用层

###### 应用层主要由服务接口和实现组成,应用层对基础设施组件的依赖以接口方式存在,这些基础设施的接口通过Mock方式模拟。

(3)测试表示层

###### 表示层对应用层的依赖表现在对服务接口的调用上,通过Mock方式获取依赖接口的实例。

(4)测试基础设施层

###### 基础设施层的测试通常涉及到配置文件、Log、HttpContext、SMTP等系统环境,通常需要使用Mock模式。

(5)使用单元测试进行集成测试

###### 首先系统之间通过接口依赖,通过依赖注入容器获取接口实例,在配置依赖时,已经实现的部分直接配置,伪实现的部分配置为Mock框架生成的实例对象。随着系统的不断实现,不断将依赖配置的Mock对象替换为实现对象。

3.使用Assert判断逻辑行为正确性

4.使用伪对象

(1)使用接口依赖取代原始类型依赖。
(2)通过对原始类型的适配实现上述接口。
(3)手动创建用于单元测试的接口实现类或在单元测试时使用Mock框架生成接口的实例。

5.单元测试常用框架和组件

(1)单元测试框架。

###### XUnit是目前最为流行的.NET单元测试框架。NUnit出现的较早被广泛使用,如nopCommerce、Orchard等项目从开始就一直使用的是NUnit。XUnit目前是比NUnit更好的选择,从github上可以看到asp.net mvc等一系列的微软项目使用的就是XUnit框架。

(2)Mock框架

###### Moq是目前最为流行的Mock框架。Orchard、asp.net mvc等微软项目使用Moq。nopCommerce使用Rhino Mocks。NSubstitute和FakeItEasy是其他两种应用广泛的Mock框架。

(3)邮件发送的Mock组件netDumbster

###### 可以通过nuget获取netDumbster组件,该组件提供了SimpleSmtpServer对象用于模拟邮件发送环境。

###### 通常我们无法直接对邮件发送使用Assert,使用netDumbster我们可以对模拟服务器接收的邮件应用Assert。

(4)HttpContext的Mock组件HttpSimulator

###### 同样可以通过nuget获取,通过使用HttpSimulator对象发起Http请求,在其生命周期内HttContext对象为可用状态。

6.使用单元测试的难处

(1)不愿意付出学习成本和改变现有开发习惯。
(2)没有思考的习惯,错误的把单元测试当框架学。
(3)在项目后期才应用单元测试,即获取不到单元测试的好处又因为代码的测试不友好对单元测试产生误解。
(4)拒绝考虑效率、扩展性和解耦,只考虑数据和功能的实现。

分类

模块接口测试

通过所测模块的数据流进行测试。调用所测模块时的输入参数与模块的形式参数的个数、属性和顺序是否匹配。

局部数据结构测试

局部数据结构是为了保证临时存储在模块内的数据在程序执行过程中完整、正确、模块的局部数据结构往往是错误的根源。

路径测试

对模块中重要的执行路径进行测试。

错误处理测试

比较完善的模块设计要求能遇见出错的条件,并设置适当的出错处理,以便在一旦程序出错时,能对出错程序重做安排,保证其逻辑上的正确性。

边界条件测试

软件经常在便捷上失效,边界条件测试是一项基础测试,也是后面系统测试中的功能测试的重点。

其他层面分类

测试工作对软件代码的的可见程度的划分

白盒测试

白盒测试,指的是把盒子盖子打开,去研究里面的源代码和程序结果。

  它是按照程序内部的结构测试程序,通过测试来检测产品内部动作是否按照设计规格说明书的规定正常进行,检验程序中的每条通路是否都能按预定要求正确工作

黑盒测试

灰盒测试介于黑盒测试与白盒测试之间。

  可以这样理解,灰盒测试关注输出对于输入的正确性,同时也关注内部表现, 但这种关注不象白盒那样详细、完整,只是通过一些表征性的现象、事件、标志来判断内部的运行状态, 有时候输出是正确的,但内部其实已经错误了,这种情况非常多,如果每次都通过白盒测试来操作,效率会很低,因此需要采取这样的一种灰盒的方法。

灰盒测试

黑盒测试,指的是把被测的软件看作是一个黑盒子,我们不去关心盒子里面的结构是什么样子的,只关心软件的输入数据和输出结果。

它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数据而产生正确的输出信息。黑盒测试着眼于程序外部结构,不考虑内部逻辑结构,主要针对软件界面和软件功能进行测试。

功能测试、性能测试

功能测试

功能测试检查实际的功能是否符合用户的需求。测试的大部分工作也是围绕软件的功能进行,设计软件的目的也就是满足客户对其功能的需求。如果偏离的这个目的任何测试工作都是没有意义的。

  功能测试又可可以细分为很多种:逻辑功能测试、界面测试、易用性测试、安装测试、兼容性测试等。

性能测试

 性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。

  软件的性能包括很多方面,主要有时间性能和空间性能两种。

  时间性能:主要是指软件的一个具体的响应时间。比如一个登录所需要的时间,一个交易所需要的时间等。当然,抛开具体的测试环境,来分析一次事务的响应时间是没有任何意义的。需要搭建一个具体且独立的测试环境。

  空间性能:主要指软件运行时所消耗的系统资源,比如硬件资源,CPU、内存,网络带宽消耗等。

手工测试与自动化测试

手工测试

手工测试:

手工测试就是由人去一个一个的去执行测试用例,通过键盘鼠标等输入一些参数,查看返回结果是否符合预期结果。

自动化测试

自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。

优点

可以频繁的进行测试

可以在任何时间进行测试,也可以按计划定时进行,例如:可以在半夜进行自动化测试

比人工测试速度快

可以更快速地发现错误

基本上是非常可靠的

测试代码与生产代码紧密结合

使得开发团队更具有幸福感

其他测试

冒烟测试

是指在对一个新版本进行系统大规模的测试之前,先验证一下软件的基本功能是否实现,是否具备可测性。

回归测试

回归测试是指修改了旧代码后,重新时行测试以确认修改后没有引入新的错误或导致其他代码产生错误。

随机测试

是指测试中的所有输入数据都是随机生成的,其目的是模拟用户的真实操作,并发现一些边缘性的错误。

探索性测试

探索性测试可以说是一种测试思维技术。它没有很多实际的测试方法、技术和工具,但是却是所有测试人员都应该掌握的一种测试思维方式。探索性强调测试人员的主观能动性,抛弃繁杂的测试计划和测试用例设计过程,强调在碰到问题时及时改变测试策略。

安全测试

安全测试是在IT软件产品的生命周期中,特别是产品开发基本完成到发布阶段,对产品进行检验以验证产品符合安全需求定义和产品质量标准的过程。

自动化测试

四、常见的自动化测试框架

1、接口自动化框架:

①、java+testNG/Junit+Maven/Ant/Gradle+Jenkins+MySQL+testlink/redmine

②、python+unittest/pytest+Git+Jenkins+MySQL+testlink/redmine

③、python+rebot framework+unittest/pytest+Git+Jenkins+MySQL+testlink/redmine

④、jmeter+Maven/Ant+Jenkins+MySQL+testlink/redmine

2、UI自动化测试框架

①、java+selenium/appium+testNG/Junit+Maven/Ant/Gradle+Jenkins+MySQL+testlink/redmine

②、python+selenium/appium+unittest/pytest+Git+Jenkins+MySQL+testlink/redmine

③、python+rebot framework+unittest/pytest+Git+Jenkins+MySQL+testlink/redmine

敏捷开发

敏捷软件开发宣言

个人与交互 高于 流程和工具

可用软件 高于 详尽的文档

客户合作 高于 合同谈判

响应变化 高于 遵循计划

敏捷宣言的十二条原则

我们最重要的目标,是通过持续不断地及早交付有价值的软件使客户满意。

欣然面对需求变化,即使在开发后期也一样。为了客户的竞争优势,敏捷过程掌控变化。

经常地交付可工作的软件,相隔几星期或一两个月,倾向于采取较短的周期。

业务人员和开发人员必须相互合作,项目中的每一天都不例外。

激发个体的斗志,以他们为核心搭建项目。提供所需的环境和支援,辅以信任,从而达成目标。

不论团队内外,传递信息效果最好效率也最高的方式是面对面的交谈。

可工作的软件是进度的首要度量标准。

敏捷过程倡导可持续开发。责任人、开发人员和用户要能够共同维持其步调稳定延续。

坚持不懈地追求技术卓越和良好设计,敏捷能力由此增强。

以简洁为本,它是极力减少不必要工作量的艺术。

最好的架构、需求和设计出自自组织团队。

团队定期地反思如何能提高成效,并依此调整自身的举止表现。

应该着重注意的点

需求在开发中的重要性

大量的开发过程告诉我,需求在软件开发过程中是极其重要的。传统的开发强调初期的需求调研及需要分析,这个过程对于一些正规的团队会产生大量的文档,而后交由开发展开产品生产。

然而,事实却不是想象这么简单,无数的例子说明了一点,仅仅在需求调研过程中了解到的需求是无法保证的。数不清的例子告诉我们,需求是会变的,变的原因很多。在极端的情况下,有些客户签字的需求在开发完后,有需要变更也很正常。

所以需求是影响软件开发的第一重要因素,需求来源于业务,我们开发的产品不就是因为这些业务才去做的吗?如何需求都无法把握好,还谈什么开发出好用的产品?

然而如何做好需求呢?我想首先要确立需求的地位,然后只有通过不断的沟通、尝试、反馈向真实需求迈进。

强调人与人的交流

不管怎么样开发过程中主要还是靠人的,而且软件开发是个复杂的团体工程,一个小些的产品也会涉及到各类人:客户、业务分析、管理人员、程序员、测试员等等。这么多人在一起做事情,有一方没有处理好结果肯定就会有问题。

有这样一个例子:客户提出了一个会员管理功能需求,需求人员了解后组织了解决方案,于是交付了开发实现。而经过二个月无尽的黑夜之后交付,需求一看有个模块做的有偏差,但是已经来不及修改了。交给客户看后,发现这不是他们要的会员管理功能相差较大,另外在功能开发的这一段时间,客户又有了新想法,要对原先需求做调整。

这种例子可能大家经常经历吧?

这种问题在敏捷开发方法中提出了解决方法,就是通过不断的交付可用的制品。看起来很抽象,其实很简单。同样是上面的例子:

Ø 客户提出会员管理功能需求

Ø 需求人员在了解需求后与开发负责人商量,确定一个快迭代的开发计划,每二周向客户演示一次,并将这个计划与客户确认

Ø 确认后需求人员向全体成员讲解需求背景故事

Ø 开发负责人组织并确定迭代计划内容,明确每个迭代提交的产品目标、开发任务安排、测试跟踪计划

Ø 每个迭代过程中都由需求及测试进行确认每个任务的实现结果是否跑偏

Ø 后面就是每二周向客户演示一次产品,并获得客户的反馈

Ø 根据客户的反馈调整下个迭代计划,并继续下一个迭代

Ø 直到产品交付

通过上面的步骤,就不至于在开发完成后才知道用户的真实想法,因为很多用户对软件开发是没有概念的,他只知道自己有某种需求,但最开始是没有一个完整的概念的。所以就要通过不断的让用户看到产品的模型,这个过程用户才会逐步的对产品产生概念。同样的在过程中客户的提出需求变更也是在一定的可控制范围之内,这样一来可以大大的减少软件返工的情况,自然就不会拖延计划了。

而这个过程中,需求已经完成了一个真正的过渡,不再是一头重的情况了。他让需求从客户那快速的反馈到开发团队中。同样的,在开发不断的交付制品时,需求也更加及时的了解到产品的进度,把握开发人员开发的功能是否符合需求。

当然这并不是一个标准做法,不同的团队可以有不同的处理方式。这里只是想强调需求需要更多的投入到开发过程中去,及时的与客户沟通交流,了解到客户的真实想法。

强调文档的作用

我觉得很多对敏捷开发的一个误解就是不需要文档,敏捷开发并未抛弃文档。只是更强调更有效的方式使用文档。在很多传统开发方法中,特别是很多很正规的开发团队对文档的要求非常苛刻。然而事实是文档不易管理,最痛苦的是不好维护,文档需要随着变化而变化,比如需求调整、技术架构升级、产品维护等等。如果要保证文档的一致性,太难了。特别是对于一些无法进行有效管理的开发团队就更加明显,经常是软件已经几个版本了,文档却是两年前的。

但敏捷真的不需要文档吗?我想不是的,如何把文档做到好维护我想才是最重要的。文档到底指的指的什么?什么样的算文档?

提出上面两个问题,我们先想想经常说的文档的作用是什么?不就是一个传播工具吗?可以用作记录、给他人看、用于以后查看。有很多方法可就解决了这个问题,比如wiki系统。维护一个wiki系统,可以随时写,随时维护,可以方便的查找。嗯,多方便。

另外一个问题就是什么样的工作需要形成文档呢?

记得在前一家公司,维护一个10多年的老系统修改一个公式计算的BUG,但是怎么也不知道这个复杂的公式是什么意思,问过了公司大部分的人也无人可解。这时想,如果当初有那么一份文档,谢天谢地。

像这种关键的内容有份文档还是很重要的,否则随着时间推移,谁也不能保证能记得住当时为什么会这么干。

记得多年前一次记笔记的经历,我看了一篇文章了解了DELPHI实现单实例模式的方法,这种方法很酷。于是整理成了笔记写在了wiki上,第二天就得到了回复,帮助到了别外产品开发组的同事。

嗯,文档就是这样他具有传播性,你不可能跑去跟所有人说出你的想法,但是文档却更容易达成。他也有传承性,有些文档也许10多年后又起了重要作用。

团队协作

1、减少对开发人员的干扰

曾经接手一个产品的开发,最初遇到一个很头痛的问题,原先写好的迭代计划,而且工作量也较大,大家都在忙着。即便在这样的状态下,客服人员却经常跑来找某个程序员A维护各种系统问题,程序员A在一次维护中竟然导致了系统数据出现大面积错误。程序员A心理上承受着巨大的压力,而每天的这些问题又不得不解决,加之新版本又有很重的开发任务无法完成,最终导致整个开发计划变更。

我无法再忍受,找到了需求及客服的负责人,沟通后发现这些问题很多都是重复性的,主要是因为原先系统的不足。于是回去组织人员做了几个后台临时功能,并交付给了客服人员,之后就没有再来找过这位程序员A。后续我又找到了客服负责人,要求不能直接找开发人员解决这类问题,并与负责人约定了处理过程。

这是个例子,在实际情况中还有很多这种事情,甚至有很多开发人员要直接面对客户。我想对于职能型团队来说,开发团队最好是减少这些方面的干忧。当然对于一个人包干的情况就不讨论了。

大部分的人都不是超人,在一个时间段内处理超出自己负荷的工作是很难做好保质保量的。所以对于开发管理人员一定要考虑到这点,尽量让开发人员有比较好的工作进度环境,通过外界的方式来解决一些开发团队的干扰。

我接触过的很多程序员都很反感这种干扰,虽然有些人在这种全面的工作强度下成长很快,但是并非所有人都适应,长期下来会有怨恨和不快,工作效率会下降。心情舒畅还是很重要的,记得有一次迭代总结时,有个程序员总结说:发现心情舒畅自己的工作效率很高。呵呵。我想你也有同感吧。

2、不要忽略测试人员在开发阶段的作用

曾经多少次在项目发布前加班到深夜2点的情景还历历在目,那种感觉即快乐又痛苦。由于和客户签定的合同的交付日期就要到了,产品却迟迟未集成完成,测试只能干等着上网聊QQ。就在下班前的一刻发布了,测试开始了紧张的测试,在屏幕闪动中,一个个的BUG提交,直到流程都无法都走不下去,测试无奈了。第二天就要发布,实施人员就等着制品第二天出差。只有不断的改,再发布,无尽的循环。直到大家都憔悴的看着老大,终于老大说:还剩下的这几个问题无关紧要,大家回去吧。

几个月的开发过去后在总结会上,只能抱怨测试资源不足,时间太短,需求更改太多,需求更改后测试不知道。无数的问题一次一次的出现在同样的总结会议上。

上面的这个例子很多人应该经历过,真的测试只有最后一刻才能体现价值吗?我想不是的。

在后面的项目中我总结了这个问题的,针对每个开发任务要求进行测试验证。而测试如何验证呢?他需要知道这个开发任务的需求是如何,提前做好测试计划及测试用例,在接到开发制品后测试并提交BUG,这个工作是可以开发过程中就能不断的进行的。保证每一个任务的质量,可以大大减少后期集成的错误量。

另外根据敏捷开发的思想,测试团队在开发过程中也需要加强与开发团队的交流,甚至有必要组成虚拟团队,位置调整到一起,这样可以及时快速的交流,参加开发团队的站立会议同样可以及时了解到开发的实际情况及进度,反过来把握测试计划及测试内容。

特别是测试从另一个角度来审视需求,这样也可以一定程度上发现或者改善需求上的不足。

3、发挥团队人员的潜力

敏捷开发比较提倡开发任务由开发自己评估并认领工作任务,这样可以激发开发的潜在动力。

之前在做一个新产品时,需要使用java,而我们团队是使用C#的,面临转型问题。而有一位同事很感兴趣,于是我就让他负责前期的框架探索与搭建。结果就是这位小伙工作效率很高,我最初给他的目标全部都完成了。最有意思的是后面产品开始研发时,这位小伙已经成为了团队的大牛,大家有问题都找他解决。也正是因为这个过程,这位小伙被全面激活,也在大家面前展示了能力。甚至在小伙离职时也被领导给予大幅涨薪来挽留。只不过谁又能想象到这位小伙进入我团队之前是因为被定为裁员的目标而调剂过来的呢!

所以充分发挥好每个人员的特点,让人能够在自己感兴趣的工作中,效果会很多。减少指派方式的任务的分配,充分发挥个人的主动性,这个团队精神面貌也会好很多。

4、管理者不要离团队太远

作为团队的Leader要参与到团队的工作中去,比如一个开发主管一定要写写代码,参与架构等对项目有关的事情,而不是在那里分分任务。这样团队成员才会觉得这个Leader很亲近感。

特别是有些开发主管在带队后离团队越来越远,有时对于开发进度不如意时就说:“这么个简单功能怎么会搞了这么久?”,其实每天都在加班的同事心里想着:“有本事你来?”,即使这个小组长有这个能力,但对于团队来说也不是一件好事,因为大家都抱有怨恨之心,还谈什么好好工作呢?这个小组长就是失职的。所以这种情况下应该主动去了解进度滞后的原因,并且自己要加入到解决问题的工作中去,而不是在边上抱怨别人。

5、小组织不要搞太多的官

中国几千年的文化,官本位一直影响着我们,大家都想坐在那指挥,自己啥事也不用干,想想都惬意。在我们这个行业是不是发现也很类似?大家都想着干几年当个小组长,然后升个部门经理,当上CTO迎娶白富美。

团队的管理基本是事与人的管理,非常的伤脑和心。如果一个组织内,特别是小组织内“官”太多,协调就会非常的难,大家就会经常性的扯皮。

结束

敏捷开发的推理

符合现实的软件

软件是为着解决现实的问题而产生的。从而软件存在的意义就是与现实相适应。敏捷开发的核心即:符合现实的软件。一个符合现实的软件,才能够可持续地与现实共同发展。一旦软件与现实背离,软件的生命周期也就到了结束的时候了。

现实的世界是动态变化的,人类造出来的东西,往往是落后于世界的变化的。如,地图造出来之后,可能又多修了几条路,几个建筑;刚买了一款高配置的计算机,几个月后,自己的机器配置又处于被甩的地位了……这些变化,人是被迫要去接受。因为这些东西属于硬件,人在目前还无法轻易地改变硬件。

而与此不同的软件,则是另外一种现象了。改变软件的代价是相当低廉的。改变软件,实际上只是改变硬盘上的磁性。改变软件的容易性,带来的结果是: 一、软件开发者容易以自己的想象来决定软件怎么做。 开发出一个无用的软件,比起因为出错而要毁掉待出售的10万张地图,比起因为工艺漏洞而要招回已经出售的计算机来讲,代价太低廉了。 二、软件更加具备符合现实的条件。 开发者让软件与现实相适应,所要付出的代价非常低廉。

所以,敏捷开发的核心就是符合现实的软件。为了造出符合现实的软件,才有了进一步的价值观及方法论。

简单

简单,是在人认识到事物的本质的时候才能够获得的。在开发软件的时候,我们往往疲于应付各种各样的需求。很少有人能够将复杂的需求化为简单的概念。比如,做一个音乐软件,有“我喜欢的”、“最近播放”、“最新添加”等不同的性质的歌。有些开发者会做出三个列表来存放三种性质的歌。而实际上他们的本质是一样的,即播放列表。区别在于触发加入播放列表的条件不同而已。因而只需要做一个列表,在列表中标记每首歌的触发条件。

把软件做得很复杂,通常说明软件所抓住的本质还很少。需要再好好考虑一下如何进一步进行简化。软件的概念简单,一方面可以让用户很容易理解和操作;另一方面能够适应世界的变化。再拿以上的音乐软件来说。如何做成三个列表,再要加一个“听了又听”的歌,又得创建一个列表。而使用一个列表的方法,则只需要处理“听了又听”这个触发条件。

符合现实的软件必然是简单的。所以,敏捷开发的第一条价值观是:简单。我们在实施敏捷开发的时候,都是围绕“简单”这一价值观而进行实施的。即,时刻保证软件的简单性。简单性包括两个方面:一是对于用户而言,概念很简单;二是对于开发者而言,开发的技术及代码很简单。

软件的可持续性也取决于软件是否简单。可持续性是指,快速响应现实的变化。一个复杂的软件,要么让用户无所适从,要么让代码无法维护。这都将导致软件无法持续。这会迫使我们以制造硬件的方式来开发软件。硬件是在迫不得已的情况下才丢掉重新升级(计算机在实在没有办法用的时候,才买新的),要让软件也这样做,软件开发低廉代价的优势就白白浪费掉了。

反馈

一个软件要符合现实,就需要通过现实的反馈来发展。软件前进的动力是现实的反馈。敏捷开发是欢迎现实,拥抱变化的开发。强调该条价值观,是为了消除开发者容易犯的错误——以自己的想象去决定软件怎么做。

因而,在做一个软件之前,首先要找到能够给出反馈的人。如果连能够给出反馈的人都没有,那么这个软件就没有做的必要了。

反馈的重要性,更可以这样说:矛盾推动事物的发展。反馈是指出不足的矛,软件是弥补不足的盾。在矛的不断攻击之下,盾才能不断完善。矛之不存,盾何以壮。

在方法论上面,敏捷开发强调快速发布版本,取得现实的反馈而不是开发者大脑中自己想像的反馈。如果开发者正好也是使用者,那么软件做成的几率就要大很多。开源软件大多数都是开发者自己要解决问题而产生的。

沟通

沟通是开发者取得反馈的手段。一个优秀的开发者,是善于沟通的。沟通包含口语、写文档等各种方式。优秀的开发者应该能够清晰而有条理地表达自己的想法。

现实世界中,人们普遍认为:软件开发者因为跟机器打交道,从而是内向的,不善于沟通的。实际上,这样的开发者不能算是优秀的。他们所做的事情,更多地是把需求转化为计算机语言的工作,即翻译员。而现在都出来谷歌翻译了,人类语言翻译成计算机语言只是时间问题了。

沟通的目的是进行思想碰撞。在沟通当中了解别人的思维方式,表达自己的思维方式,进一步扬弃为更加优秀的思维方式。在优秀的思维方式之下才能保持让自己与现实相符合。优秀的开发者是不会放弃获取优秀的思维方式的机会的。

在敏捷开发当中,提出这一价值观,正是要开发者变得优秀。放弃优秀的开发者无法适应敏捷开发。

勇气

在现实生活中,缺乏勇气比较常见。比如,不敢大大方方地表白,不敢尝试新的事物……在软件开发领域,缺乏勇气更是常见:技术更新好几代了,公司还不敢使用新技术;公司不敢尝试新的开发模式(敏捷开发)……

勇气,本质上来讲,是对现状的否定。人们往往一厢情愿地相信永恒;一旦确定,就不愿意改变。这正是勇气的用武之地。勇气使人去否定永恒,拥抱改变。勇气是创造的源泉。人没有勇气,人就永远是他现在的这样了,正是勇气才迫使他去改变。

在开发的时候,我们可能花了很多时间写了很多代码,但要决定放弃已经写过的所有代码,这是非常需要勇气的。而如果能够做到这一点,在软件开发上就占据了非常有利的位置。比如,我们可能会花大量时间去写页面原型,以希望能够得到用户反馈。在确定得到用户反馈之后,我们可以完全放弃原型代码,进而可以得到更加符合现实(也更加简单)的代码。

敏捷开发强调勇气这一价值观,正是要开发者去拥抱现实的变化,让开发者及软件朝着符合现实的路线走。

迭代开发

讲完四个价值观之后,接下来我把四个价值观联系起来,得到一个方法论——迭代开发。

如图所示,简单是软件开发的起点,也是软件开发的终点。

说它是起点,是因为,如果开发的东西还是复杂的,那就有必要把概念弄得简单一些。这包含两个方面的行动:一、把复杂的系统砍掉一半的功能(广度上);二、尽可能对各个功能进行抽象(深度上,参考前面音乐软件的例子)。

接下来,我们拿着简单的软件(或者软件原型)进入沟通环节。我们可以在两个方面进行沟通:一、与用户沟通软件的逻辑是否满足要求;二、与开发者沟通软件是否在技术上代价很高,如何权衡。

沟通之后,我们可以得到现实的反馈,在现实的反馈之下,我们才有勇气进行改变,使用我们的软件继续维持其简单性。这就完成了软件的一个迭代。

敏捷方法

Scrum

Scrum是和种迭代式及递增式的敏捷软件开发框架,它用于管理软件项目,产品,或程序的开发。它的着重点是一个灵活的,全面的产品开发策略,它把一个开发团队通常作为一个单位进而实现一个常规目的。相反,它不着重于传递的序列化式的方法。Scrum会问传统瀑布式开发“为什么我们要花费这么长时间,这么多努力去做一件事?为什么我们不能衡量出做一件事所需时间和人力?” Scrum拥抱变化和创造力,因为这是人们的工作方式。Scrum有一个流程学习结构,能够让团队评估他们做了什么以及他们怎样做的。

Scrum角色

产品持有人 Product Owner

###### 产品持有人代表着公司或股东的权益并传递客户的声音。

###### 专门负责确保商业价值

###### 制定以客户为中心的一些工作条目,排序后放到产品待处理列表(Product backlog)中。

###### Scrum团队应该有一个产品持有人,他/她也可以是开发团队中的一员。

###### 产品持有人不是Scrum领导者(ScrumMaster)。

开发团队 Development Team

###### 在每一个Sprint周期结束后,负责交付将来需要发布的产品的模块。

###### 由3到9人组成并拥有各种所需技能(分析,设计,开发,测试,技术沟通,文档,等等)。

###### 自我组织,有可能需要与更高级的项目管理部门交流。

Scrum领导人 ScrumMaster

###### 专门负责扫清团队在交付Sprint目标或产品中遇到的障碍。

###### 不是团队领导人,但是扮演着团队与可能分散团队注意力的影响之间的缓冲区。

###### 确保Scrum流程的使用在计划中。

###### 规则强制执行人。团队保护者,以保持团队专注于他们手中的工作。

###### 也会被看作一个人民公仆去加强这些双重观点。

###### 不同于一个项目经理,没有与ScrumMaster不相关的人员管理职责

###### 没有任何额外的员工责任。

会议

1、Sprint计划会议

###### Sprint是短距离赛跑的意思,这里面指的是一次迭代,而一次迭代的周期是1个月时间(即4个星期),也就是我们要把一次迭代的开发内容以最快的速度完成它,这个过程我们称它为Sprint。

2、每日例会

#######

3、Sprint评审会议

#######

4、Sprint回顾会议

#######

三个构件

1、产品Backlog 产品Backlog指根据初始需求分解出的任务列表,包括功能性和非功能性的所有功能。

###### Backlog未完成项列表

  • 产品的待完成项列表是一个需求的排列列表,我们维护这个列表是为了更好的开发产品。它的组成有功能,BUG修复,非功能需求等任何为了成功发布可用软件系统的所必须的内容。在Scrum中,开始一个项目不必先开发一个冗长文档去记录所有的需求。这个敏捷产品backlog对于第一个Sprint足够了。当有更多产品需求时和客户需求时,Scrum产品backlog允许变更和增加。

  • Sprint backlog是开发团队下个Sprint需要处理的工作列表。这个列表是产品backlog最上面的需求项衍生出来的,直到开发团队在这个Sprint中有足够的工作去做。开发团队通过问一些问题来完成backlog的选择,如“我们是不是也能做这个?”。

  • 从概念上讲,团队从优先级最高的Scrum backlog开始画一条线划分出优先级较低的项,同时线上面的backlog也是团队认为他们可以完成的项。在实践中,团队通常不会去选择优先级最高的五项再选择优先级较低的两项组合在一起即使它们是互相关联的。

2、Sprint Backlog Sprint Backlog就是任务列表,如果映射到传统的项目管理理论中就是WBS(work breakdown structure),而且是典型的采用面向交付物的任务分解方法得到的WBS。

###### 任务看版包含 未完成、正在做、已完成 的工作状态,假设你今天把一个未完成的工作已经完成,那么你要把小卡片从未完成区域贴到已完成区域。

3、燃尽图。

完成Scrum敏捷开发的流程为:

第一步:Product Backing 找出完成产品需要做的事情。
第二步:Sprint Backlog 决定当前冲刺需要解决的事情。
第三步:Sprint 冲刺。

###### 1.我昨天做了什么。

###### 2.我今天要什么。

###### 3.我碰到了哪些问题。

第四步:得到软件的一个增量版本,发布给用户。然后在此基础上进一步计划增量的新功能和改进。

Scrum开发的一些注意事项:

1、我们首先需要确定一个Product Backlog(按优先顺序排列的一个产品需求列表),这个是由Product Owner 负责的;
2、Scrum Team根据Product Backlog列表,做工作量的预估和安排;
3、有了Product Backlog列表,我们需要通过 Sprint Planning Meeting(Sprint计划会议) 来从中挑选出一个Story作为本次迭代完成的目标,这个目标的时间周期是1~4个星期,然后把这个Story进行细化,形成一个Sprint Backlog;
4、Sprint Backlog是由Scrum Team去完成的,每个成员根据Sprint Backlog再细化成更小的任务(细到每个任务的工作量在2天内能完成);
5、在Scrum Team完成计划会议上选出的Sprint Backlog过程中,需要进行 Daily Scrum Meeting(每日站立会议),每次会议控制在15分钟左右,每个人都必须发言,并且要向所有成员当面汇报你昨天完成了什么,并且向所有成员承诺你今天 要完成什么,同时遇到不能解决的问题也可以提出,每个人回答完成后,要走到黑板前更新自己的 Sprint burn down(Sprint燃尽图);
6、做到每日集成,也就是每天都要有一个可以成功编译、并且可以演示的版本;很多人可能还没有用过自动化的每日集成,其实TFS就有这个功能,它可 以支持每次有成员进行签入操作的时候,在服务器上自动获取最新版本,然后在服务器中编译,如果通过则马上再执行单元测试代码,如果也全部通过,则将该版本 发布,这时一次正式的签入操作才保存到TFS中,中间有任何失败,都会用邮件通知项目管理人员;
7、当一个Story完成,也就是Sprint Backlog被完成,也就表示一次Sprint完成,这时,我们要进行 Srpint Review Meeting(演示会议),也称为评审会议,产品负责人和客户都要参加(最好本公司老板也参加),每一个Scrum Team的成员都要向他们演示自己完成的软件产品(这个会议非常重要,一定不能取消);
8、最后就是 Sprint Retrospective Meeting(回顾会议),也称为总结会议,以轮流发言方式进行,每个人都要发言,总结并讨论改进的地方,放入下一轮Sprint的产品需求中;

需求收集

1.1 需求的分类

###### 需求可与分为业务团队的,也可以包括团度内部的,比如性能优化。

1.2 需求提交模板

###### 需求种类 优先级 需求类型 需求标题 详细描述 验收条件 价值验证 提交时间 需求人 备注

  • ① 需求种类 可从以下四种情况中选择

    • – 概念想法

    • – 可用性问题(Bug)

    • – 任务

    • – 性能问题

    • 注意:即使是概念性的想法,目前技术上无法实现的想法都可以收集。

② 优先级 可从以下五种情况中选择

###### – 普通

###### – 非常重要

###### – 特别的严重

###### – 很重要

###### – 低

###### 注意:切忌将所有的任务的优先级都设置的非常的高,这里不提供非常紧急这样的表述。我们只会根据重要程度去执行任务,所以紧急的任务需要业务部门及需求方尽早的提出。

③ 需求类型 可以是两种类型

###### – 毛坯需求

###### – 详细需求

###### 注意:我们的需求并不是要求一定要完整的,及时是一些非常毛坯的需求,也可以提交过来,毛坯的需求由产品负责人进行分析和梳理,暂不清楚的可选择搁置。

④ 需求标题 有自己进行书写,但是需要遵守的规范是采用动宾短语格式。

###### 比如:“导出+CN酒店每天的PV、UV等流量数据”

###### 注意:这里的需求内容一定是站长使用者角度是提出的,切勿出现专业的程序方面的表述:如添加一个导出的按钮。还有需要注意的是动词切忌使用大而宽泛的词,比如“管理”,类似“管理关键词”这样的需求是严格避免的,这样会使得要开发的内容变得没有清晰的边界。

⑤ 详细描述 需要按照用户故事的格式进行书写。具体用户故事格式的要求如下:

###### 活动:需要完成什么样的功能。

###### 角色:谁要使用这个功能。

###### 商业价值:为什么需要这个功能,这个功能带来什么样的价值。

用户故事是从用户的角度来描述用户渴望得到的功能。需要注意的是用户故事不能够使用技术语言来描述,要使用用户可以理解的业务语言来描述。一个好的用户故事包括三个要素:

###### 活动:需要完成什么样的功能。

###### 角色:谁要使用这个功能。

###### 商业价值:为什么需要这个功能,这个功能带来什么样的价值。

用户故事通常按照如下的格式来表达:作为一个<角色>, 我想要<活动>, 以便于<商业价值>
比如:作为一名酒店前端开发人员,我期望查看所有酒店页面的页面打开时间,以便了解哪些页面需要进行技能优化。
一个好的用户故事同时要符合INVEST原则,INVEST原则分别是:

###### 短小(Small): 一个好的故事在工作量上要尽量短小,最好不要超过8个人/天的工作量,至少要确保的是在一个迭代能够完成。用户故事越大,在安排计划,工作量估算等方面的风险就会越大。

###### 有价值(Valuable): 每个故事必须对客户具有价值。一个让用户故事有价值的好方法是让客户来写下它们。一旦一个客户意识到这是一个用户故事并不是一个契约而且可以进行协商的时候,他们将非常乐意写下故事。

###### 独立性(Independent): 要尽可能的让一个用户故事独立于其他的用户故事。用户故事之间的依赖使得制定计划,确定优先级,工作量估算都变得很困难。通常我们可以通过组合用户故事和分解用户故事来减少依赖性。

###### 可协商性(Negotiable): 一个用户故事的内容要是可以协商的,用户故事不是合同。一个用户故事卡片上只是对用户故事的一个简短的描述,不包括太多的细节。具体的细节在沟通阶段产出。一个用户故事带有了太多的细节,实际上限制了和用户的沟通。

###### 可以估算性(Estimable):开发团队需要去估计一个用户故事以便确定优先级,工作量,安排计划。但是让开发者难以估计故事的问题来自:对于领域知识的缺乏(这种情况下需要更多的沟通),或者故事太大了(这时需要把故事切分成小些的)。

###### 可测试性(Testable): 一个用户故事要是可以测试的,以便于确认它是可以完成的。如果一个用户故事不能够测试,那么你就无法知道它什么时候可以完成。

注意:
角色的范围不能过大,比如是作为一名“用户”,这样是的不被接受的。
商业价值也不能大而宽泛,比如,能为公司创造业绩。如果要写也一定要对业绩做初步估算,比如,预期会给公司带来每月1万张订单。
⑥ 验收条件 是开发完成后检验的标准,所以一定要认真填写,否则可能开发出来的东西与预期不达标。

###### 4) 对于导出数据做好日志记录,后期可查是谁进行了导出。

###### 2) 导出的时间可以细化的天。即可导出每天的流量。

###### 以上面的“导出+CN酒店每天的PV、UV等流量数据”为例,它的验收条件可以为:

###### 1) 可以为每个用户设置是否拥有此导出权限

###### 3) 导出数据的最大时间跨度为31天

###### 5) 导出的字段包括:PV、UV、跳出率、新访客占比。

⑦ 价值验证 说明如何跟踪上线后的效果

Sprint 计划会议 1

目标:定出 Sprint 目标和既定产品 Backlog。
2.1 会议准备

Sprint 验收会议的时间安排

Sprint 的最后一天已确定

Sprint 计划会议 2 的时间安排

Sprint 时间表已经安排

开发团队

产品负责人

在会议前一天确定议程,将目标和议程发送给所有与会者

投影仪

所有会议资源都已预订

会议室

笔记本

原始需求人(可选择不来)

Scrum Master

已按优先级排列产品 Backlog整理完毕

Sprint 计划会议 1 的时间安排

Sprint 的第一天已确定

Scrum 每日例会的时间安排

Sprint 回顾会议的时间安排

2.2 会议议程

如果对需求的优先级存在异议,可会上讨论,确定最终的执行顺序。

产品负责人或者原始需求者负责解答不清楚的故事点。

产品负责人向团队产品阐述需求(用户故事)

把 Sprint 时间表公开给所有人

开发人员对用户故事不清楚的点可以及时提出。

如果讨论现场发现有遗漏的需求,可由产品负责人添加至产品Backlog。

产品负责人& 需求方和小组成员相互认可这 Sprint 目标和既定产品 Backlog

2.3 会议结果

为 Sprint 计划会议2的进行准备好既定产品 Backlog

2.4 补充内容

###### 需求种类 优先级 需求类型 需求标题 详细描述 验收条件 提交时间 需求人 备注 跟进人 预计完成时间 实际完成时间 Sprint版本号 处理情况

###### 产品Backlog模板(基本同需求模板)

###### 处理情况可从以下几种类型中选择

  • – 暂时搁置

  • – 已经完成

  • – 等待处理

  • – 正在进行

  • – 不予处理

  • – 需要讨论

Sprint 计划会议 2

目标:确定所有任务,生成 Sprint Backlog,确认 Sprint 目标

3.1 会议准备

Sprint 计划会议1中整理的既定产品 Backlog

开发团队

产品负责人

要求原始需求者离开会议,参会人员为

Scrum Master

在Sprint 计划会议1后10分钟举行

任务估时牌(按1,2,3,5,8,13估算)

3.2 会议进程

如果团队评估下来任务过多,可和产品负责人一起删减任务

可看情况确定是否使用扑克估时

部署

学习新技术

测试

团队成员按顺序分析既定产品 Backlog的讨论实现细节

编码

代码审核

编写文档

上传

任务超过一天时,需要拆成多个小任务

如果团队评估下来任务过少,可和产品负责人一起从产品Blaclog中引入新的需求。

3.3 会议结果

将最终确认的可完成的需求清单邮件至

  • □ Scrum Master

  • □ 原始需求人

  • □ 产品负责人

  • □ 开发团队

将最终确认的任务列表邮件至

  • □ Scrum Master

  • □ 产品负责人

  • □ 开发团队

3.4 补充内容

优先级 需求标题 详细描述 验收条件 需求人 跟进人 处理人 任务描述 处理日期 估时 实际耗时

Sprint Backlog模板

需求和任务是一对多的关系,及一个需求可以产生多个任务,任务可以是程序类描述,如“数据数据库设计”

Scrum 每日例会

目标:团队成员间工作进度的沟通和协调
4.1 会议准备

在 Sprint Backlog 上的所有任务都是可以增删修改,可重排序的

外部团队协助人员(如有有需要的话)

邀请与会者

原始需求人(只有选择是否参加,过程中不可发言)

一台电脑,中间标识任务的状态,可设为“待处理”,“正在处理”,“已完成”的。

4.2 会议进程

如果相关人员想发表些言论

如果展开了一个问题的讨论

有什么问题阻碍了你的开发

如果任务可以在一天内完成:把任务状态设为“正在处理”

如果任务不在 Sprint Backlog 上:添加这个任务

下一次会议之前,你计划完成什么任务?

上次会议时的任务哪些已经完成?

###### – 会议限定在15分钟内

###### 注意:

###### – 团队里的每个成员都必须回答以下三个问题,并考虑其相关的行动。

###### □把任务从“正在处理”状态转为“已完成”状态

如果任务状态为“待处理”:转为“正在处理”状态

如果任务不能在一天内完成:把这任务细分成多个任务

如果任务状态已经是“正在处理”:询问是否存在阻碍任务完成得问题

如果有阻碍你开发进度的问题:把该障碍加入到障碍 Backlog 中,Scrum Master负责记录

提醒团队的成员们注意把精力集中在回答关键问题上

礼貌地提醒他,该会议只允许让小组成员讨论

4.3 会议结果

###### 4.4 障碍Backlog

最新的工作进度图(燃尽图)

得到最新的障碍 Backlog

得到最新的 Sprint Backlog

第一次的例会创建一封邮件,由Scrum Master会议后将例会内容回复此邮件。

###### 障碍 Backlog 列举了所有团队内部和团队相关的和阻碍项目进度的问题。Scrum Master 需要确保所有的障碍 Backlog 中的问题都已分配并可以得到解决。

  • 10 大典型障碍

    • – 团队的 Sprint Backlog 混乱

    • – 团队人数过多

    • – 并不是所有负责交付产品的人员都是团队里的成员

    • – 没有产品负责人负责回答提问

    • – 会议规则没能被遵循

    • – 产品远景和 Sprint 目标不清晰

    • – 产品 Backlog 未能按商业价值区分优先级

    • – Scrum Master 还要处理其他任务,不能集中精力

    • – 团队没有能坐在一起工作的空间

    • – 中间遇到了技术难题

Sprint 验收会议

目标:根据团队这次 Sprint 所发布的版本,评审相关的 Backlog 中的问题,检查是否已达到 Sprint 的目标。
5.1 会议准备

对于每个人来说 Sprint 目标都是公开的

Scrum Master

原始需求人(可选择不来)

笔记本

会议室

所有会议资源都已预订

投影仪

在会议前一天确定议程,将目标和议程发送给所有与会者

产品负责人

开发团队

对每个人来说既定产品 Backlog 是公开的,可获取的

5.2 会议进程

如果对功能有一个新的想法:添加一个新问题到产品 Backlog 中

团队按 Backlog 中的问题,逐个地介绍这次 Sprint 的结果,和演示新功能。

如果产品负责人或需求方想要改变功能:添加一个新问题到产品 Backlog 中

如果小组报告项目遇到阻碍现在还没能解决:把该障碍加入到障碍 Backlog

5.3 会议结果

对这次 Sprint 的结果和整个产品的开发状态的共识

Sprint 回顾会议

目标:通过总结以往的实践经验来提高团队生产力。
注意:主要指导原则:不管我们现在发现了什么问题,我们必须懂得并坚信每个人通过他们当时所知的,他所拥有的技能和可得到的资源,在限定的环境下,都尽其所能做出了最好的成绩。
6.1 会议准备

在白板上写上“谁负责”,然后分成两个区域——“团队”和“公司”

在白板上写上“我们的成功经验是什么”

在白板上写上主要指导原则

便签纸

产品负责人(可选)

Scrum Master

邀请与会者:

团队所有成员

附属工具

白板

在白板上画上一个至少三页纸连在一起长的时间轴

在白板上写上“有什么能够改进”

###### 附属工具:

6.2 会议进程

给会议做个总结

把便签纸移到挂纸板中“谁负责”的区域中

对于挂纸板上“有什么能够改进”的区域中的每一项

分发便签纸,并让每人写上“有什么能够改进的”,限时5分钟

分发便签纸,并让每人写上“我们的成功经验是什么”,限时5分钟

派发便签,并且让每人写上他们认为这次 Sprint 中最为重要的事,限时 5 分钟

在时间轴上,标记出 Sprint 的开始和结束时间

介绍会议目标

介绍会议主要指导原则

向与会者解说如何使用该便签纸进行工作

每个与会者轮流把他的贴纸贴到白板的时间轴上,并用两句话来解说这事有什么特别的地方

每个与会者轮流把他的贴纸贴到白板“我们的成功经验是什么”的区域上,并解说。

每个与会者轮流把他的贴纸贴到白板“有什么能够改进的”的区域上,并解说。

询问团队“谁去负责解决这个问题?”

和团队一起把这些区域按优先次序排好

###### □每个与会者对 Sprint 回顾会议作简短的回馈

6.3 会议结果

把与团队范围相关的障碍增加到障碍 Backlog 中去

白板上“谁负责”这栏对于公司内所有人是公开的

把与公司范围相关的障碍增加到障碍 Backlog 中去

整理所有会议结果,邮件至团队中所有人

极限编程XP

极限编程是一个轻量级的、灵巧的软件开发方法;

同时它也是一个非常严谨和周密的方法。 它的基础和价值观是交流、朴素、反馈和勇气; 即,任何一个软件项目都可以从四个方面入手进行改善:加强交流; 从简单做起;寻求反馈;勇于实事求是。 XP是一种近螺旋式的开发方法,它将复杂的开发过程分解为一个个相对比较简单的小周期; 通过积极的交流、反馈以及其它一系列的方法, 开发人员和客户可以非常清楚开发进度、变化、待解决的问题和潜在的困难等,并根据实际情况及时地调整开发过程。

开发人员知道要做什么,以及要优先做什么;
工作有效率;
有问题或困难时,能得到客户、同事、上级的回答或帮助;
对工作做评估,并根据周围情况的变化及时重新评估;
积极承担工作,而不是消极接受分配;
一周40小时工作制,不加班。

与其他方法论相比,其最大的不同在于

在更短的周期内,更早地提供具体、持续的反馈信息。
在迭代的进行计划编制,首先在最开始迅速生成一个总体计划,然后在整个项目开发过程中不断的发展它。
依赖于自动测试程序来监控开发进度,并及早地捕获缺陷。
依赖于口头交流、测试和源程序进行沟通。
倡导持续的演化式设计。
依赖于开发团队内部的紧密协作。
尽可能达到程序员短期利益和项目长期利益的平衡。

四大价值观

XP的核心是其总结的沟通、简单、反馈、勇气四大价值观,它们是XP的基础,也是XP的灵魂。
1. 沟通

###### 通畅程序员给人留下的印象就是“内向、不善言谈”,然后项目中的许多问题就出在这些缺乏沟通的开发人员身上。经常由于某个程序员做出了一个设计决定,但是却不能及时地通知大家,结果使得大家在协作与配合上出现了很多的麻烦,而在传统的方法论中,并不在意这种口头沟通不畅的问题,而是希望借助于完善的流程和面面俱到的文档、报表、计划来替代,但是这同时又引入了效率不高的新问题。

###### XP方法论认为,如果小组成员之间无法做到持续的、无间断的交流,那么协作就无从谈起,从这个角度能够发现,通过文档、报表等人工制品进行交流面临巨大的局限性。因此,XP组合了诸如对编程这样的最佳实践,鼓励大家进行口头交流,通过交流解决问题,提高效率。

2. 简单

###### 另外,在XP中提倡时刻对代码进行重构,一直保持其良好的结构与可扩展性。也就是说,可扩展性和为明天设计并不是同一个概念,XP是反对为明天考虑而工作,并不是说代码要失去扩展性

###### 正如对传统开发方法的认识一样,许多开发人员也会质疑XP,保持系统的扩展性很重要,如果都保持简单,那么如何使得系统能够有良好的扩展性呢?其实不然,保持简单的理由有两个:

###### XP方法论提倡在工作中秉承“够用就好”的思路,也就是尽量地简单化,只要今天够用就行,不考虑明天会发现的新问题。这一点看上去十分容易,但是要真正做到保持简单的工作其实很难的。因为在传统的开发方法中,都要求大家对未来做一些预先规划,以便对今后可能发生的变化预留一些扩展的空间。

###### 开发小组在开发时所做的规划,并无法保证其符合客户需要的,因此做的大部分工作都将落空,使得开发过程中重复的、没有必要的工作增加,导致整体效率降低。

###### 而且简单和沟通之间还有一种相对微妙的相互支持关系。当一个团队之间,沟通的越多,那么就越容易明白哪些工作需要做,哪些工作不需要做。另一方面,系统越简单,需要沟通的内容也就越少,沟通也将更加全面。

3. 反馈

###### 在开发过程中,还应该加强集成工作,做到持续集成,使得每一次增量都是一个可执行的工作版本,也就是逐渐是软件长大,整个过程中,应该通过向客户和管理层演示这些可运行的版本,以便及早地反馈,及早地发现问题。

###### 而且在项目的过程中,这样的现象不仅出现在开发团队与客户、管理层之间,还包括在开发团队内部。这一切问题都需要我们更加注重反馈。,反馈对于任何软件项目的成功都是至关重要的,而在XP方法论中则更进一步,通过持续、明确的反馈来暴露软件状态的问题。具体而言就是:

###### 是什么原因使得我们的客户、管理层这么不理解开发团队?为什么客户、管理层总是喜欢给我们一个死亡之旅?究其症结,就是开发的过程中缺乏必要的反馈。在许许多多项目中,当开发团队经历过了需求分析阶段之后,在相当长的一段时间内,是没有任何反馈信息的。整个开发过程对于客户和管理层而言就像一个黑盒子,进度完全是可见的。

###### 在开发团队内部,通过提前编写单元测试代码,时时反馈代码的问题与进展。

###### 同时,我们也会发现反馈与沟通也有着良好的配合,及时和良好的反馈有助于沟通。而简单的系统更有利于测试盒反馈。

4. 勇气

###### 也就是XP方法论要求开发人员穿上强大、自动测试的盔甲,勇往直前,在重构、编码规范的支持下,有目的地快速开发。

###### 在应用XP方法论时,我们每时每刻都在应对变化:由于沟通良好,因此会有更多需求变更的机会;由于时刻保持系统的简单,因此新的变化会带来一些重新开发的需要;由于反馈及时,因此会有更多中间打断你的思路的新需求。

###### 总之这一切,使得你立刻处于变化之中,因此这时就需要你有勇气来面对快速开发,面对可能的重新开发。也许你会觉得,为什么要让我们的开发变得如此零乱,但是其实这些变化若你不让它早暴露,那么它就会迟一些出现,并不会因此消亡,因此,XP方法论让它们早出现、早解决,是实现“小步快走”开发节奏的好办法。

###### 勇气可以来源于沟通,因为它使得高风险、高回报的试验成为可能;勇气可以来源于简单,因为面对简单的系统,更容易鼓起勇气;勇气可以来源于反馈,因为你可以及时获得每一步前进的状态(自动测试),会使得你更勇于重构代码。

5. 四大价值观之外
在这四大价值观之下,隐藏着一个更深刻的东西,那就是尊重。因为这一切都建立在团队成员之间的相互关心、相互理解的基础之上。

5个原则

1. 快速反馈

###### 及时地、快速地获取反馈,并将所学到的知识尽快地投入到系统中去。也就是指开发人员应该通过较短的反馈循环迅速地了解现在的产品是否满足了客户的需求。这也是对反馈这一价值观的进一步补充。

2. 简单性假设

###### 类似地,简单性假设原则是对简单这一价值观的进一步补充。这一原则要求开发人员将每个问题都看得十分容易解决,也就是说只为本次迭代考虑,不去想未来可能需要什么,相信具有将来必要时增加系统复杂性的能力,也就是号召大家出色地完成今天的任务。

3. 逐步修改

###### 就像开车打方向盘一样,不要一次做出很大的改变,那样将会使得可控性变差,更适合的方法是进行微调。而在软件开发中,这样的道理同样适用,任何问题都应该通过一系列能够带来差异的微小改动来解决。

4. 提倡更改

###### 在软件开发过程中,最好的办法是在解决最重要问题时,保留最多选项的那个。也就是说,尽量为下一次修改做好准备。

5. 优质工作

###### 在实践中,经常看到许多开发人员喜欢将一些细小的问题留待后面解决。例如,界面的按钮有一些不平整,由于不影响使用就先不管;某一两个成员函数暂时没用就不先写等。这就是一种工作拖泥带水的现象,这样的坏习惯一旦养成,必然使得代码质量大打折扣。

###### 而在XP方法论中,贯彻的是“小步快走”的开发原则,因此工作质量决不可打折扣,通常采用测试先行的编码方式来提供支持。

13个最佳实践

在XP中,集成了13个最佳实践,有趣的是,它们没有一个是创新的概念,大多数概念和编程一样老。其主要创新点在于提供一种良好的思路,将这些最佳实践结合在一起,并且确保尽可能彻底地执行它们,使得它们能够在最大程度上相互支持,紧接下来,我们就对每一种最佳实践进行一番了解。
1. 计划游戏

###### 开发人员进行估算:首先客户按优先级将用户故事分成必须要有、希望有、如果有更好三类,然后开发人员对每个用户故事进行估算,先从高优先级开始估算。如果在估算的时候,感到有一些故事太大,不容易进行估算,或者是估算的结果超过2人/周,那么就应该对其进行分解,拆成2个或者多个小故事。

###### 好了,明白这些就可以进行计划游戏了。首先客户和开发人员坐在同一间屋子里,每个人都准备一支笔、一些用于记录用户故事的纸片,最好再准备一个白板,就可以开始了。

###### 计划游戏的主要思想就是先快速地制定一份概要的计划,然后随着项目细节的不断清晰,再逐步完善这份计划。计划游戏产生的结果是一套用户故事及后续的一两次迭代的概要计划。

###### “客户负责业务决策,开发团队负责技术决策”是计划游戏获得成功的前提条件。也就是说,系统的范围、下一次迭代的发布时间、用户故事的优先级应该由客户决定;而每个用户故事所需的开发时间、不同技术的成本、如何组建团队、每个用户故事的风险,以及具体的开发顺序应该有开发团队决定。

###### 客户编写故事:由客户谈论系统应该完成什么功能,然后用通俗的自然语言,使用自己的语汇,将其写在卡片上,这也就是用户故事。

###### 确定迭代的周期:接下来就是确定本次迭代的时间周期,这可以根据实际的情况进行确定,不过最佳的迭代周期是2~3周。有了迭代的时间之后,再结合参与的开发人数,算出可以完成的工作量总数。然后根据估算的结果,与客户协商,挑出时间上够、优先级合适的用户故事组合,形成计划。

2. 小型发布

###### XP方法论秉承的是“持续集成,小步快走”的哲学,也就是说每一次发布的版本应该尽可能的小,当然前提条件是每个版本有足够的商业价值,值得发布。

###### 由于小型发布可以使得集成更频繁,客户获得的中间结果也越频繁,反馈也就越频繁,客户就能够实时地了解项目的进展情况,从而提出更多的意见,以便在下一次迭代中计划进去。以实现更高的客户满意度。

3. 隐喻

###### 描述体系结构:体系结构是比较抽象的,引入隐喻能够大大减轻理解的复杂度。例如管道体系结构就是指两个构件之间通过一条传递消息的“管道”进行通信。

###### 发明共享词汇:通过隐喻,有助于提出一个用来表示对象、对象间的关系通用名称。例如,策略模式(用来表示可以实现多种不同策略的设计模式)、工厂模式(用来表示可以按需“生产”出所需类得设计模式)等。

###### 相对而言,隐喻这一个最佳实践是最令人费解的。什么是隐喻呢?根据词典中的解释是:“一种语言的表达手段,它用来暗示字面意义不相似的事物之间的相似之处”。那么这在软件开发中又有什么用呢?总结而言,常常用于四个方面。

###### 寻求共识:也就是鼓励开发人员在寻求问题共识时,可以借用一些沟通双方都比较熟悉的事物来做类比,从而帮助大家更好地理解解决方案的关键结构,也就是更好地理解系统是什么、能做什么。

###### 创新的武器:有的时候,可以借助其他东西来找到解决问题的新途径。例如:“我们可以将工作流看做一个生产线”。

###### 当然,如果能够找到合适的隐喻是十分快乐的,但并不是每种情况都可以找到恰当的隐喻,你也没有必要强求

4. 简单设计

###### 使用Demeter(迪米特)法则:迪米特法则,也称为LoD法则、最少知识原则。也就是指一个对象应当对其他对象尽可能少地了解。用隐喻的方法来解释的话就是“只与你直接的朋友通信”、“不要和陌生人说话”。

###### 首先写测试代码:具体将在后面详细描述。

###### 他认为要想保持设计简单的系统,需要具备简单思考的能力,拥有理解代码和修改的勇气,以及为了消除代码的“坏味道”而定期重构的习惯。

###### 清楚地表现了程序员赋予的所有意图。

###### 能够通过所有的测试程序。

###### 强调简单设计的价值观,引出了简单性假设原则,落到实处就是“简单设计”实践。这个实践看上去似乎很容易理解,但却又经常被误解,许多批评者就指责XP忽略设计是不正确的。其实,XP的简单设计实践并不是要忽略设计,而且认为设计不应该在编码之前一次性完成,因为那样只能建立在“情况不会发生变化”或者“我们可以预见所有的变化”之类的谎言的基础上的。

###### Kent Beck概念中简单设计是这样的:

###### 没有包括任何重复的代码。

###### 包括尽可能少的类和方法

###### 那么如何开始进行简单的设计呢?XP实践者们也总结也一些具体的、可操作的思考方法。

###### 保持每个类只负责一件事:SRP(单一职责原则)是面向对象设计的基础原则之一。

###### 使用CRC卡片进行探索。

5. 测试先行

###### 工匠一:先拉上一根水平线,砌每一块砖时,都与这跟水平线进行比较,使得每一块砖都保持水平。

###### 你会选择哪种工作方法呢?你一定会骂工匠二笨吧!这样多浪费时间呀!然而你自己想想,你平时在编写程序的时候又是怎么做的呢?我们就是按工匠二的方法在工作呀!甚至有时候比工匠二还笨,是整面墙都砌完了,直接进行“集成测试”,经常让整面的墙倒塌。看到这里,你还会觉得自己的方法高明吗?这个连工匠都明白的道理,自己却画地为牢呀。

###### 为了鼓励程序员原意甚至喜欢在编写程序之前编写测试代码,XP方法论还提供了许多有说服力的理由。

###### 如果你在结对编程,那么如果你想出一个好的测试代码,那么你的伙伴一定行。

###### 当你的客户看到所有的测试都通过的时候,会对程序充满前所未有的信心。

###### 测试先行是XP方法论中一个十分重要的最佳实践,并且其中所蕴含的知识与方法也十分丰富。

###### 当你需要进行重构时,测试代码会给你带来更大的勇气,因为你要测试是否重构成功只需要一个按钮。

###### 当所有的测试都通过的时候,你再也不会担心所写的代码今后会“暗箭伤人”,那种感觉是相当棒的。

###### 如果你已经保持了简单的设计,那么编写测试代码根本不难。

###### 不仅我们没有采用工匠一的工作方法,甚至有的时候程序员会以“开发工作太紧张”为理由,而忽略测试工作。但这样却导致了一个恶性循环,越是没有空编写测试程序,代码的效率与质量越差,花在找Bug、解决Bug的时间也越来越多,实际产能大打降低。由于产能降低了,因此时间更紧张,压力更大。你想想,为什么不拉上一根水平线呢?难道,我们不能够将后面浪费的时间花在单元测试上,使得我们的程序一开始就更健壮,更加易于修改吗?不过,编写测试程序当然要比拉一条水平线难道多,所以我们需要引入“自动化测试工具”,免费的xUnit测试框架就是你最佳的选择。

###### 工匠二:先将一排砖都砌完,然后再拉上一根水平线,看看哪些砖有问题,对有问题的砖进行适当的调整。

###### 当我第一次看到“测试先行”这个概念的时候,我的第一感觉就是不解,陷入了“程序都还没有写出来,测试什么呀?”的迷思。我开始天马行空地寻求相关的隐喻,终于找到了能够启发我的工匠,首先,我们来看看两个不同的工匠是如何工作的吧。

6. 重构

###### 实现某个特性之前:尝试改变现有的代码结构,以使得实现新的特性更加容易。

###### 在《重构》一书中,作者Martin Fowler提示我们:在考虑重构时,应该要养成编写并经常运行测试代码的习惯;要先编写代码,再进行重构;把每一次增加功能都当做一次重构的好时机;将每一个纠正错误当做一次重构的重要时机。同时,该书中也列出大量需要重构的情况和重构方法。

###### XP提倡集体代码所有制,因此你可以大胆地在任何需要修改的地方做改动。

###### 在重构中遇到困难,和你结对编程的伙伴能够为你提供有效的帮助。

###### 测试先行让你拥有了一个有效的检验器,随时运行一下就知道你重构的工作是否带来了影响。

###### 重构技术是对简单性设计的一个良好的补充,也是XP中重视“优质工作”的体现,这也是优秀的程序员必备的一项技能。

###### 由于XP在持续集成,因此你重构所带来的破坏很快就能够暴露,并且得以解决。

###### 简单的设计,会给重构带来很大的帮助。

###### 由于在XP项目组中有完整的编码标准,因此在重构前无须重新定义格式。

###### 最后类似地,给还没有足够勇气进行重构的程序员打几剂强心针:

###### 实现某个特性之后:检查刚刚写完的代码后,认真检查一下,看是否能够进行简化。

###### 重构时一种对代码进行改进而不影响功能实现的技术,XP需要开发人员在闻到代码的坏味道时,有重构代码的勇气。重构的目的是降低变化引发的风险,使得代码优化更加容易。通常重构发生在两种情况之下。

7. 结对编程

###### 不过,自从20世纪60年代,就有类似的实践在进行,长期以来的研究结果却给出了另外一番景象,那就是结对编程的效率反而比单独编程更高。一开始虽然会牺牲一些速度,但慢慢的,开发速度会逐渐加快,究其原因,主要是结对编程大打降低了沟通的成本,提供了工作的质量,具体表现在:

###### 系统的任何一个部分都肯定至少有2个人以上熟悉。

###### 结对组合的动态性,是一个企业知识管理的好途径。

###### 而且XP方法论集成的其他最佳实践也能够使得结对编程更加容易进行:

###### 隐喻可以帮助结对伙伴更好地沟通。

###### 结对编程技术被誉为XP保持工作质量、强调人文主义的一个典型的实践,应用得当还能够使得开发团队之前的协作更加流畅、知识交流与共享更加频繁,团队的稳定性也会更加稳固。

###### 简单设计可以使得结对伙伴更了解他们所从事的工作。

###### 编码标准可以消除一些无谓的分歧。

###### 代码总是能够保证被评审过。

###### 几乎不可能有2个人都忽略的测试项或者其他任务

###### 所有的设计决策确保不是由一个人做出的。

###### “什么!两个人坐在一起写程序?那岂不是对人力的巨大浪费吗?而且我在工作时可不喜欢有一个人坐在边上当检察官。”是的,正如这里列举出来的问题一样,结对编程技术还是被很多人质疑的。

8. 集体代码所有制

###### 也就是说,团队中的每个成员都拥有对代码进行改进的权利,每个人都拥有全部代码,也都需要对全部代码负责。同时,XP强调代码是谁破坏的(也就是修改后发生问题),就应该由谁来修复。

###### 由于在XP项目中,集成工作是一件经常性得工作,因此当有人修改代码而带来了集成的问题,会在很快的时间内被发现。

###### 由于每一个代码的修改就是通过了结对的两个程序员共同思考,因此通常做出的修改都是对系统有益的。

###### 集成代码所有制是XP与其他敏捷方法的一个较大不同,也是从另一个侧面体现了XP中蕴含的很深厚的编码情节。

###### 由于大家都坚持了相同的编码标准,因此代码的可读性、可修改性都会比较好,而且还能够避免由于命名法、缩进等小问题引发经常性得代码修改。

###### 由于每一个类都会有一个测试代码,因此不论谁修改了代码,都需要运行这个测试代码,这样偶然性的破坏发生的概率将很小。

###### 由于在XP中,有一些与之匹配的最佳实践,因此你并无须担心采用集体代码所有制会让你的代码变得越来越乱:

###### 由于XP方法论鼓励团队进行结对编程,而且认为结对编程的组合应该动态地搭配,根据任务的不同、专业技能的不同进行最优组合。由于每个人都肯定会遇到不同的代码,所以代码的所有制就不再适合于私有,因为那样会给修改工作带来巨大的不便。

9. 持续集成

###### 这样,就可以及早地暴露、消除由于重构、集体代码所有制所引入的错误,从而减少解决问题的痛苦

###### 在前面谈到小型发布、重构、结对编程、集体代码所有制等最佳实践的时候,我们多次看到“持续集成”的身影,可以说持续集成是对这些最佳实践的基本支撑条件。

###### 可能大家会对持续集成与小型发布代表的意思混淆不清,其实小型发布是指在开发周期经常发布中间版本,而持续集成的含义则是要求XP团队每天尽可能多次地做代码集成,每次都在确保系统运行的单元测试通过之后进行。

###### 要在开发过程中做到持续集成并不容易,首先需要养成这个习惯。而且集成工作往往是十分枯燥、烦琐的,因此适当地引入每日集成工具是十分必要的。XP建议大家首先使用配置管理服务器将代码管理起来,然后使用Ant或Nant等XP工具,编写集成脚本,调用xUint等测试框架,这样就可以实现每当程序员将代码Check in到配置服务器上时,Ant就会自动完成编译和集成,并调用测试代码完成相应的测试工作。

10. 每周工作40小时

###### Kent Beck认为开发人员即使能够工作更长的时间,他们也不该这样做,因为这样做会使他们更容易厌倦编程工作,从而产生一些影响他们效能的其他问题。因此,每周工作40小时是一种顺势行为,是一种规律。其实对于开发人员和管理者来说,违反这种规律是不值得的。

###### 管理者:也许这可以称得上“第二种人月神话”,那就是你不得不通过延长每天的工作时间来获得更多的人月。这是因为,每个开发人员的工作精力是有限的,不可能无限增长,在精力不足的时候,不仅写出来的代码质量没有保障,而且还可能为项目带来退步的效果。因此采用加班的方式并不是一个理性的方式,是得不偿失的。

###### 不过有一点是需要解释的,“每周工作40小时”中的40不是一个绝对数,它所代表的意思是团队应该保证按照“正常的时间”进行工作。那么如何做到这一点呢?

  • 其次,逐步将工作时间调整到“正常工作时间”。

  • 最后,鼓起勇气,制定一个合情合理的时间表。

  • 正如米卢说过的“享受足球”一样,同样地,每一个开发人员应该做到“享受编程”,那么“每周工作40小时”就是你的起点。

  • 再次,除非你的时间计划一团糟,否则不应该在时间妥协。

  • 首先,定义符合你团队情况的“正常工作时间”。

###### 开发人员:如果不懂得休息,那么就无法将自己的节奏调整到最佳状态,那么就会带来很大的负面影响。而且在精神不集中的状态下,开发质量也得不到保证。

###### 这是最让开发人员开心的、管理者反对的一个最佳实践了,加班、再加班早已成为开发人员的家常便饭,也是管理者最常使用的一种策略,而XP方法论认为,加班最终会扼杀团队的积极性,最终导致项目失败,这也充分体现了XP方法关注人的因素比关注过程的因素更多一些。

11. 现场客户

###### 也许有人会问,客户提交了用户故事之后不就完成工作了吗?其实很多尝试过用户故事的团队都会发现其太过简单,包含的信息量极少,XP方法论不会不了解,因此,不会把用户故事当做开发人员交付代码的唯一指示。用户故事只是一个起点,后面的细节还需要开发人员与客户之间建立起来的良好沟通来补充。

###### 其实现场客户在具体实施时,也不是一定需要客户一直和开发团队在一起,而是在开发团队应该和客户能够随时沟通,可以是面谈,可以是在线聊天,可以是电话,当然面谈是必不可少的。其中的关键是当开发人员需要客户做出业务决策是,需要进一步了解业务细节时能够随时找到相应的客户。

###### 当开发组织中已经有相关的领域专家时。

###### 去尝试吧,现场客户不仅可以争取得到,而且还能使得团队焕然一新,与客户建立起良好的合作与信任。

###### 当做一些探索性工作,而且客户也不知道他想要什么时(例如新产品、新解决方案的研究与开发)。

###### 不过,也有一些项目是可以不要现场客户参与的:

###### 作为一名有经验的开发人员,绝对不会对现场客户的价值产生任何怀疑,但是都会觉得想要实现现场客户十分困难。要实现这一点,需要对客户进行沟通,让其明白,想对于开发团队,项目成功对于客户而言更为重要。而现场客户则是保障项目成功的一个重要措施,想想在你装修房子的时候,你是不是常常在充当现场客户的角色呢?其实这隐喻就是让客户理解现场客户重要性最好的突破口。

###### 为了保证开发出来的结果与客户的预想接近,XP方法论认为最重要的需要将客户请到开发现场。就像计划游戏中提到过的,在XP项目中,应该时刻保证客户负责业务决策,开发团队负责技术决策。因此,在项目中有客户在现场明确用户故事,并做出相应的业务决策,对于XP项目而言有着十分重要的意义。

12. 编码标准

###### 不过,XP方法论的编码标准的目的不是创建一个事无巨细的规则表,而是只要能够提供一个确保代码清晰,便于交流的指导方针。

###### 如果你的团队已经拥有编码标准,就可以直接使用它,并在过程中进行完善。如果还没有,那么大家可以先进行编码,然后在过程中逐步总结出编码规则,边做边形成。当然除了这种文字规范以外,还可以采用一些如自动格式化代码工具之类的方法进行代码规范。,事实上,你只需要很好地贯彻执行其他的实践并且进行沟通,编码标准会很容易地浮现出来。

###### 编码标准是一个“雅俗共享”的最佳实践,不管是代表重型方法论的RUP,PSP,还是代表敏捷方法论的XP,都认为开发团队应该拥有一个编码标准。XP方法论认为拥有编码标准可以避免团队在一些与开发进度无关的细节问题上发生争论,而且会给重构、结对编程带来很大麻烦。试想如果有人将你上次写的代码的变量命名法做了修改,下次你需要再改这部分代码时,会是一种什么感觉呢?

13. 配合是关键
有句经典名言“1+1>2”最适合表达XP的观点,Kent Beck认为XP方法论的最大价值在于在项目中融会贯通地运用12个最佳实践,而非单独地使用。你当然可以使用其中的一些实践,但这并不意味着你就运用了XP方法论。XP方法论真正能够发挥其效能,就必须完整地运用12个实践。

水晶方法

水晶方法,Crystal ,

是由 Alistair Cockburn 和 Jim Highsmith 建立的敏捷方法系列, 其目的是发展一种提倡“机动性的”方法, 包含具有共性的核心元素,每个都含有独特的角色、过程模式、工作产品和实践。 Crystal 家族实际上是一组经过证明、对不同类型项目非常有效的敏捷过程, 它的发明使得敏捷团队可以根据其项目和环境选择最合适的 Crystal 家族成员。 水晶系列与XP一样,都有以人为中心的理念,但在实践上有所不同。

七大特征

体系特征一:经常交付
体系特征二:反思改进
体系特征三:渗透式交流
体系特征四:个人安全
体系特征五:焦点
体系特征六:与专家用户建立方便的联系
体系特征七:配有自动测试、配置管理和经常集成功能的技术环境

DSDM-动态系统开发方法

Dynamic System Development Management,

它倡导以业务为核心,快速而有效地进行系统开发。 实践证明DSDM是成功的敏捷开发 方法之一。 在英国,由于其在各种规模的软件组织中的成功, 它已成为应用最为广泛的快速应用开发方法。 主要内容:DSDM如何加快产品的 交付, 为什么像DSDM这样的敏捷开发方法能够快速体现所开发系统给业务带来的好处, 如何组织用户参与项目以开发出可用的系统, 如何将不同知识背景的人组 成一个团队, 如何应对常规的业务约束以进行项目管理。

基本原则

原则1:用户必须持续参与 active user involvement is imperative
原则2:必须授予DSDM团队制定决策的权利 DSDM teams are empowered to make decisions including refining or changing requirements without the direct involvement of higher management
原则3:注重产品的经常交付 The focus is on frequent product delivery
原则4:满足业务用户用途是接受交付品的主要依据 Fitness for purpose is the key criterion

###### 开发人员不必沉溺于完美的 解决方案之中,耽误项目时间。在受限的时间内,实现业务利益最大化的交付品才是最重要的。

原则5:迭代和增量式开发对得到正确的业务解决方案是必不可少的 Iterative and incremental development is necessary to converge on an accurate business solution

###### 采用迭代开发的方法,能够使业务流程逐步进化,使系统不断朝着满足业务需求的方向前进。

原则6:开发过程的所有变化可逆 All changes during development are reversible

###### 采用迭代和增量式开发过程中,很可能会碰到走错的情况,此时需要回退到一个已知的可靠的点上。

原则7:在高层次上制定需求的基线 Requirements are initially agreed at a high level

###### 在业务研究中所得出的需求必须在高层次上达成一致。接下来在迭代过程中再得到详细的需求。

原则8:测试自始至终贯穿于开发周期之中 Testing is integrated throughout the life cycle — this is essential with an incremental approach

###### 开发人员完成一个模块的开发后,自己会进行单元测试。当模块集成到现有系统后,测试人员需要执行集成测试。另外,回归测试在DSDM中占有很重 要的地位。

原则9:所有项目涉众间的通力合作是不可获缺的 A collaborative and co-operative approach between all stakeholders is essential

测试驱动开发

测试驱动开发的基本思想就是在开发功能代码之前,先编写测试代码,然后只编写使测试通过的功能代码,从而以测试来驱动整个开发过程的进行。这有助于编写简洁可用和高质量的代码,有很高的灵活性和健壮性,能快速响应变化,并加速开发过程。

测试驱动开发的基本过程如下:

① 快速新增一个测试
② 运行所有的测试(有时候只需要运行一个或一部分),发现新增的测试不能通过
③ 做一些小小的改动,尽快地让测试程序可运行,为此可以在程序中使用一些不合情理的方法
④ 运行所有的测试,并且全部通过
⑤ 重构代码,以消除重复设计,优化设计结构

简单来说,就是不可运行/可运行/重构——这正是测试驱动开发的口号。

测试驱动开发不是一种测试技术,它是一种分析技术、设计技术,更是一种组织所有开发活动的技术。 相对于传统的结构化开发过程方法优势:

1) TDD根据客户需求编写测试用例,对功能的过程和接口都进行了设计,而且这种从使用者角度对代码进行的设计通常更符合后期开发的需求。因为关注用户反馈,可以及时响应需求变更,同时因为从使用者角度出发的简单设计,也可以更快地适应变化。
2) 出于易测试和测试独立性的要求,将促使我们实现松耦合的设计,并更多地依赖于接口而非具体的类,提高系统的可扩展性和抗变性。而且TDD明显地缩短了设计决策的反馈循环,使我们几秒或几分钟之内就能获得反馈。
3) 将测试工作提到编码之前,并频繁地运行所有测试,可以尽量地避免和尽早地发现错误,极大地降低了后续测试及修复的成本,提高了代码的质量。在测试的保护下,不断重构代码,以消除重复设计,优化设计结构,提高了代码的重用性,从而提高了软件产品的质量。
4) TDD提供了持续的回归测试,使我们拥有重构的勇气,因为代码的改动导致系统其他部分产生任何异常,测试都会立刻通知我们。完整的测试会帮助我们持续地跟踪整个系统的状态,因此我们就不需要担心会产生什么不可预知的副作用了。
5) TDD所产生的单元测试代码就是最完美的开发者文档,它们展示了所有的API该如何使用以及是如何运作的,而且它们与工作代码保持同步,永远是最新的。
6) TDD可以减轻压力、降低忧虑、提高我们对代码的信心、使我们拥有重构的勇气,这些都是快乐工作的重要前提。
7)快速的提高了开发效率。

Lean软件开发(精益软件开发)

面对开发团队以及最终的产品大小的额外挑战,可以说软件开发是个持续学习的过程。最佳的改善软件开发环境的做法就是增强学习。在代码完成后马上进行测试可以避免缺陷的累积。不是去做成更多的文档或详细设计,而是对各种各样的想法进行实际的编码尝试。用户需求的收集过程可以简单地通过给最终客户演示,并听取他们的反馈来完成。

使用短周期的迭代(每个迭代都应包括重构和集成测试)可以加速学习过程。在决定当前阶段的开发内容并对未来改善的努力方向进行调整时,在客户端帮助下通过简短的反馈会议来增强反馈。通过这些简短的反馈会议,客户代表和开发团队会更多地发现在进一步开发时会遇到的主要问题及可能的解决方案。从而,基于已开发出的原型,客户可以更好地理解自己的需求,开发者也能了解到如何才能更好地满足客户的需求。另一个关于和客户沟通、学习的想法是“基于组的开发”,这种方法聚焦于未来解决方案的约束限定而不是各种可能的解决方案,因此通过和客户的对话加速了解决方案的产生。

原则

消除浪费
增强学习
尽量延迟决定
尽快发布
下放权力
嵌入质量
全局优化

轻量型RUP

RUP其实是个过程的框架,它可以包容许多不同类型的过程, Craig Larman 极力主张以敏捷型方式来使用RUP。

他的观点是:目前如此众多的努力以推进敏捷型方法,只不过是在接受能被视为RUP 的主流OO开发方法而已。

RUP 是一种以架构为中心的开发过程,而这正是大、中型项目成功的关键。

RUP(Rational Unified Process)是一个风险驱动的基于UML 和构件式架构的迭代递增型开发过程(框架)。RUP 定义了4 个阶段(起始、细化、构造、移交)和9 个科目(业务建模、需求、分析和设计、实现、测试、部署、配置和变更管理、项目管理、环境)。这些阶段对应着关键里程碑的划分,而不同科目的工作流和活动 在生命周期的迭代中可以并发进行,具体执行的程度则可以调节。RUP 对于角色、流程、工件和活动的要求是灵活的、可配置的,所以它广泛地适用于各种类型和规模的项目。RUP 集中体现了6 个软件开发的最佳实践方法:迭代式开发、需求管理、构件式架构、基于UML 的可视化建模、持续校验质量、变更管理。

RUP认为下面这些最佳实践可以改善软件的开发状况:

在早期迭代中解决高风险和高价值的问题
不断的让用户参与评估、反馈和需求
在早期迭代中建立内聚的核心架构
不断地验证质量:提早、经常和实际的测试
可视化软件建模(使用UML)
仔细的管理需求
实行变更请求和配置管理

四个阶段

初始阶段(Inception):

预见项目的范围、构想和业务案例 (Lifecycle Objective)

###### 初始阶段不是一个需求阶段,而是类似与可行性阶段,项目相关人员是否就项目的构想达成基本的一致,项目是否值得继续进行认真的研究

###### 时间不应超过一周,只需要确定这个项目是否值得认真研究,而不是真正去深入研究项目(这个工作留待细化阶段进行)如果预选就决定项目必须进行,而且项目明显是可行的,那么初始阶段会很短,可能只包含一次需求研讨会,并为第一次迭代执行计划,然后就快速的进入细化阶段

###### 主要实践活动-用例建模

###### 对于迭代开发的一个关键理解在于:过程中的工件在初始阶段只是部分完成,在之后的迭代中在逐步精化提炼。例如,用例模型可以列举大多数所需的用例和参与者,但其中可能只有10%的用例会被详细描述,这样就足以建立起有关系统的范围、目标和风险的高层的大致构想。

###### 主要工件:是否意味着大量的文档?工件是可选的,只需要从下面选择对项目确实有价值的工件,放弃哪些不必要的工件,工件的关键不是文档或图表本身,而是其中蕴含的思想、分析和前期准备。

  • 构想和业务案例:描述高层的目标和约束、业务案例,并提供一个执行摘要

  • 用例模型:描述功能需求和相关的非功能需求

  • 补充规范:描述其他需求

  • 术语表:关键的领域术语

  • 风险列表和风险管理计划:描述业务、技术、资源和进度的风险,以及如何减轻这些风险或该如何应对

  • 原型和概念验证:阐明构想,验证技术问题。

  • 迭代计划:描述在第一次细化迭代中该作什么

  • 阶段计划和软件开发计划:对细化阶段的持续时间和工作量进行低精度的猜测。开发涉及的工具、人员、培训和其他资源

  • 开发案例:描述为本项目定制的统一过程的步骤和工件。在统一过程中,总需要为项目定制一些步骤或工件

细化阶段(Elaboration):

已精化的构想,核心架构的迭代实现,高风险的解决,大多数需求和范围的识别,更为现实的评估。 (Lifecycle Architecture)

###### 细化阶段不是一个需求或设计阶段,而是一个迭代实现核心架构并降低高风险的阶段

###### 在细化前不需要定义大多数需求,10%的详细用例书写出来即可

###### 先处理具有风险的元素,开始实际产品代码的编写,产生可执行架构

###### 除了极少数理解良好的问题外需要多次迭代

构造阶段(Construction):

迭代实现遗留下来的风险较低和比较容易的元素,准备部署 (Initial Operational Capability)

移交阶段(Transition):

beta测试,部署 (Product Release)

多个流程

业务建模:在开发单独的应用时,业务建模包括领域对象建模。在从事大规模业务分析或业务过程再工程时,业务建模包括跨越整个企业的业务过程的动态建模。
需求:对应用的需求分析,如写出用例和识别非功能性需求
分析和设计:设计的所有方面,包括总体架构、对象、数据库、网络连接等。分析强调的是对问题和需求的调查研究,而不是解决方案。设计强调的是满足需求的概念上的解决方案,而不是其实现。分析和设计可以被概括为:作正确的事(分析)和正确的做事(设计)。
实现:编程和构建系统,而不是部署系统
测试
配置和变更管理
项目管理
环境:指建立工具并为项目定制过程,也就是说,设置工具和过程环境。
1-5为核心工作流程,6-8为支持工作流程
The way of controlling

###### 如何计划和管理迭代:需要多少迭代?每次迭代多长时间?每次迭代的目的是什么?如何跟踪每次迭代情况?

  • The Phase Plan (Project Plan):一个粗略的计划,每个开发项目只有一份项目计划。包括了一个周期(cycle)内所有的环节(有时也可以包含多个周期)。计划包含主要里程碑的时间,要求的资源。如果能够明确分几个iteratio,则需要标识时每个小里程碑的时间和目的。

  • The Iteration Plan:迭代计划,包含当前迭代的详细计划,包括时间、任务和资源分配,在当前迭代后半期还需要包含下一个迭代的计划

###### 风险管理

###### 度量

The way of supporting
The way of communicating

###### RUP定义了一系列流程和工件,这些工作作为各角色间沟通的主要内容,用例和架构是RUP的两个重要内容。

###### 用例驱动开发:使用用例表达需求,对业务进行描述。用例作为整个开发流程的基础。

###### 架构为中心流程:架构使用多个、协调一致的视图来表达系统,作为概念、构建、管理和演进系统的主要工件

模型和流程对应

角色: the who
活动: the how
工件:the what
工作流: the when
规程(Disciplines): 组合前面四种元素

六大经验

迭代式开发。在软件开发的早期阶段就想完全、准确的捕获用户的需求几乎是不可能的。实际上,我们经常遇到的问题是需求在整个软件开发工程中经常会改变。迭代式开发允许在每次迭代过程中需求可能有变化,通过不断细化来加深对问题的理解。迭代式开发不仅可以降低项目的风险,而且每个迭代过程以可以执行版本结束,可以鼓舞开发人员。
管理需求。确定系统的需求是一个连续的过程,开发人员在开发系统之前不可能完全详细的说明一个系统的真正需求。RUP描述了如何提取、组织系统的功能和约束条件并将其文档化,用例和脚本的使用以被证明是捕获功能性需求的有效方法。
基于组件的体系结构。组件使重用成为可能,系统可以由组件组成。基于独立的、可替换的、模块化组件的体系结构有助于管理复杂性,提高重用率。RUP描述了如何设计一个有弹性的、能适应变化的、易于理解的、有助于重用的软件体系结构。
可视化建模。RUP往往和UML联系在一起,对软件系统建立可视化模型帮助人们提供管理软件复杂性的能力。RUP告诉我们如何可视化的对软件系统建模,获取有关体系结构于组件的结构和行为信息。
验证软件质量。在RUP中软件质量评估不再是事后进行或单独小组进行的分离活动,而是内建于过程中的所有活动,这样可以及早发现软件中的缺陷。
控制软件变更。迭代式开发中如果没有严格的控制和协调,整个软件开发过程很快就陷入混乱之中,RUP描述了如何控制、跟踪、监控、修改以确保成功的迭代开发。RUP通过软件开发过程中的制品,隔离来自其他工作空间的变更,以此为每个开发人员建立安全的工作空间。

核心概念

角色:描述某个人或者一个小组的行为与职责。RUP预先定义了很多角色。
活动:是一个有明确目的的独立工作单元。
工件:是活动生成、创建或修改的一段信息。

RUP裁剪

RUP是一个通用的过程模板,包含了很多开发指南、制品、开发过程所涉及到的角色说明,由于它非常庞大所以对具体的开发机构和项目,用RUP时还要做裁剪,也就是要对RUP进行配置。RUP就像一个元过程,通过对RUP进行裁剪可以得到很多不同的开发过程,这些软件开发过程可以看作RUP的具体实例。RUP裁剪可以分为以下几步:
1) 确定本项目需要哪些工作流。RUP的9个核心工作流并不总是需要的,可以取舍。
2) 确定每个工作流需要哪些制品。
3) 确定4个阶段之间如何演进。确定阶段间演进要以风险控制为原则,决定每个阶段要那些工作流,每个工作流执行到什么程度,制品有那些,每个制品完成到什么程度。
4) 确定每个阶段内的迭代计划。规划RUP的4个阶段中每次迭代开发的内容。
5) 规划工作流内部结构。工作流涉及角色、活动及制品,他的复杂程度与项目规模即角色多少有关。最后规划工作流的内部结构,通常用活动图的形式给出。

面向对象

结构化与面向对象方法特点比较

  1. 从概念方面看,

结构化软件是功能的集合,通过模块以及模块和模块之间的分层调用关系实现;面向对象软件是事物的集合,通过对象以及对象和对象之间的通讯联系实现;

  1. 从构成方面看

结构化软件=过程+数据,以过程为中心;面向对象软件=(数据+相应操作)的封装,以数据为中心;

  1. 从运行控制方面看

结构化软件采用顺序处理方式,由过程驱动控制;面向对象软件采用交互式、并行处理方式,由消息驱动控制;

  1. 从开发方面看,

结构化方法的工作重点是设计;面向对象方法的工作重点是分析;

在结构化方法中需要把在分析阶段采用的具有网络特征的数据流图转换为设计阶段采用的具有分层特征的结构图,在面向对象方法中则不存在这一问题。

  1. 从应用方面看,

相对而言,结构化方法更加适合数据类型比较简单的数值计算和数据统计管理软件的开发;面向对象方法更加适合大型复杂的人机交互式软件和数据统计管理软件的开发;

OOD(Object Oriented Design)

OOD就是“根据需求决定所需的类、类的操作以及类之间关联的过程”。

OOD是一种解决软件问题的设计范式(paradigm),一种抽象的范式。使用OOD这种设计范式,我们可以用对象(object)来表现问题领域(problem domain)的实体,每个对象都有相应的状态和行为。我们刚才说到:OOD是一种抽象的范式。抽象可以分成很多层次,从非常概括的到非常特殊的都有,而对象可能处于任何一个抽象层次上。另外,彼此不同但又互有关联的对象可以共同构成抽象:只要这些对象之间有相似性,就可以把它们当成同一类的对象来处理。

面向对象设计(Object-Oriented Design,OOD)方法是OO方法中一个中间过渡环节。其主要作用是对OOA分析的结果作进一步的规范化整理,以便能够被OOP直接接受。

面向对象设计(OOD)是一种软件设计方法,是一种工程化规范。这是毫无疑问的。按照Bjarne Stroustrup的说法,面向对象的编程范式(paradigm)是[Stroustrup, 97]:

由这个定义,我们可以看出:OOD就是“根据需求决定所需的类、类的操作以及类之间关联的过程”。

OOD的目标是管理程序内部各部分的相互依赖。为了达到这个目标,OOD要求将程序分成块,每个块的规模应该小到可以管理的程度,然后分别将各个块隐藏在接口(interface)的后面,让它们只通过接口相互交流。比如说,如果用OOD的方法来设计一个服务器-客户端(client-server)应用,那么服务器和客户端之间不应该有直接的依赖,而是应该让服务器的接口和客户端的接口相互依赖。

这种依赖关系的转换使得系统的各部分具有了可复用性。还是拿上面那个例子来说,客户端就不必依赖于特定的服务器,所以就可以复用到其他的环境下。如果要复用某一个程序块,只要实现必须的接口就行了。

OOD是一种解决软件问题的设计范式(paradigm),一种抽象的范式。使用OOD这种设计范式,我们可以用对象(object)来表现问题领域(problem domain)的实体,每个对象都有相应的状态和行为。我们刚才说到:OOD是一种抽象的范式。抽象可以分成很多层次,从非常概括的到非常特殊的都有,而对象可能处于任何一个抽象层次上。另外,彼此不同但又互有关联的对象可以共同构成抽象:只要这些对象之间有相似性,就可以把它们当成同一类的对象来处理。

OOD步骤

决定你要的类;

给每个类提供完整的一组操作;

明确地使用继承来表现共同点。

细化重组类

细化和实现类间关系,明确其可见性

增加属性,指定属性的类型与可见性

分配职责,定义执行每个职责的方法

对消息驱动的系统,明确消息传递方式

利用设计模式进行局部设计

画出详细的类图与时序图

OOD设计过程中要展开的主要几项工作

(一)对象定义规格的求精过程

对于OOA所抽象出来的对象-&-类以及汇集的分析文档,OOD需要有一个根据设计要求整理和求精的过程,使之更能符合OOP的需要。这个整理和求精过程主要有两个方面:一是要根据面向对象的概念

模型整理分析所确定的对象结构、属性、方法等内容,改正错误的内容,删去不必要和重复的内容等。二是进行分类整理,以便于下一步数据库设计和程序处理模块设计的需要。整理的方法主要是进行归

类,对类一&一对象、属性、方法和结构、主题进行归类。

(二)数据模型和数据库设计

数据模型的设计需要确定类-&-对象属性的内容、消息连接的方式、系统访问、数据模型的方法等。最后每个对象实例的数据都必须落实到面向对象的库结构模型中。

(三)优化

OOD的优化设计过程是从另一个角度对分析结果和处理业务过程的整理归纳,优化包括对象和结构的优化、抽象、集成。

对象和结构的模块化表示OOD提供了一种范式,这种范式支持对类和结构的模块化。这种模块符合一般模块化所要求的所有特点,如信息隐蔽性好,内部聚合度强和模块之间耦合度弱等。

集成化使得单个构件有机地结合在一起,相互支持。

六、OO方法的特点和面临的问题

OO方法以对象为基础,利用特定的软件工具直接完成从对象客体的描述到软件结构之间的转换。这是OO方法最主要的特点和成就。OO方法的应用解决了传统结构化开发方法中客观世界描述工具与软

件结构的不一致性问题,缩短了开发周期,解决了从分析和设计到软件模块结构之间多次转换映射的繁杂过程,是一种很有发展前途的系统开发方法。

但是同原型方法一样,OO方法需要一定的软件基础支持才可以应用,另外在大型的MIS开发中如果不经自顶向下的整体划分,而是一开始就自底向上的采用OO 方法开发系统,同样也会造成系统结构不合理、各部分关系失调等问题。所以OO方法和结构化方法目前仍是两种在系统开发领域相互依存的、不可替代的方法。

实现UML建模

(1) 业务对象的提取

(2) 根据SRS、CRC等实现用况建模

(3) 实现业务顺序图

(4) 建立类图,根据用况图建立对象之间的关联

(5) 绘制活动图、实现协作图、状态图

OOP(Object Oriented Programming)

面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。OOP 达到了软件工程的三个主要目标:重用性、灵活性和扩展性。为了实现整体运算,每个对象都能够接收信息、处理数据和向其它对象发送信息。OOP 主要有以下的概念和组件:

组件 - 数据和功能一起在运行着的计算机程序中形成的单元,组件在 OOP 计算机程序中是模块和结构化的基础。

抽象性 - 程序有能力忽略正在处理中信息的某些方面,即对信息主要方面关注的能力。

封装 - 也叫做信息封装:确保组件不会以不可预期的方式改变其它组件的内部状态;只有在那些提供了内部状态改变方法的组件中,才可以访问其内部状态。每类组件都提供了一个与其它组件联系的接口,并规定了其它组件进行调用的方法。

多态性 - 组件的引用和类集会涉及到其它许多不同类型的组件,而且引用组件所产生的结果得依据实际调用的类型。

继承性 - 允许在现存的组件基础上创建子类组件,这统一并增强了多态性和封装性。典型地来说就是用类来对组件进行分组,而且还可以定义新类为现存的类的扩展,这样就可以将类组织成树形或网状结构,这体现了动作的通用性。

由于抽象性、封装性、重用性以及便于使用等方面的原因,以组件为基础的编程在脚本语言中已经变得特别流行。Python 和 Ruby 是最近才出现的语言,在开发时完全采用了 OOP 的思想,而流行的 Perl 脚本语言从版本5开始也慢慢地加入了新的面向对象的功能组件。用组件代替“现实”上的实体成为 JavaScript(ECMAScript) 得以流行的原因,有论证表明对组件进行适当的组合就可以在英特网上代替 HTML 和 XML 的文档对象模型(DOM)。

设计模式、技术和直觉构成严峻的挑战。这是选择编程语言之前必须认识到的,尽管不同语言的设计特性可能促进或者阻碍这一转化。

在网络应用的增长中,一个很重要的部分是小型移动设备和特殊Internet设备的爆炸性增长。这些设备各有各的操作系统,或者只在某种特定的设备领域内有共同的操作系统。我们现在还可以一一列举出这些设备——家庭接入设备、蜂窝电话、电子报纸、PDA、自动网络设备等等。但是这些设备领域的数量和深入程度将会很快变得难以估量。我们都知道这个市场大得惊人,PC的兴起与之相比不过小菜一碟。因此在这些设备的应用程序市场上,竞争将会相当残酷。获胜的重要手段之一,就是尽快进入市场。开发人员需要优秀的工具,迅速高效地撰写和调试他们的软件。平台无关性也是制胜秘诀之一,它使得程序员能够开发出支持多种设备平台的软件。

我预期的另一个变化是,我们对于代码(Java)和数据(XML)协同型应用程序的开发能力将会不断提高。这种协同是开发强大应用程序的核心目标之一。我们从XML的迅速流行和ebXML规范的进展中,已经看到了这个趋势。ebXML是一个针对电子商务和国际贸易的,基于XML的开放式基础构架,由联合国贸易促进和电子商务中心(UN/CEFACT)与结构性信息标准推进组织(OASIS)共同开发。

我们能否期望出现一个真正的面向组件(component-oriented)的语言?它的创造者会是谁呢?

Stroustrup: 我怀疑,这个领域中之所以缺乏成果,正是因为人们——主要是那些非程序员们——对“组件”这个意义含糊的字眼寄予了太多的期望。这些人士梦想,有朝一日,组件会以某种方式把程序员赶出历史舞台。以后那些称职的“设计员”只需利用预先调整好的组件,把鼠标拖一拖放一放,就把系统组合出来。对于软件工具厂商来说,这种想法还有另一层意义,他们认为,到时候只有他们才保留有必要的技术,有能力编写这样的组件。

这种想法有一个最基本的谬误:这种组件很难获得广泛欢迎。一个单独的组件或框架(framework),如果能够满足一个应用程序或者一个产业领域对所提出的大部分要求的话,对于其制造者来说就是划算的产品,而且技术上也不是很困难。可是该产业内的几个竞争者很快就会发现,如果所有人都采用这些组件,那么彼此之间的产品就会变得天下大同,没什么区别,他们将沦为简单的办事员,主要利润都将钻进那些组件/框架供应商的腰包里!

小“组件”很有用,不过产生不了预期的杠杆效应。中型的、更通用的组件非常有用,但是构造时需要非同寻常的弹性。

OOA(Object Oriented Analyzing)

需要做什么

为完成用户要求系统应提供哪些功能?

系统应有哪些对象构成?

每个对象应有哪些属性和服务?

对象间应有怎样的联系?要

怎么做

个体特征分析:标识对象及其属性和服务。

静态分析:分析和描述系统的静态结构。

动态分析:分析对象及之间的行为及其控制关系,建立系统的动态模型。

主要原则

(1)抽象

抽象原则包括过程抽象和数据抽象两个方面。过程抽象是指,任何一个完成确定功能的操作序列。数据抽象是根据施加于数据之上的操作来定义数据类型。

(2)封装

就是把对象的属性和服务结合为一个不可分的系统单位,并尽可能隐蔽对象的内部细节。

(3)继承

继承原则的好处是:使系统模型比较简练也比较清晰。

特殊类的对象拥有的其一般类的全部属性与服务,称作特殊类对一般类的继承。

(4)分类

就是把具有相同属性和服务的对象划分为一类,用类作为这些对象的抽象描述。分类原则实际上是抽象原则运用于对象描述时的一种表现形式。

(5)聚合

又称组装,其原则是:把一个复杂的事物看成若干比较简单的事物的组装体,从而简化对复杂事物的描述。

(6)关联

是人类思考问题时经常运用的思想方法:通过一个事物联想到另外的事物。能使人发生联想的原因是事物之间确实存在着某些联系。

(7)消息通信

这一原则要求对象之间只能通过消息进行通信,而不允许在对象之外直接地存取对象内部的属性。通过消息进行通信是由于封装原则而引起的。在OOA中要求用消息连接表示出对象之间的动态联系。

(8)粒度控制

一般来讲,人在面对一个复杂的问题域时,不可能在同一时刻既能纵观全局,又能洞察秋毫。因此需要控制自己的视野:考虑全局时,注意其大的组成部分,暂时不详察每一部分的具体的细节;考虑某部分的细节时则暂时撇开其余的部分。这就是粒度控制原则。

(9)行为分析

现实世界中事物的行为是复杂的。由大量的事物所构成的问题域中各种行为往往相互依赖、相互交织。

三种分析模型

1、对象模型

对用例模型进行分析,把系统分解成互相协作的分析类,通过类图/对象图描述对象/对象的属性/对象间的关系,是系统的静态模型

2、动态模型

描述系统的动态行为,通过时序图/协作图描述对象的交互,以揭示对象间如何协作来完成每个具体的用例,单个对象的状态变化/动态行为可以通过状态图来表达

3、功能模型(即用例模型作为输入)。

OOA主要优点

(1)加强了对问题域和系统责任的理解;

(2)改进与分析有关的各类人员之间的交流;

(3)对需求的变化具有较强的适应性;

(4)支持软件复用。

(5)贯穿软件生命周期全过程的一致性。

(6)实用性;

(7)有利于用户参与。

基本步骤

第一步,确定对象和类。

这里所说的对象是对数据及其处理方式的抽象,它反映了系统保存和处理现实世界中某些事物的信息的能力。类是多个对象的共同属性和方法集合的描述,它包括如何在一个类中建立一个新对象的描述。

第二步,确定结构(structure)。

结构是指问题域的复杂性和连接关系。类成员结构反映了泛化-特化关系,整体-部分结构反映整体和局部之间的关系。

第三步,确定主题(subject)。

主题是指事物的总体概貌和总体分析模型。

第四步,确定属性(attribute)。

属性就是数据元素,可用来描述对象或分类结构的实例,可在图中给出,并在对象的存储中指定。

第五步,确定方法(method)。

方法是在收到消息后必须进行的一些处理方法:方法要在图中定义,并在对象的存储中指定。对于每个对象和结构来说,那些用来增加、修改、删除和选择一个方法本身都是隐含的(虽然它们是要在对象的存储中定义的,但并不在图上给出),而有些则是显示的。

面向对象

第一步是抽取建立领域的概念模型

在UML中表现为建立对象类图、活动图和交互图。

对象类就是从对象中经过“察同”找出某组对象之间的共同特征而形成类:

对象与类的属性:数据结构;

对象与类的服务操作:操作的实现算法;

对象与类的各外部联系的实现结构;

设计策略:充分利用现有的类;

方法:继承、复用、演化;

活动图用于定义工作流,

主要说明工作流的5W(Do What、Who Do、When Do、Where Do、Why Do)等问题,交互图把人员和业务联系在一起是为了理解交互过程,发现业务工作流中相互交互的各种角色。

第二步是构建完善系统结构:

对系统进行分解,将大系统分解为若干子系统,

子系统分解为若干软件组件,

并说明子系统之间的静态和动态接口,

每个子系统可以由用例模型、分析模型、设计模型、测试模型表示。

软件系统结构的两种方式:层次、块状

层次结构:系统、子系统、模块、组件(同一层之间具有独立性);

块状结构:相互之间弱耦合

系统的组成部分:

问题论域:业务相关类和对象(OOA的重点);

人机界面:窗口、菜单、按钮、命令等等;

数据管理:数据管理方法、逻辑物理结构、操作对象类;

任务管理:任务协调和管理进程;

第三步是利用“4+1”视图描述系统架构

用例视图及剧本;说明体系结构的设计视图;

以模块形式组成包和层包含概要实现模型的实现视图;

说明进程与线程及其架构、分配和相互交互关系的过程视图;

说明系统在操作平台上的物理节点和其上的任务分配的配置视图。在RUP中还有可选的数据视图。

第四步是性能优化

(速度、资源、内存)、模型清晰化、简单化(简单就是享受)。

基本

抽象类

抽象类是提供多个派生类共享基类的公共定义,它既可以提供抽象方法,也可以提供非抽象方法。抽象类不能实例化,必须通过继承由派生类实现其抽象方法,因此对抽象类不能使用new关键字,也不能被密封。如果派生类没有实现所有的抽象方法,则该派生类也必须声明为抽象类。另外,实现抽象方法由override方法来实现。

抽象类的特点:

(1). 抽象类是一个类,可以包含类的一切东西:属性、字段、委托、方法。

(2). 抽象方法必须包含在抽象类中,抽象方法没有方法体,但抽象类中还可以包含普通的非抽象方法。

(3). 抽象类和抽象方法的关键字均为abstract。

(4). 继承抽象类的子类中,必须显式的覆写(override)其父类中的所有抽象方法。

(5). 抽象类不能直接被实例化,声明的对象只能使用抽象类中已有的方法,不能使用子类新增的方法。

(6). 同一个类只能继承唯一一个父类。

对比父类中的虚方法(virtual)和抽象方法(abstract)的区别:

(1). 抽象方法没有方法体,其继承子类必须对其进行覆写(override).

(2). 虚方法有方法体,其继承子类可以对其进行覆写(override),可以不进行覆写。若进行覆写,调用的则是子类中覆写后的方法;若不进行覆写,则调用的是父类 中的方法。

(3). 抽象方法的关键字是abstract,且必须存在于抽象类中;虚方法的关键字是virtual,可以存在于任何类中。

属性

方法

对象

接口

接口是包含一组虚方法的抽象类型,其中每一种方法都有其名称、参数、返回值。接口方法不能包含任何实现,CLR允许接口可以包含事件、属性、索引器、静态方法、静态字段、静态构造函数以及常数。 但是接口不能包含任何静态成员。一个类可以实现多个接口,当一个类实现某个接口时,它不仅要实现该接口定义的所有方法,还要实现该接口从其他接口中继承的所有方法。

(1). 接口不是类,里面可以包含属性、方法、事件,但不能包括字段和静态成员。

(2). 接口只能包含没有实现的方法。

(3). 子类实现接口,必须要实现该接口定义的所有方法,还要实现该接口从其他接口中继承的所有方法。

(4). 接口不能被直接实例化,声明的对象只能使用接口中的方法,不能使用子类新增的方法。

(5). 同一个类可以实现多个接口。

关系

依赖(Dependency):

两个事物间的语义关系,其中一个事物发生了变化会影响到另一个事物。

关联(Association):

是一种结构关系,它描述了一组链,链是对象之间的连接。比如一个人为一家公司工作(WorksFor),这里WorksFor就是一个关联。

是对象之间物理上或概念上的连接。例如:张三为微软公司工作(WorksFor),这里WorksFor就是一个链接。

聚合(Aggregation):

其是一种特殊形式的关联。表示整体与部分的关系。比如项目组与其各成员之间的关系就是一种聚合关系。

组合关系(Composition):

其也是一种特殊形式的关联。表示整体拥有各个部分,部分与整体共存。比如一个窗口是由文本框、列表框、菜单等组成的。关闭窗口,各个组成部分也相继消失,窗口与其各组成部分之间的关系便是组合关系。Ao对象中FeatureClass与Feature之间就是一种组合关系。

泛化(Generalization):

其是一种特殊/一般关系,特殊元素(子元素)/的对象可替代一般元素(父元素)的对象。也称为“Is a关系”。

实现(Realization):

是类元之间的语义关系,其中一个类元指定了由另一个类元保证执行的契约。

符号

Class1 < – ClassA:泛化(子类继承父类)

Class2 <– ClassB:关联(成员变量)

Class3 *– ClassC:组合(是整体与部分的关系,但部分不能离开整体而单独存在)

Class4 o– ClassD:聚合(Aggregation 整体与部分)

Class5 < .. ClassE:实现(类实现接口)

Class6 <.. ClassF:依赖(局部变量、方法的参数或者对静态方法的调用)

面向对象的三大特征

(1). 封装

将一些行为以类为单位进行包裹起来,然后通过类进行调用(如People类),可以利用private、public、protected灵活控制属性的可访问性。

①:保证数据安全(灵活使用private、public、protected进行控制)

②:屏蔽细节,只要方法名不变,可以随意扩展。

③:代码重用

(2). 继承

通过继承,子类可以拥有父类的一切动作(如Student类继承People类)

(3). 多态

多态有很多种。

①:通过不同子类继承同一个父类,实现多态(类似的还有子类继承抽象类、或者实现接口)

②:方法的重载本身就是一种多态

③:利用默认参数实现方法多态(利用命名参数实现方法的重载,即方法的多态)

④:运行时的多态(里氏替换原则,声明父类对象,调用虚方法,在子类覆写或者不覆写的情况下,分别调用子类方法或父类方法《只有在运行的时候才知道》)

抽象类和接口的比较

相同点

  1. 都不能被直接实例化,都可以通过继承实现其抽象方法。
  1. 都是面向抽象编程的技术基础,实现了诸多的设计模式。

不同点

  1. 接口支持多继承;抽象类不能实现多继承。
  1. 接口只能定义抽象规则;抽象类既可以定义规则,还可能提供已实现的成员。
  1. 接口是一组行为规范;抽象类是一个不完全的类,着重族的概念。
  1. 接口可以用于支持回调;抽象类不能实现回调,因为继承不支持。
  1. 接口只包含方法、属性、索引器、事件的签名,但不能定义字段和包含实现的方法;抽象类可以定义字段、属性、包含有实现的方法。
  1. 接口可以作用于值类型和引用类型;抽象类只能作用于引用类型。例如,Struct就可以继承接口,而不能继承类。

规则与场合

  1. 请记住,面向对象思想的一个最重要的原则就是:面向接口编程。
  1. 借助接口和抽象类,23个设计模式中的很多思想被巧妙的实现了,我认为其精髓简单说来就是:面向抽象编程。
  1. 抽象类应主要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。
  1. 接口着重于CAN-DO关系类型,而抽象类则偏重于IS-A式的关系;
  1. 接口多定义对象的行为;抽象类多定义对象的属性;
  1. 接口定义可以使用public、protected、internal 和private修饰符,但是几乎所有的接口都定义为public,原因就不必多说了。
  1. 在接口中,所有的方法都默认为public。
  1. “接口不变”,是应该考虑的重要因素。所以,在由接口增加扩展时,应该增加新的接口,而不能更改现有接口。
  1. 尽量将接口设计成功能单一的功能块,以.NET Framework为例,IDisposable、IDisposable、IComparable、IEquatable、IEnumerable等都只包含一个公共方法。
  1. 接口名称前面的大写字母“I”是一个约定,正如字段名以下划线开头一样,请坚持这些原则。
  1. 如果预计会出现版本问题,可以创建“抽象类”。例如,创建了狗(Dog)、鸡(Chicken)和鸭(Duck),那么应该考虑抽象出动物(Animal)来应对以后可能出现风马牛的事情。而向接口中添加新成员则会强制要求修改所有派生类,并重新编译,所以版本式的问题最好以抽象类来实现。
  1. 从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。
  1. 对抽象类不能使用new关键字,也不能被密封,原因是抽象类不能被实例化。
  1. 在抽象方法声明中不能使用 static 或 virtual 修饰符。(abstract 不能与static 或virtual一起用)

MSDN建议

  1. 如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单易行的方法来控制组件版本。通过更新基类,所有继承类都随更改自动更新。另一方面,接口一旦创建就不能更改。如果需要接口的新版本,必须创建一个全新的接口。
  1. 如果创建的功能将在大范围的全异对象间使用,则使用接口。抽象类应主要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。
  1. 如果要设计小而简练的功能块,则使用接口。如果要设计大的功能单元,则使用抽象类。
  1. 如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类。抽象类允许部分实现类,而接口不包含任何成员的实现。

.NET Framework中关于接口和抽象类的使用:

集合类使用了基于接口的设计,请关注System.Collections中关于接口的设计实现;

数据流相关类使用了基于抽象类的设计,请关注System.IO.Stream类的抽象类设计机制。

其他问题

面向对象与面向过程区别

5.1、面向对象是将事物高度抽象化。

5.2、面向过程是一种自顶向下的编程

5.3、面向对象必须先建立抽象模型,之后直接使用模型就行了。

5.4、面向过程(OP)和面向对象(OO)本质的区别在于分析方式的不同,最终导致了编码方式的不同。

面向对象设计原则

1、单一职责原则 SRP

(Single Responsibility Principle)

一个类,只有一个引起它变化的原因。主要是解耦合高内聚。

2、开闭原则 OCP

(Open Close Principle)

对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,易于维护和升级。

3、里氏代换原则 LSP

(Liskov Substitution Principle)

任何基类可以出现的地方,子类一定可以出现。

4、依赖倒转原则 DIP

(Dependence Inversion Principle)

就是要依赖于抽象,不要依赖于具体实现。

5、接口隔离原则 ISP

(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好,也是降低类之间的耦合度。

6、合成复用原则 CRP

(Composite Reuse Principle)

要尽量使用组合/聚合关系,少用继承。

7、迪米特法则(最少知道原则)DP

(Demeter Principle)

一个软件实体应当尽可能少的与其他实体发生相互作用。

Gof设计模式

GoF:(Gang of Four,GOF设计模式)—四人组

Design Patterns: Elements of Reusable Object-Oriented Software(即后述《设计模式》一书),由 Erich Gamma、Richard Helm、Ralph Johnson 和 John

Vlissides 合著(Addison-Wesley,1995)。这几位作者常被称为“四人组(Gang of Four)”,而这本书也就被称为“四人组(或 GoF)”书。

行为型

Iterator(迭代器模式)

Iterator(迭代器模式):提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。

Interpreter(解析器模式)

Interpreter(解析器模式):给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。

Observer(观察者模式)

Observer(观察者模式):定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。

Mediator(中介者模式)

Mediator(中介者模式):用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

Visitor(访问者模式)

Visitor(访问者模式):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

Memento(备忘录模式)

Memento(备忘录模式):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。

State(状态模式)

State(状态模式):允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。

Strategy(策略模式)

Strategy(策略模式):定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。

Template Method(模板方法模式)

Template Method(模板方法模式):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。

Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

Command(命令模式)

Command(命令模式):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。

Chain of Responsibility(职责链模式)

Chain of Responsibility(职责链模式):为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。

创建型

Singleton(单例模式)

Singleton(单例模式):保证一个类仅有一个实例,并提供一个访问它的全局访问点。

Prototype(原型模式)

Prototype(原型模式):用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。

Builder(建造者模式)

Builder(建造者模式):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

Factory Method(工厂模式)

Factory Method(工厂模式):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。 Factory Method使一个类的实例化延迟到其子类

 Abstract Factory(抽象工厂模式)

Abstract Factory(抽象工厂模式):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

结构型

Bridge(桥接模式)

Bridge(桥接模式):将抽象部分与它的实现部分分离,使它们都可以独立地变化。

Facade(外观模式)

Facade(外观模式):为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

Composite(组合模式)

Composite(组合模式):将对象组合成树形结构以表示“部分-整体”的层次结构。它使得客户对单个对象和复合对象的使用具有一致性。

Decorator(装饰模式):

Decorator(装饰模式):动态地给一个对象添加一些额外的职责。就扩展功能而言, 它比生成子类方式更为灵活。

Adapter(适配器模式)

Adapter(适配器模式):将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

Proxy(代理模式)

Proxy(代理模式):为其他对象提供一个代理以控制对这个对象的访问。

Flyweight(享元模式)

Flyweight(享元模式):运用共享技术有效地支持大量细粒度的对象。

模式之间关系

其他

参考资料

23种设计模式UML图

UML

UML是一种通用的建模语言,其表达能力相当的强,不仅可以用于软件系统的建模,而且可用于业务建模以及其它非软件系统建模。UML综合了各种面向对象方法与表示法的优点,至提出之日起就受到了广泛的重视并得到了工业界的支持。

组成

视图(View): 是表达系统的某一方面的特征的UML建模元素的子集,由多个图构成,是在某一个抽象层上,对系统的抽象表示。

图(Diagram): 是模型元素集的图形表示,通常是由弧(关系)和顶点(其他模型元素)相互连接构成的

模型元素(Model Element):代表面向对象中的类、对象、消息和关系等概念,是构成图的最基本的常用概念。

通用机制(General Mechanism):用于表示其他信息,比如注释、模型元素的语义等。另外,UML还提供扩展机制,使UML语言能够适应一个特殊的方法(或过程),或扩充至一个组织或用户。本的常用概念。

架构视图分类

(1) 用例视图(Use Case View),强调从用户的角度看到的或需要的系统功能,是被称为参与者的外部用户所能观察到的系统功能的模型图。

(2) 逻辑视图(Logical View),展现系统的静态或结构组成及特征,也称为结构模型视图(Structural Model View)或静态视图(Static View)。

(3) 并发视图(Concurrent View),体现了系统的动态或行为特征,也称为行为模型视图(Behavioral Model View)或动态视图(Dynamic View)。

(4) 组件视图(Component View),体现了系统实现的结构和行为特征,也称为实现模型视图(Implementation Model View)。

(5) 配置视图(Deployment View),体现了系统实现环境的结构和行为特征,也称为环境模型视图(Environment Model View)或物理视图(Physical View)。

UML视图

(1) 用例图(Use Case Diagram),描述系统功能;

(2) 类图(Class Diagram),描述系统的静态结构;

基本元素符号:

###### 1. 类(Classes)类(Class)是指具有相同属性、方法和关系的对象的抽象, 它封装了数据和行为,是面向对象程序设计(OOP)的基础, 具有封装性、继承性和多态性等三大特性。 在 UML 中,类使用包含类名、属性和操作且带有分隔线的矩形来表示。

￿[{“data”:{“id”:”cf32aswv30w0”,”created”:1634613991376,”text”:”类包含3个组成部分。第一个是Java中定义的类名。第二个是属性(attributes)。第三个是该类提供的方法。”,”richText”:{“ops”:[{“attributes”:{},”insert”:”类包含3个组成部分。第一个是Java中定义的类名。第二个是属性(attributes)。第三个是该类提供的方法。”},{“insert”:”\n”,”attributes”:{}}]},”background”:”transparent”},”children”:[]}] ￿[{“data”:{“id”:”cf32aswutog0”,”created”:1634613991376,”text”:”属性和操作之前可附加一个可见性修饰符。加号(+)表示具有公共可见性。减号(-)表示私有可见性。#号表示受保护的可见性。省略这些修饰符表示具有package(包)级别的可见性。如果属性或操作具有下划线,表明它是静态的。在操作中,可同时列出它接受的参数,以及返回类型,如下图所示:”,”richText”:{“ops”:[{“attributes”:{},”insert”:”属性和操作之前可附加一个可见性修饰符。加号(+)表示具有公共可见性。减号(-)表示私有可见性。#号表示受保护的可见性。省略这些修饰符表示具有package(包)级别的可见性。如果属性或操作具有下划线,表明它是静态的。在操作中,可同时列出它接受的参数,以及返回类型,如下图所示:”},{“insert”:”\n”,”attributes”:{}}]},”background”:”transparent”},”children”:[]}]

* 1. 类名(Name)是一个字符串,例如,Student。

  • (2) 属性(Attribute)是指类的特性,即类的成员变量。UML 按以下格式表示:

  • [可见性]属性名:类型[=默认值]

  • 例如:-name:String

  • 注意:“可见性”表示该属性对类外的元素是否可见,包括公有(Public)、私有(Private)、受保护(Protected)和朋友(Friendly)4 种,在类图中分别用符号+、-、#、~表示。

  • (3) 操作(Operations)是类的任意一个实例对象都可以使用的行为,是类的成员方法。UML 按以下格式表示:

  • [可见性]名称(参数列表)[:返回类型]

  • 例如:+display():void。

###### 2. 包(Package) 包可直接理解为命名空间,文件夹,是用来组织图形的封装,包图可以用来表述功能组命名空间的组织层次。

•在面向对象软件开发的视角中,类显然是构建整个系统的基本构造块。 但是对于庞大的应用系统而言,其包含的类将是成百上千, 再加上其间“阡陌交纵”的关联关系、多重性等,必然是大大超出了人们可以处理的复杂度。 这也就是引入了“包”这种分组事物构造块。

￿[{“data”:{“id”:”cf32aswvrh40”,”created”:1634613991377,”text”:”包是一种常规用途的组合机制。UML中的一个包直接对应于Java中的一个包。在Java中,一个包可能含有其他包、类或者同时含有这两者。进行建模时,你通常拥有逻辑性的包,它主要用于对你的模型进行组织。你还会拥有物理性的包,它直接转换成系统中的Java包。每个包的名称对这个包进行了惟一性的标识。”,”richText”:{“ops”:[{“attributes”:{},”insert”:”包是一种常规用途的组合机制。UML中的一个包直接对应于Java中的一个包。在Java中,一个包可能含有其他包、类或者同时含有这两者。进行建模时,你通常拥有逻辑性的包,它主要用于对你的模型进行组织。你还会拥有物理性的包,它直接转换成系统中的Java包。每个包的名称对这个包进行了惟一性的标识。”},{“insert”:”\n”,”attributes”:{}}]},”background”:”transparent”},”children”:[]}]

  • 包的可见性:

  • 用“+”来表示“public”,

  • 用“#”来表示“protected”,

  • 用“-”来表示“private”

###### 3. 接口(Interface) 接口(Interface)是一种特殊的类,它具有类的结构但不可被实例化, 只可以被子类实现。它包含抽象操作,但不包含属性。 它描述了类或组件对外可见的动作。 在 UML 中,接口使用一个带有名称的小圆圈来进行表示。

￿[{“data”:{“id”:”cf32aswvqhc0”,”created”:1634613991377,”text”:”接口是一系列操作的集合,它指定了一个类所提供的服务。它直接对应于Java中的一个接口类型。接口既可用下面的那个图标来表示(上面一个圆圈符号,圆圈符号下面是接口名,中间是直线,直线下面是方法名),也可由附加了<<interface»的一个标准类来表示。通常,根据接口在类图上的样子,就能知道与其他类的关系。\n”,”richText”:{“ops”:[{“insert”:”接口是一系列操作的集合,它指定了一个类所提供的服务。它直接对应于Java中的一个接口类型。接口既可用下面的那个图标来表示(上面一个圆圈符号,圆圈符号下面是接口名,中间是直线,直线下面是方法名),也可由附加了<<interface»的一个标准类来表示。通常,根据接口在类图上的样子,就能知道与其他类的关系。\n”}]},”background”:”transparent”},”children”:[]}]

关 系:

###### 1. 依赖(Dependency)

1.1.1 依赖(Dependency):虚线箭头表示 1、依赖关系也是类与类之间的联结 2、依赖总是单向的。(#add 注意,要避免双向依赖。一般来说,不应该存在双向依赖。) 3、依赖关系在 Java 或 C++ 语言中体现为局部变量、方法的参数或者对静态方法的调用。

(软件开发中,往往会设计一些公用类,供别的类调用,如果这些公用类出问题了,那调用这些公用类的类都会因此而出问题。 两个元素之间的一种关系,其中一个元素(提供者)的变化将影响另一个元素(客体),或向它提供所需信息 显示一个类引用另一个类)

方法参数示例:

复制代码 public class Person { void buy(Car car) { … } } 复制代码

表示方法:虚线加箭头

特点:当类与类之间有使用关系时就属于依赖关系,不同于关联关系,依赖不具有“拥有关系”,而是一种“相识关系”,只在某个特定地方(比如某个方法体内)才有关系。

依赖关系可以分为以下四类: 1) 使用依赖(Usage)表示客户使用提供者提供的服务以实现它的行为,包括:

使用<<use»–声明使用一个类时需要用到已存在的另一个类。 调用<<call»–声明一个类调用其他类的操作的方法。 参数<<parameter»–声明一个操作和它的参数之间的关系。 发送<<send»–声明信号发送者和信号接收者之间的关系。 实例化<<instantiate»–声明用一个类的方法创建了另一个类的实例。 2) 抽象依赖(Abstraction)表示客户与提供者之间用不同的方法表现同一个概念,通常一个概念更抽象,一个概念更具体。包括:

跟踪<<trace»–声明不同模型中的元素之间存在一些连接但不如映射精确。 精化<<refine»–声明具有两个不同语义层次上的元素之间的映射。 派生<<derive»–声明一个实例可以从另一个实例导出。 3) 授权依赖(Permission)表达提供者为客户提供某种权限以访问其内容的情形。包括:

访问<<access»–允许一个包访问另一个包的内容。 导入<<import»–允许一个包访问另一个包的内容并为被访问包的组成部分增加别名。 友元<<friend»–允许一个元素访问另一个元素,不管被访问的元素是否具有可见性。 4) 绑定依赖(Binding)较高级的依赖类型,用于绑定模板以创建新的模型元素,包括:

绑定<<bind»–为模板参数指定值,以生成一个新的模型元素。

  • 依赖(Dependency)关系是一种使用关系,它是对象之间耦合度最弱的一种关联方式, 是临时性的关联。在代码中,某个类的方法通过局部变量、 方法的参数或者对静态方法的调用来访问另一个类(被依赖类)中的某些方法来完成一些职责。

###### 2. 关联(Association)

￿[{“data”:{“id”:”cf32akd93z40”,”created”:1634613972776,”text”:”实体之间的一个结构化关系表明对象是相互连接的。箭头是可选的,它用于指定导航能力。如果没有箭头,暗示是一种双向的导航能力。在Java中,关联转换为一个实例作用域的变量,就像图E的“Java”区域所展示的代码那样。可为一个关联附加其他修饰符。多重性(Multiplicity)修饰符暗示着实例之间的关系。在示范代码中,Employee可以有0个或更多的TimeCard对象。但是,每个TimeCard只从属于单独一个Employee。”,”richText”:{“ops”:[{“attributes”:{},”insert”:”实体之间的一个结构化关系表明对象是相互连接的。箭头是可选的,它用于指定导航能力。如果没有箭头,暗示是一种双向的导航能力。在Java中,关联转换为一个实例作用域的变量,就像图E的“Java”区域所展示的代码那样。可为一个关联附加其他修饰符。多重性(Multiplicity)修饰符暗示着实例之间的关系。在示范代码中,Employee可以有0个或更多的TimeCard对象。但是,每个TimeCard只从属于单独一个Employee。”},{“insert”:”\n”,”attributes”:{}}]},”background”:”transparent”},”children”:[]}]

关联(Association):实线箭头表示 1、关联关系是类与类之间的联结,它使一个类知道另一个类的属性和方法。 2、关联可以是双向的,也可以是单向的(#add还有自身关联)。双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。 3、在 Java 或 c++ 中,关联关系是通过使用成员变量来实现的。

复制代码 public class 徒弟 {

}

public class 唐僧 { protected: list<徒弟> tdlist; } 复制代码

表示方法:实线箭头

特征:表示类与类或类与接口之间的依赖关系,表现为“拥有关系”;具体到代码可以用实例变量来表示。(A类有一个成员变量保存的是B类的一个引用,也就是说由A类可以找到B类)

  • 关联(Association)关系是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系, 如老师和学生、师傅和徒弟、丈夫和妻子等。 关联关系是类与类之间最常用的一种关系,分为一般关联关系、聚合关系和组合关系。我们先介绍一般关联。

关联可以是双向的,也可以是单向的。在 UML 类图中, 双向的关联可以用带两个箭头或者没有箭头的实线来表示, 单向的关联用带一个箭头的实线来表示,箭头从使用类指向被关联的类。 也可以在关联线的两端标注角色名,代表两种不同的角色。

###### 3. 聚合(Aggregation)

￿[{“data”:{“id”:”cf32akd946w0”,”created”:1634613972776,”text”:”聚合是关联的一种形式,代表两个类之间的整体/局部关系。聚合暗示着整体在概念上处于比局部更高的一个级别,而关联暗示两个类在概念上位于相同的级别。聚合也转换成Java中的一个实例作用域变量。”,”richText”:{“ops”:[{“attributes”:{},”insert”:”聚合是关联的一种形式,代表两个类之间的整体/局部关系。聚合暗示着整体在概念上处于比局部更高的一个级别,而关联暗示两个类在概念上位于相同的级别。聚合也转换成Java中的一个实例作用域变量。”},{“insert”:”\n”,”attributes”:{}}]},”background”:”transparent”},”children”:[]}] ￿[{“data”:{“id”:”cf32akd8tag0”,”created”:1634613972776,”text”:”关联和聚合的区别纯粹是概念上的,而且严格反映在语义上。聚合还暗示着实例图中不存在回路。换言之,只能是一种单向关系。”,”richText”:{“ops”:[{“attributes”:{},”insert”:”关联和聚合的区别纯粹是概念上的,而且严格反映在语义上。聚合还暗示着实例图中不存在回路。换言之,只能是一种单向关系。”},{“insert”:”\n”,”attributes”:{}}]},”background”:”transparent”},”children”:[]}]

1.1.3 聚合(Aggregation):带空心菱形头表示 1、聚合关系是关联关系的一种,是强的关联关系。 2、聚合是整体和部分之间的关系,例如汽车由引擎、轮胎以及其它零件组成。 3、聚合关系也是通过成员变量来实现的。但是,关联关系所涉及的两个类处在同一个层次上,而聚合关系中,两个类处于不同的层次上,一个代表整体,一个代表部分。 4、关联与聚合仅仅从 Java 或 C++ 语法上是无法分辨的,必须考察所涉及的类之间的逻辑关系。

复制代码 public class 引擎 {

} public class 轮胎 {

} public class 汽车 { protected:引擎 engine; protected:轮胎 tyre[4]; } 复制代码

表示方法:空心菱形头

特征:属于是关联的特殊情况,体现部分-整体关系,是一种弱拥有关系;整体和部分可以有不一样的生命周期;是一种弱关联;

  • 聚合(Aggregation)关系是关联关系的一种,是强关联关系,是整体和部分之间的关系, 是 has-a 的关系。聚合关系也是通过成员对象来实现的,其中成员对象是整体对象的一部分, 但是成员对象可以脱离整体对象而独立存在。 例如,学校与老师的关系,学校包含老师,但如果学校停办了,老师依然存在。

###### 4. 合成(Composition)

￿[{“data”:{“id”:”cf32akd8vlk0”,”created”:1634613972776,”text”:”合成是聚合的一种特殊形式,暗示“局部”在“整体”内部的生存期职责。合成也是非共享的。所以,虽然局部不一定要随整体的销毁而被销毁,但整体要么负责保持局部的存活状态,要么负责将其销毁。”,”richText”:{“ops”:[{“attributes”:{},”insert”:”合成是聚合的一种特殊形式,暗示“局部”在“整体”内部的生存期职责。合成也是非共享的。所以,虽然局部不一定要随整体的销毁而被销毁,但整体要么负责保持局部的存活状态,要么负责将其销毁。”},{“insert”:”\n”,”attributes”:{}}]},”background”:”transparent”},”children”:[]}] ￿[{“data”:{“id”:”cf32akd8s680”,”created”:1634613972776,”text”:”局部不可与其他整体共享。但是,整体可将所有权转交给另一个对象,后者随即将承担生存期职责。Employee和TimeCard的关系或许更适合表示成“合成”,而不是表示成“关联”。”,”richText”:{“ops”:[{“attributes”:{},”insert”:”局部不可与其他整体共享。但是,整体可将所有权转交给另一个对象,后者随即将承担生存期职责。Employee和TimeCard的关系或许更适合表示成“合成”,而不是表示成“关联”。”},{“insert”:”\n”,”attributes”:{}}]},”background”:”transparent”},”children”:[]}]

1.1.4 组合(Composition):带实心菱形头的实线表示 1、合成关系是关联关系的一种,是比聚合关系还要强的关系。 2、它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期。

复制代码 class 肢 { } class 人 { protected: 肢 limb[4]; } 复制代码

表示方法:一般是实心菱形加实线箭头表示

特征:属于是关联的特殊情况,也体现了体现部分-整体关系,是一种强“拥有关系”;整体与部分有相同的生命周期,是一种强关联;

  • 组合(Composition)关系也是关联关系的一种,也表示类之间的整体与部分的关系, 但它是一种更强烈的聚合关系,是 cxmtains-a 关系。 在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不存在, 部分对象不能脱离整体对象而存在。例如,头和嘴的关系,没有了头,嘴也就不存在了。

###### 5. 泛化(Generalization)

￿[{“data”:{“id”:”cf32akd9luo0”,”created”:1634613972777,”text”:”泛化表示一个更泛化的元素和一个更具体的元素之间的关系。泛化是用于对继承进行建模的UML元素。在Java中,用extends关键字来直接表示这种关系。”,”richText”:{“ops”:[{“attributes”:{},”insert”:”泛化表示一个更泛化的元素和一个更具体的元素之间的关系。泛化是用于对继承进行建模的UML元素。在Java中,用extends关键字来直接表示这种关系。”},{“insert”:”\n”,”attributes”:{}}]},”background”:”transparent”},”children”:[]}]

1.1.5 泛化(Generalization): 带空心箭头的实线线表示 泛化(下图)表示一个更泛化的元素和一个更具体的元素之间的关系。泛化是用于对继承进行建模的UML元素。在Java中,用extends关键字来直接表示这种关系。

泛化关系表示类与类之间的继承关系,接口与接口之间的继承关系。如下图:

  • 泛化(Generalization)关系是对象之间耦合度最大的一种关系, 表示一般与特殊的关系,是父类与子类之间的关系,是一种继承关系,是 is-a 的关系。

###### 6. 实现(Realization)

￿[{“data”:{“id”:”cf32akd9t1k0”,”created”:1634613972777,”text”:”实例关系指定两个实体之间的一个合同。换言之,一个实体定义一个合同,而另一个实体保证履行该合同。对Java应用程序进行建模时,实现关系可直接用implements关键字来表示。”,”richText”:{“ops”:[{“attributes”:{},”insert”:”实例关系指定两个实体之间的一个合同。换言之,一个实体定义一个合同,而另一个实体保证履行该合同。对Java应用程序进行建模时,实现关系可直接用implements关键字来表示。”},{“insert”:”\n”,”attributes”:{}}]},”background”:”transparent”},”children”:[]}]

1.1.6 实现(Realization):空心箭头和虚线表示 实例(图I)关系指定两个实体之间的一个合同。换言之,一个实体定义一个合同,而另一个实体保证履行该合同。对Java应用程序进行建模时,实现关系可直接用implements关键字来表示。表达一种说明元素与实现元素之间的关系;

  • 实现(Realization)关系是接口与实现类之间的关系。 在这种关系中,类实现了接口, 类中的操作实现了接口中所声明的所有的抽象操作。

###### 关系之间关联与区别

1.聚合与组合

(1)聚合与组合都是一种结合关系,只是额外具有整体-部分的意涵。

(2)部件的生命周期不同

聚合关系中,整件不会拥有部件的生命周期,所以整件删除时,部件不会被删除。再者,多个整件可以共享同一个部件。 组合关系中,整件拥有部件的生命周期,所以整件删除时,部件一定会跟着删除。而且,多个整件不可以同时间共享同一个部件。

(3)聚合关系是“has-a”关系,组合关系是“contains-a”关系。

“弱”包含表示如果部门没有了,员工也可以继续存在; “强”包含表示如果部门没有了,员工也不再存在; 在做软件需求时,往往会将所有的包含关系画成“弱”包含,后面发现某些关系可以表示为“强”包含是,才转为实心菱形。

2.关联和聚合

(1)表现在代码层面,和关联关系是一致的,只能从语义级别来区分。

(2)关联和聚合的区别主要在语义上,关联的两个对象之间一般是平等的,例如你是我的朋友,聚合则一般不是平等的。

(3)关联是一种结构化的关系,指一种对象和另一种对象有联系。

(4)关联和聚合是视问题域而定的,例如在关心汽车的领域里,轮胎是一定要组合在汽车类中的,因为它离开了汽车就没有意义了。但是在卖轮胎的店铺业务里,就算轮胎离开了汽车,它也是有意义的,这就可以用聚合了。

3.关联和依赖

(1)关联关系中,体现的是两个类、或者类与接口之间语义级别的一种强依赖关系,比如我和我的朋友;这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。

(2)依赖关系中,可以简单的理解,就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但是B类的变化会影响到A。

4.泛化和实现

实现表示类对接口的实现关系,表示方式:用一条带有空心三角箭头的虚线指向接口。

泛化表示类与类之间的继承关系、接口与接口之间的继承关系,表示方式一条带有空心三角箭头的实线指向基类(父接口)。

5.综合比较

  这几种关系都是语义级别的,所以从代码层面并不能完全区分各种关系;但总的来说,后几种关系所表现的强弱程度依次为:

          组合>聚合>关联>依赖

  其中依赖(Dependency)的关系最弱,而关联(Association),聚合(Aggregation),组合(Composition)表示的关系依次增强。换言之关联,聚合,组合都是依赖关系的一种,聚合是表明对象之间的整体与部分关系的关联,而组合是表明整体与部分之间有相同生命周期关系的聚合。

而关联与依赖的关系用一句话概括下来就是,依赖描述了对象之间的调用关系,而关联描述了对象之间的结构关系。

(3) 对象图(Object Diagram),描述系统在某个时刻的静态结构;

(4) 组件图(Component Diagram),描述了实现系统的元素的组织;

(5) 配置图(Deployment Diagram),描述了环境元素的配置,并把实现系统的元素映射到配置上;

(6) 状态图(State Diagram),描述了系统元素的状态条件和响应;

(7) 时序图(Sequence Diagram),按时间顺序描述系统元素间的交互;

(8) 协作图(Collaboration Diagram),按照时间和空间顺序描述系统元素间的交互和它们之间的关系;

(9) 活动图(Activity Diagram),描述了系统元素的活动;

Other

包图

###### 包图是 UML 一種用以显示包和包之间的依赖关系的结构性图表。模型图能显示系统的不同视图,例如,多层应用程序。

组合结构图

###### 组合结构图是添加到 UML 2.0 中的新的图表之一。复合结构图与类图相似,是一种用于微观视角的系统建模组件图,而不是整个类的组成部分。它是一种静态结构图,显示了一个类的内部结构和这个结构所实现的协作。

轮廓图

###### 轮廓图 使您能够创建特定于域和平台的原型,并定义它们之间的关系。

序列图

###### 序列图根据时间序列展示对象如何进行协作。它展示了在用例的特定场景中,对象如何与其他对象交互。凭借先进的可视化建模功能,您只需点击几下即可创建复杂的顺序图。另外,Visual Paradigm 可以根据用例描述中定义的事件流生成序列图。

通訊圖

###### 与序列图类似,通訊圖也用于模拟用例的动态行为。与序列图相比,通訊圖更侧重于显示对象的协作而不是时间顺序。它们实际上在语义上是等价的,因此一些建模工具(如 Visual Paradigm)允许您从一个模型生成一个到另一个。

交互概览图

###### 交互概述图侧重于交互控制流程的概述,它是活动图的变体,其中节点是交互 (Interactions) 或交互发生 (Interaction Occurrences)。交互概述图描述了隐藏於消息 (Message) 和生命线 (Lifeline) 間的交互。

时序图

###### 时序图显示了既定时间内对象的行为。时序图是序列图的一种特殊形式,它俩之间的差异是轴反转,时间从左到右增加,生命线显示在垂直排列的独立隔间中。

内部结构图

###### 内部结构图(Internal structure diagram):显示分类器的内部结构 – 将分类器分解为其属性,部件和关系。

  • 结构化类(structured class),

  • 属性类(part),

  • 端口(port),

  • 连接器(connector),

  • 作用关系(usage)。

协作使用图

###### 协作使用图(Collaboration use diagram)显示系统中的对象彼此合作以产生系统的某些行为。

  • 协作(collaboration),

  • 连接器(connector),

  • 属性类(part),

  • 依赖(dependency)。

表现图

表现图(Manifestation diagram):用于显示工件的组件的显化(实现)和工件的内部结构。可以把它作为组件图和部署图的补充,组件图显示组件和分类器之间的组件关系,部署图表达把工件部署到部署环境。

由于表现图不是由UML 2.5规范定义的,因此可以使用组件图或部署图来显示通过构件显示的组件。

###### 表现形式(manifestation),

###### 组件(component),

###### 工件(artifact)。

网络体系结构图

###### 网络体系结构图(Network architecture diagram):用来显示系统的逻辑或物理网络架构的部署图 。在UML 2.5中没有正式定义。

  • 节点(node),

  • 交换机(switch),

  • 路由器(router),

  • 负载均衡器(load-balancer),

  • 防火墙(firewall),

  • 通信路径(communication-path),

  • 网段(network-segment),

  • 主干网(backbone)。

配置文件图

配置文件图(Profile diagram):作为UML标准的轻量级扩展机制的辅助图,它允许定义定制的原型、标记值和约束。概要文件允许对不同的UML元模型进行调整

平台(比如J2EE或.NET)或者 域(如实时或业务流程建模)。 配置图首次在UML 2.0中引入。

###### 配置(profile),

###### 配置类(profile-metaclass),

###### 模板(stereotype),

###### 配置扩展(profile-extension),

###### 配置参考(profile-reference),

###### 配置应用程序(profile-application)。

信息流程图

###### 信息流图(information-flow-diagrams):显示一些高度抽象的系统实体之间的信息交换。信息流在尚未完全明确或缺少细节的情况下,显示系统信息的流转过程。

  • 信息流(information-flow),

  • 信息项目(information-item),

  • 参与者(actor),

  • 类(class)。

行为状态机图

###### 行为状态机图(behavioral-state-machine)通过有限状态转换显示设计系统的一部分的离散行为。

  • 行为状态(behavioral state),

  • 行为转换(behavioral transition),

  • 伪状态(pseudostate)。

协议状态机图

###### 协议状态机图(protocol state machine diagrams):显示使用协议或某个分类器的生命周期,例如可以在分类器的每个状态下调用分类器的哪些操作,在哪些特定条件下以及在分类器转换到目标状态之后满足某些可选的后置条件。

  • 协议状态(protocol state),

  • 协议转换(protocol transition),

  • 伪状态(pseudostate)。

交互图

交互图(Interaction diagram)包括几种不同类型的图:

序列图(sequence diagrams), 通信图(communication-diagrams)(在UML 1.x中称为协作图), 时序图(timing diagrams), 交互概览图(interaction overview diagrams)。

###### 序列图(sequence diagrams),

  • 生命线(lifeline),

  • 执行申明(execution specification),

  • 消息(message),

  • 复合片段(Combined Fragment),

  • 交互使用(interaction use),

  • 状态不变式(state invariant),

  • 销毁(Destruction Occurrence)。

###### 通信图(communication-diagrams)(在UML 1.x中称为协作图),

  • 生命线(lifeline),

  • 消息(message)。

###### 时序图(timing diagrams),

  • 生命线(lifeline),

  • 状态或状况时间表(state or condition timeline),

  • 销毁事件(destruction event),

  • 持续约束(duration constraint),

  • 时间限制(duration constraint)。

###### 交互概览图(interaction overview diagrams)。

  • 交互概览图(interaction overview diagrams)通过一种活动图的变体定义交互,以促进控制流的概述。交互概述图侧重于交互或交互使用的控制流节点的概述 。生命线和消息不会出现在此概述中。

    • 初始节点(initial node),

    • 流最终节点(flow final node),

    • 活动最终节点(activity final node),

    • 决策节点(decision node),

    • 合并节点(merge node),

    • 分叉节点(fork node),

    • 连接节点(join node),

    • 交互(interaction),

    • 交互使用(interaction use),

    • 持续约束(duration constraint),

    • 时间限制(duration constraint)。

分类

不同架构视图的应用

(1) 用户模型视图

(1) 用例图(Use Case Diagram)

(2) 结构模型视图

(2) 类图(Class Diagram);

(3) 对象图(Object Diagram)

(3) 行为模型视图

(6) 状态图(State Diagram)

(7) 时序图(Sequence Diagram)

(8) 协作图(Collaboration Diagram)

(9) 活动图(Activity Diagram)

(4) 实现模型视图

(4) 组件图(Component Diagram)

(5) 环境模型视图

(5) 配置图(Deployment Diagram)

静态结构还是动态行为

静态结构

(2) 类图(Class Diagram);

(3) 对象图(Object Diagram)

(4) 组件图(Component Diagram)

(5) 配置图(Deployment Diagram)

动态行为

(1) 用例图(Use Case Diagram)

(6) 状态图(State Diagram)

(7) 时序图(Sequence Diagram)

(8) 协作图(Collaboration Diagram)

(9) 活动图(Activity Diagram)

4+1视图与UML视图对应

场景视图 use case

逻辑视图 类图

开发视图 类图,组件图

进程视图 无完全对应

部署视图 部署图

词汇表和术语

抽象类:一个永远不会被实例化的类。这个类的一个实例永远不会存在。

Actor:发起系统参与的事件的对象或人物。

活动:活动图中的步骤或行动。表示系统或演员采取的行动。

活动图:一个美化的流程图,显示了流程中的步骤和决定以及并行操作,如算法或业务流程。

聚合:是另一类的一部分。图中的包含类旁边有一个空心钻石。

工件:描述设计过程中某个步骤输出的文档。描述是图形,文字或其他组合。

关联:一个模型的两个元素之间的联系。这可能代表代码中的成员变量,或者人员记录与其所代表的人之间的关联,或者两类工作人员之间的关系,或者任何类似的关系。默认情况下,一个关联中的两个元素是相等的,并且通过该关联知道对方。一个协会也可以是一个可导航的协会,这意味着协会的来源端知道目标端,但反之亦然。

关联类:表示两个其他类之间的关联信息的类。

属性:可用于引用其他对象或保存对象状态信息的对象的特征。

基类:定义由子类通过泛化关系继承的属性和操作的类。

分支:活动图中的决策点。分支出现多个转变,每个都有一个保护条件。当控制到达分支时,恰好一个保护条件必须为真; 并且控制遵循相应的转换。

类:类似对象的类别,全部由相同的属性和操作描述,并且所有的赋值兼容。

类图:显示系统类和它们之间的关系。

分类器 :具有属性和操作的UML元素。具体来说,Actor,Classes和Interfaces。

协作:通信图中两个对象之间的关系,指示消息可以在对象之间来回传递。

通信图:显示如何在强调对象角色的同时完成操作的图表。

组件:系统中可部署的代码单元。

组件图:显示各种组件和接口之间关系的图表。

概念:要包含在域模型中的名词或抽象概念。

构建阶段:Rational统一过程的第三阶段,在这个阶段中,正在构建的系统中内置了多个功能迭代。这是主要工作完成的地方。

依赖关系:指示一个分类器的关系知道另一个分类器的属性和操作,但不直接连接到第二个分类器的任何实例。

部署图:显示各种处理器之间关系的图表。

域:系统所涉及的宇宙的一部分。

精化阶段:Rational统一过程的第二阶段,允许额外的项目计划,包括构建阶段的迭代。

元素:出现在模型中的任何项目。

封装:对象中的数据是私有的。

泛化:指示一个类是另一个类(超类)的子类。一个空心箭头指向超类。

事件:在状态图中,这表示导致系统采取行动或切换状态的信号或事件或输入。

最终状态 :在状态图或活动图中,这表示图完成的点。

叉:活动图中的一个点,多个并行控制线程开始。

泛化:继承关系,其中一个子类继承并添加到基类的属性和操作。

高凝聚力:GRASP评估模式,确保课程不是太复杂,做不相关的功能。

低耦合:GRASP评估模式,衡量一个类别依赖于另一个类别或与另一个类别相关联。

启动阶段:Rational统一过程的第一阶段,处理原始概念化和项目开始阶段。

继承:子类继承父类(超类)类的属性或特性。这些属性可以在子类中重写。

初始状态:在状态图或活动图中,这表示图开始的点。

实例:一个类像模板一样用来创建一个对象。这个对象被称为类的一个实例。可以创建任何数量的该类的实例。

接口:定义形成行为契约的属性和操作的分类器。提供者类或组件可以选择实现接口(即实现其属性和操作)。客户端类或组件可以依赖于接口,并因此使用提供者而不提供提供者的真实类别的任何细节。

迭代:一个小项目部分,在这个小项目中,一小部分功能被添加到项目中。包括分析,设计和编码的开发循环。

加入:活动图中的一个点,多个并行控制线程同步并重新加入。

成员:分类器中的属性或操作。

合并:活动图中的一个点,不同的控制路径汇集在一起​​。

消息:从一个对象到另一个对象的请求,要求接收消息的对象执行某些操作。这基本上是对接收对象中的方法的调用。

方法:对象中的函数或过程。

模型:中央UML神器。由各个元素组成的层次结构,以及元素之间的关系。

多重性:显示在领域模型中,表示外部概念框,表示与其他对象的分位数的对象数量关系。

可导航性:指示关系的哪一端知道另一端。关系可以具有双向可导航性(每一端意识到另一端)或单向导航(一端意识到另一端,但反之亦然)。

符号:创建分析和设计方法的图形化文档。

对象:对象:在活动图中,从活动接收信息或向活动提供信息的对象。在“协作图”或“序列图”中,参与图中所示场景的对象。通常:给定分类器(Actor,Class或Interface)的一个实例或示例。

包:逻辑上应该组合在一起的一组UML元素。

包图:所有元素都是包和依赖关系的类图。

模式:用于确定交互对象责任分配的解决方案。这是一个成功解决众所周知的常见问题的名称。

参数:一个操作的参数。

多态性:相同的消息,不同的方法。也用作模式。

私有:应用于属性或操作的可见性级别,指示只有包含该成员的分类器的代码才可以访问该成员。

处理器:在部署图中,代表可以部署代码的计算机或其他可编程设备。

受保护:应用于属性或操作的可见性级别,指示只有包含该成员或其子类的分类器的代码才能访问该成员。

公开:应用于属性或操作的可见性级别,指示任何代码都可以访问该成员。

读取方向箭头:指示领域模型中关系的方向。

实现:表示组件或类提供给定的接口。

角色:用于域模型,是关于角色角色的可选描述。

顺序图:一个图表,显示随着时间的推移对象的存在,以及随着时间的推移在这些对象之间传递的消息来执行一些行为。状态图图 - 显示所有可能的对象状态的图。

状态:在状态图中,这表示系统或子系统的一种状态:它在某个时间点所做的事情,以及其数据的值。

状态图:显示系统或子系统的状态,状态之间的转换以及导致转换的事件的图表。

静态:一个属性的修饰符,用于指示分类器的所有实例之间共享的属性只有一个副本。“操作”的修饰符,用于指示“操作”独立运行并且不在分类器的一个特定实例上操作。

刻板印象(Stereotype):一个应用于Model元素的修饰符,用于指示它通常不能用UML表示的东西。从本质上讲,定型允许你定义你自己的UML“方言”。

子类:继承由子类通过泛化关系定义的属性和操作的类。

互動區:活动图的一个元素,指示系统或域的哪些部分执行特定的活动。泳道内的所有活动都由泳道所代表的对象,组件或者演员负责。

时间拳击:每次迭代都会有特定目标的时间限制。

过渡:在活动图中,表示从一个活动或分支或合并或分叉或连接到另一个的控制流程。在国家图中,代表着一个国家向另一个国家的转变。

过渡阶段 - Rational 统一过程的最后一个阶段,在这个阶段,用户接受使用新系统和系统的培训,用户可以使用这个阶段。

统一建模语言( UML):统一建模语言( UML)利用文本和图形文档,通过在对象之间建立更紧密的关系,来增强软件项目的分析和设计

用例:在用例图中,表示系统响应来自Actor的某个请求所采取的操作。

用例图:显示参与者和用例之间关系的图表。

可见性:对属性或操作的修饰符,指示哪些代码可以访问成员。可见性级别包括公共,受保护和私有。

工作流程:一组产生特定结果的活动。

低代码平台

低代码开发平台(LCDP)是无需编码(0代码)或通过少量代码就可以快速生成应用程序的开发平台。通过可视化进行应用程序开发的方法,使具有不同经验水平的开发人员可以通过图形化的用户界面,使用拖拽组件和模型驱动的逻辑来创建网页和移动应用程序。低代码开发平台(LCDP)的正式名称直到2014年6月才正式确定,整个低代码开发领域却可以追溯到更早前第四代编程语言和快速应用开发工具。

Microsoft Platform

其包括 Power Apps, Power Apps Sutdio ,Power Apps Mobile, Power Platform Admin Center。

Power BI 商业表格 Power Apps 创建app Power Pages 网页 Power Automate 自动化流程 Power Virtual Agents。 聊天机器人

PCF(Power Apps Component Framework) 为程序员提供利用代码开发自定义组件。

Microsoft Dataverse 存储和管理业务应用程序使用的数据

流程自动化。

OPS

计算机软件管理中的基本概念以及定义性的东西

多关注最新国外行业消息和一些书籍

敏捷开发 scrum

  • 个体和互动高于流程和工具
  • 工作的软件高于详尽的文档
  • 客户合作高于合同谈判
  • 响应变化高于遵循计划

敏捷开发注重交流,交互,交付,变化。

软件工程

持续集成devops ci cd

grpc

脚手架:CLI – Command-Line Interface 命令行界面,俗称脚手架。脚手架就是一个大概的框架,是建筑学上的一个概念。

Etl 工具

Msbuild

新技术专项什么是企业中台

但是,时间一长大家就发现了,这些系统中有一些部分大同小异,在做第二个项目的时候并不用将所有的功能重写,可以把之前项目中那些共有的模块拿出来,稍作修改就可以在新项目中应用了。这就是中台的雏形。

转动的齿轮

抽象和解耦是软件开发铁律,同样也适用于中台系统。中台系统就是将“后台”系统中那些针对技术,业务,组织的通用“模块/服务”从原来固定的项目中抽离出来,并且使之能够成为一个自治的服务提供给更多的“前台”使用。

中台分为如下几类:

业务中台:例如:客户服务,结算中心,订单中心。

技术中台:通常我们会将服务进行拆解通过微服务的方式重新组织。每个微服务都是自我治理的,通过服务注册,服务网关,服务跟踪的方式让他们形成一个整体。技术中台的划分通常分为两个维度,第一个是基础服务,这些服务针对整个系统来说相对通用,如:日志服务,安全服务等等。第二个就是业务服务,这些服务都针对每个业务模块做划分,通常这些服务会根据业务的变化或者增量进行更新或者横向扩展。

数据中台:数据的获取通常需要经过数据采集,数据清洗/过滤,数据存储,数据归档几个步骤,最后才能通过数据服务的形式展现给用户。特别是针对客户端来说,同时通过数据中台提供的服务来获取数据的。数据中台会根据不同的业务场景,生成不同的数据服务,满足客户的需要。让前端不用关心数据处理过程,只专注于“数据服务”

组织中台:相关的人员组织

关于开源如果单纯享用成功不付出是不行的。开源的模式最好是相关组织,组织内都是贡献者,非贡献者需要购买商业许可。组织成员也要定期考核,不合格者剔除。当然那种来源给所有人类的贡献者自然是伟大的,但是却也培养出一批懒人,寄生虫!

红薯,组织结构

职能型

项目型