软件工程基础

2017-2-3

软件开发最初始是规模较小的程序,编写者和使用者是同一个人。

 

软件工程面对的问题:

1、产品很多时候根本不是用户想要的。

2、开发成本和进度难以估计。前期的估算到后期演变为指数级都常见。为了时间或成本进度而权宜之计常常影响产品质量。

3、软件产品的质量靠不住。软件质量保证技术如审查、测试因为主观或客观原因没有完全运用。

4、软件常常是不可维护的。缺乏乏文档资料。

 

 

软件危机的原因:软件本身的属性;开发和维护的方法不科学。

属性:

1、缺乏可见性;过程进展质量难以定量衡量。软件运行中发现错误可能就是在开发期间引入,而测试没有检测出来。软件维护意味着需要修改原来的设计,这使得维护异常艰难。

2、规模庞大,程序的复杂性随着程序的规模指数级上升,多人协作构建软件系统极端困难,涉及技术问题,分析方法,设计方法,形式说明,版本控制,需要有严格科学的管理

3、意识上重视开发,明确需求、测试维护、规范性等缺乏正确的认知。

 

软件不同阶段进行修改的成本差异巨大。越前成本越低。

软件维护的费用占软件总费用的55%-70%

 

 

软件是程序、数据以及相关文档的集合。程序是能完成预定功能和性能的可执行的指令序列。数据是程序能处理信息的数据结构。文档是开发使用和维护程序所需要的图文资料。

 

软件工程的中心课题是控制复杂性。把问题分解,各个部分是可理解的,各个部分保持简单的通信关系。这种方式不能降低整体复杂性,但是可变成可管理的。如何协作,明确规定每个人的责任和相互通信的方法,标准和规章。

软件工程师常常缺乏应用领域的相关知识。产品经理。

 

开发人员应该少而精,素质高。

 

 

软件工程包括技术和管理两方面,是技术和管理紧密结合的工程学科。所谓的管理就是通过计划、组织和控制,合理配置和使用资源达到既定的目标。

 

 

 

传统的方法是一个阶段一个阶段的顺序推进。前一个阶段的完成是后一个阶段的前提和基础。需要严格的管理复查才算结束。需要高质量的文档资料。优点是有条不紊,保证质量,提高可维护性,极大的提高成功率。缺点是当规模庞大,以及对软件需求模糊或随时间变化需求往往难以沿用。

传统方法是强调自顶向下顺序完成各个阶段的任务,一开始对于整体有相当明确的定义,然而人类的认知是一个渐进的过程。人的认知需要在继承已有的知识基础上,经过多次反复才能逐步深化,人的认知深化过程包括了从一般到特殊的演绎过程,也包括了特殊到一般的归纳思想。

面向对象的基本原则是尽量模仿人类的习惯,使开发软件的方法和过程接近人类认知世界,解决问题的方法和过程,从而使描述问题的问题空间与实现解法的解空间在结构上一致。

面向对象将数据和行为结合。

面向对象的方法是一个主动反复迭代的演化过程,面向对象的类即为特殊到一般的归纳思想,通过继承建立的等级体系即为一般到特殊的演绎过程。

面向对象的优点是促进了软件复用重用。面向对象的特点:抽象,继承,封装,多态性。

 

 

 

2017-2-4

软件生命周期:

1、软件定义时期

需求分析,定义解决的问题,定义目标系统,产品需求说明书。产品经理职责。

2、软件开发时期

总体设计是在较抽象的高层次上进行分析和设计问题。一个系统应该是由若干个规模适中的模块按合理的层次结构组织而成,总体设计需要确定系统由哪些模块构成以及模块间的关系。以较为抽象的概括方式提出了解决问题的方法。

详细设计是把总体设计的方案具体化。详细的规格说明。模块设计,详细的设计模块,确定模块功能的算法和数据结构。

编码和单元测试。

综合测试。集成测试和验收测试。集成测试是把通过了单元测试的模块按照某种策略组织起来,在装配过程中进行测试。验收测试是对需求分析阶段确定的系统交由用户进行测试验收。

3、软件维护时期

提出维护需求,分析维护需求,提出方案,确定方案,修改设计,修改程序,测试程序,复查验收。实际上是压缩和简化的软件工程。

 

常见的软件模型:

1、瀑布模型

需求分析验证、规格说明验证、设计验证、编码验证、综合测试、维护。

特点:阶段间具有顺序性和依赖性,前一阶段的输出是后一阶段的输入;推迟实现;文档驱动.

优点:强迫开发人员用规范的方法,每个阶段都被验证,每个阶段提交高质量文档,软件维护有基础。

缺点:在产品交付用户以前,用户只能通过文档了解产品是怎样的。事实证明,当用户开始接触一个软件,在头脑中关于该软件应该做什么的想法或多或少的会变化,当初提出的需求不完全适用了。要求用户不经过实践就完全提出准确完全的需求是不切实际的。瀑布模型完全依赖文档规格说明,可能导致最终的软件产品不是用户想要的。

2、快速原型模型

快速建立可以运行的原型,它所完成的功能往往是产品所有功能的子集。让用户使用,提出修改意见以后迅速迭代,再次使用。一旦用户认为原型系统可以完成工作,即开始编写文档,并根据文档进行开发。原型系统是通过与用户交互得到验证的。

 

采用瀑布模型和快速原型模型,目标都是一次把满足所有需求的产品提供给用户。

 

3、增量模型

把软件看作一系列的增量进行设计、编码、集成和测试。如第一个构件完成软件的最核心功能,之后的构件不断累加。增量模型逐步的分批提交产品。构件规模适中。

在实际工作中,增量模型的设计需要更加开放的设计,这是非常困难的。有构件无法集成在一起的风险。最好的是能在实现构件之前就完成所有的分析设计工作。

 

4、螺旋模型

适用于开发大规模的软件项目。项目越大,风险越大,进行风险分析必要性越大。螺旋模型是风险驱动的,管控风险也是异常困难的事情。

使用原型来降低风险,增加了风险分析过程的快速原型模型。

 

 

最佳实践建议:

1、迭代开发,线性开发不适用,一方面不可能开发大复杂的系统,同时需求常常变更。因此需要通过一系列细化和渐进反复过程得到有效解决方案的迭代方法。

2、管理需求。确定系统需求是一个连续的过程。

3、使用基于构件的体系结构。构件是功能清晰的模块或子系统。

4、可视化建模。模型是为了理解事物而对事物进行的抽象,可视化图形更易理解。

5、验证软件质量。质量评估贯彻开发过程,全员参与。

6、控制软件变更。修改都是可接受和可跟踪的。

 

 

迭代和渐增的思路。

 

 

敏捷过程:

1、可以工作的软件胜过面面俱到的文档。

2、客户合作胜过合同谈判,满足用户不断变更的需求。

3、响应变化胜过遵循计划。计划有灵活性和可塑性。

4、优先致力于构建开发团队,包括成员和交互方式,再根据需要配置项目过程和工具。

 

极限编程是敏捷过程中最有名的。极限指的是把好的开发实践运用到极致。广泛运用于需求模糊且经常变动的场合。

特点:

1、客户作为开发团队的成员。客户与开发紧密配合,客户负责确定需求,回答问题,验收。

2、短交付周期。两周一次迭代,交互目标系统可工作的版本,不断演示迭代生成的系统获得反馈意见。

3、结对编程,测试驱动开发。先有好的测试方案然后再编程,所有的测试工作完成了才算工作完成。

4、集成所有。程序代码归所有人所有,任何人都有修改代码的权利,全体成员对所有代码负责。

5、持续集成。多次集成系统,随着需求的变更,不断回归测试。

6、可持续开发速度,能维持长期稳定的速度,开放的工作空间,全体成员在开放场所工作,随时自由交流讨论。

7、及时调整计划。计划是灵活和循序渐进的。

8、重构。代码重构是在不影响系统行为的前提下,重新调整和优化系统的内部结构,降低复杂性,消除冗余,增加灵活性,提高性能。不要过分依赖重构,前期重设计。

 

面对变化和不确定性更加快速敏捷,能快速持续迭代渐增。

 

 

2017-2-5

分层,面对复杂的系统,比较好的方法是分层次的描述系统。分层的描述方式是从抽象到具体的过程逐步深入了解一个复杂的系统。

首先用系统流程图描述系统总体概貌,表明系统的关键功能。然后分别把关键功能扩展为适当的详细程度,画在单独的空间。

 

 

系统流程图:数据在系统各个部件之间的流动情况。部件(程序、文档、数据库、人工过程等)

数据流图:描述信息流和数据从输入移动到输出的过程总所经受的变换。考虑数据的起点和终点,考虑数据存储,任何改变数据的操作是处理。只描述数据在软件中的流动和被处理的逻辑过程。只需考虑系统必须完成的逻辑功能,不用考虑具体实现。

实体联系图(ER图):包含数据对象(实体)、关系和属性。描述用户的数据要求。数据对象是具有一系列性质或属性的事物,是复合信息的抽象。可以用一组属性来定义的实体都是数据对象,数据对象彼此是有关联的,1:11:nn:n

 

范式定义消除数据冗余的程度,第一范式1NF数据冗余程度最大,第五范式最小。满足第二范式的条件之一是满足第一范式。范式级别越高,存储相同的数据需要更多的表,因此存储本身就更加复杂,范式级别提高需求变化时稳定性差,需要访问的表增多,效率降低。

数据库设计三大范式:

1:原子性。数据库的字段都是具有单一属性的,不可再分。

2:唯一性。每个非主属性都完全函数依赖于键码。记录具有唯一标识。每列都跟主键有关系。(以一对多为例)

3:消除传递依赖。每个非主属性都不伟递领带于键码。即任何字段不能由其他字段派生出来,它要求字段没有冗余。一个非关键字属性值不依赖于另外一个非关键字属性值。

没有冗余的数据库设计可以做到。但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是:在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余。

 

 

 

 

 

状态转换图:通过描述系统的状态以及引起系统状态转换的事件来表示系统的行为。

状态是任何可以被观察的系统行为模式。系统对事件的响应,可以是一个或一系列动作,也可以是改变状态,还可以是both.

IPO图是输入、处理、输出图,描述输入数据,对数据处理和输出数据的关系。

 

实体联系图建立数据模型,数据流图建立功能模型,状态图建立行为模型。IPO描述算法模型。

 

 

按照形式化的程度,可以把软件工程使用的方法划分为非形式化,半形式化和形式化三类。自然语言来描述需求规格说明是非形式化方法,数据流图或实体联系图来建立模型是半形式化方法。描述系统性质是基于数学基础的则是形式化方法。

自然语言描写规格说明书可能出现矛盾,二义性,含糊,不完整,抽象层次混乱的问题。

 

 

 

2017-2-6

总体设计,设计软件结构,确定由哪些模块构成以及模块间的关系。模块处于黑盒级别。

总体设计阶段产生逻辑模型,分析物理实现方案以后根据最优方案实现。

设计软件结构:通常程序的一个模块完成一个适当的子功能,应该把模块组织成良好的层次系统,顶层模块调用下层模块,下层调用更加下层,最下层的完成具体功能。

总体设计可以重点尝试使用数据流图。分析数据流图中的每一个处理,如果处理的功能过于复杂,切分为一系列简单的功能。最终可以考虑使用IPO图定义处理的算法。

系统说明:用系统流程图描绘系统的构成方案,层次图或结构图描述软件结构(即由模块组成的层次系统),数据流图描述定义功能,IPO图描述算法。

 

设计原理:

模块是构成软件的基本构件,模块化是为了使一个复杂的系统为人的智力所能管理,是软件应该具备的唯一属性。模块化把程序划分为可独立命名和访问的模块,每个模块完成一个子功能,模块集成构成整体。

如果一个问题由两个问题组合而成,那么它的复杂程度要大于分别考虑两个问题的复杂程度之和。当模块数量增加,每个模块的规模将会减少,但是设计模块间的接口将会增加工作量。每个软件有相应的大小最适当的模块规模。

模块化的原理使得软件结构清晰,软件容易阅读和理解,程序的错误常常是在接口间或是模块内,模块化使得软件容易调试和测试。模块化有助于工程管理。

 

人们认知复杂事物强有力的思维工具是抽象,抽象是抽出事件的本质不考虑细节。由于人的思维能力的限制,如果面对的因素太多是不能产生精确思维的,处理复杂系统的唯一有效的方式是用层次的方式构造它。一个复杂的系统可以由一系列的抽象概念来构造,如此下去不断重复直至最底层的具体元素。

顶层设计与逐步求精。自顶向下,从抽象到具体的方式分配控制.简化软件的设计和实现,提高软件的可理解和可测试性,并且使得软件更加易于维护。

逐步求精:为了集中精力解决主要问题而尽量推迟对问题细节的考虑。

Miller法则,一个人的注意力的极限是集中注意力在7+-2个事物上。这是对人类能力的研究得到的结果:一个人能力的极限也只能把注意力集中在7+-2个信息块。这就像人弹跳的极限,人忍受肌饿的极限一样,是不可改变的客观因素。它很大程度上限制人的思维能力。

承认自身的局限性,并在这个前提之下最大化努力的工作。

逐步求精的强大在于,帮助人把精力集中在当下最相关的事物上,忽略、留在以后考虑其他细节。

信息隐藏原理,一个模块内包含的信息(过程和数据)对于不需要这些信息的模块是不可访问的。局部化,把关系密切的软件元素物理的放得比较近。实际上,应该隐藏的是模块的实现信息。独立的模块之间彼此交换那些为了完成系统功能必须交换的信息。隐藏原理对于模块化程序设计有极大的好处,对于测试和维护,修改涉及的错误会很少的传播到其他部分。

 

2017-2-7

具有独立功能,与其他模块之间没有过多的相互作用的模块极为模块独立。独立的模块易于测试和维护,错误传播范围小。评判模块独立有两个定性标准度量,内聚和耦合。耦合衡量不同模块之间互相依赖(连接)的紧密程度。内聚是模块内元素结合紧密程度。

低耦合便于研究、测试维护任意模块不需要对其他的模块了解太多。由于模块间的联系简单,因此错误传播范围小。一个模块与另外的模块完全无关就是无耦合。数据耦合:模块间通过参数传递数据。控制耦合:模块间传递的信息包括控制信息。数据耦合是低耦合,控制耦合是中等程度的耦合,增加了系统的复杂情况。控制耦合往往是多余的,把模块适当的分解往往可以用数据耦合取代。

总体设计基本目的是用抽象概括的方式确定系统如何完成预定的任务。

软件结构设计,确定软件由哪些模块组成以及模块间的调用关系。结构图和层次图描述软件结构。系统-模块-子模块。软件设计应该遵循的主要原理是模块独立原则,软件应该由一组完成相对独立的子功能的模块构成,模块间的接口关系尽量简单。

抽象和求精是互补的概念,是人类解决复杂问题时最常用和最有效的方法。由抽象到具体构造出软件的层次结构。

 

测试,测试的目标是暴露程序中的错误,从心理学角度来讲,程序的编写者来测试是不恰当的。

测试的准则:1、建立设计模型以后就能立即开始设计详细的测试方案;2、先小规模测试,然后逐步大规模,先测试单个程序模块,然后测试集成模块,然后测试整个系统。3、穷举测试不切实际,设计测试方案,覆盖程序的逻辑。

黑盒测试(功能测试),不考虑程序内部的结构和处理过程。只检查程序是否能按照需求说明书的规定正常使用,程序是否能适当接收输入数据并产生正确的输出数据。

白盒测试(结构测试),完全获悉程序的结构和处理算法。根据程序内部的逻辑测试程序,检测主要执行通路是否按照预定的工作。

模块测试、集成测试、系统测试、验收测试(用户参与)、平行测试。平行测试:验收完成后并不立即投入运行,而是需要将新的系统和旧系统同时运行,比较。优点如下:风险小,意外可控,验证性能指标。

测试方案中的测试用例不仅仅包括测试使用的测试数据,还有每组数据需要检测的功能以及预期正确输出。

 

2017-2-8

单元测试,检测软件的最小单元,即模块。一般而言单元测试和编码属于同一阶段。单元测试通常是白盒测试。

测试重点:1、模块接口,输入输出;2、局部数据结构;3、重要执行通路;4、出错处理通路;5、边界条件

集成设计,模块按照设计要求组装起来测试,主要发现接口有关的问题。渐增式测试,把下一个要测试的模块同已经测试好的模块结合起来进行测试,测试完再集合下一个模块进来。

回归测试,重新执行已经执行过的测试,保证由于调试等其他原因引起的变化,不会带来额外的副作用。

确认测试也是验收测试,验证软件的有效性。软件的功能和性能如同用户所期待软件就是有效的。需求规格说明书是确认测试的基础。确认测试是用户参与的黑盒测试。

Alpha测试,用户在开发者的场所进行,并在开发者的陪同下接受测试,在受控的环境下测试。Beta测试,开发者不在现场。

所谓的测试方案是测试目的(即要测的功能),输入的测试数据,预期结果。通常把输入的测试数据,预期结果叫做测试用例。

逻辑测试,有选择的执行程序中的最具有代表性的通路是对穷尽测试的唯一可行的替代方案。

调试,在错误发生排除错误的过程。方法:1、回溯法,针对小程序比较有效,从发现症状的开始,人工沿着程序的控制流追踪错误。2、对半查找法,在调试模块中央位置注入正确变量值,然后运行程序检查输出。

白盒测试和黑盒测试相结合。白盒测试主要技术有逻辑覆盖和控制结构测试。黑盒测试方案有等价划分、边界值分析、错误推测。(黑盒测试白盒测试需要单独处理)

软件维护:改正错误或满足新的需要而修改软件的过程。

逆向工程:分析程序以便在代码抽象层次更高的基础上把握产品。抽取数据、体系结构、处理过程等信息。

 

2017-2-10

面向对象的基本原则和思想,尽可能模仿人类的思维方式,模仿人是怎么认识世界和解决问题的方法和过程,描述问题的问题空间和实现解法的解空间在结构上尽可能一致。

客观世界的问题是由客观世界的实体以及实体之间的相互关系构成的。客观世界的实体既有静态的属性,又有动态的行为。

面向对象认为1、客观世界由各种对象组成,任何事物都是对象,复杂的对象是由简单的对象以某种方式构成的。2、所有对象被划分为类,每个类定义了一组数据和方法。3、子类父类之间的继承关系构成一定的层次结构。4、对象间通过传递消息联系。私有信息被封装。

传统的方法把数据和过程作为相对独立的部分,数据代表问题空间的实体,程序代码用于处理数据。软件系统的问题空间和解空间并不一致。实际上,计算机解决的问题都是实际问题,实际问题即是相互之间存在联系的物体所组成,每个具体的物体都具有属性和行为。完整自然的描述客观世界的实体的方法是同时描述事物静态的数据结构和动态行为。

面向对象的思路强调现实世界中的概念,而不是算法。计算机的观点不重要,现实的模型重要。

对问题领域进行自然的分解,确定要使用的对象和类,建立适当的类等级,按照人们的思维习惯建立问题领域的模型。

传统的软件开发方法是瀑布模型,强调自顶向下按部就班,然而人们认知世界的方式是渐进的,继承之前的知识反复逐步深化。人的深化过程中包括从一般都特殊的演绎,也包括从特殊到一般的归纳。人们认识和解决复杂问题的思维工具是抽象。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章