模型建立的基本理念
模型是对现实世界复杂系统的简化和抽象,目的是为了更好地理解、分析和预测系统的行为。它能够真实反映研究对象的整体结构 or 某一侧面(功能、反应)的本质特征和变化规律。可以建立不同的子模型用于反应系统不同的侧面。同时,也可以使用不同的方法学:结构化方法学Structured和面向对象方法学Object-Oriented。
结构化需求分析方法
结构化方法学是一种逻辑过程,它按照顺序、选择和迭代的方式来定义。其特点为:
- 突出过程和步骤。
- 适用于简单、线性和有明确定义的任务。
自顶向下,逐步求精。一定对应着迭代的过程!
对于逻辑模型(WHAT,我要做什么?),构建以下三个子模型:
数据层面:信息域的概念模型。ER。就是建立数据库的ER图。
功能层面:使用数据流图。DFD。数据的流动能够体现模型的功能。
行为层面:状态-迁移图。实时监控,自动化系统。STD。系统对外部事件的响应情况。
数据模型
行为模型
功能模型
数据流出现的地方,一定有加工部分。数据流流动的动力来自于加工部分。可以是加工与加工部分,也可以是加工与存储部分,也可以是加工与源点、终点的部分,但不能脱离加工。
注意数据流的命名要明确、规范,便于存储固定成分。
可以简单记为:*代表&&,+代表&&和||, 代表限流(只能允许选择一个进入或产出)。
数据的源点终点主要作用是确定系统边界。告诉我们用户是谁,便于访谈等需求分析的实施。
基本思想
搞好了,就能够交给开发者了。
上图中的事务就相当于mysql中的changelog,作为更新过程经过处理可以变成实际操作——更新库存信息,并且从数据库中提取库存信息,包括库存信息临界值。
注意事项
可以把同一层分成若干个子图,有所侧重扩展具体的加工过程,最后再合并。
画图有一个7+-2法则,涉及到认知科学,超过这个法则就使得读者难以理解。
结构化方法中的子图
在结构化设计和分析中,为了更清晰地展示和理解系统的各个部分,通常会将大的、复杂的系统分解成多个更小、更简单的部分或子系统。这些子系统可以通过子图来表示。
子图的目的:
- 简化复杂性:大型系统可以非常复杂,将其分解成小的子系统或组件可以使设计和分析过程更容易进行。
- 便于管理:当处理大型项目时,子图允许团队成员在不同的部分上并行工作。
- 重用和模块化:子系统或子图中的某些部分可能在其他项目中重用。
合并:一旦各个子图或子系统已经被定义和设计,它们可以被组合或集成到一个完整的系统中,保证整体功能和性能。
7±2法则
7±2法则是认知科学中的一个概念,它指的是人类短期记忆的容量大约在5到9个信息项之间,平均为7个。这是乔治·A·米勒在1956年的一篇文章中首次提出的。
应用:
- 在界面设计中,为了保持用户界面简洁和易于理解,通常建议一次只显示7±2个选项或信息项。
- 在教育和培训中,为了确保学员能够有效地吸收和记住信息,内容通常被分为5到9个部分。
扩展理解:尽管7±2法则被广泛引用,但后续的研究表明,实际的数字可能更接近4。然而,这个原则的关键点是,人们的短期记忆容量是有限的,设计时应尽量简化信息和任务,以避免超出这个容量。
结合这两方面的内容,当使用结构化方法创建子图或设计系统时,应考虑7±2法则,以确保每个子图或组件不会过于复杂或包含过多的信息,从而确保易于理解和管理。
1. 当我们在DFD中解释或描述某个概念时,如果需要使用“、”、“和”、“以及”、“或者”这样的连词,很有可能表示这个概念或主题并没有被适当地分解或结构化。
这在写作、报告撰写、教程制作等多个领域都是一个常见的现象。
2. 千万不要有加工条件(如果……就这么加工),否则会带来控制流。
SRS(需求分析规格说明书)
SRS(软件需求规格说明书)是一个详细的文档,它描述了系统应该如何运行和功能。在功能需求部分,有必要进行详细的需求规约。
假定的输入方式:
- 这部分详细描述了用户如何与系统交互。这可能包括:键盘输入、鼠标点击、触摸屏手势、语音指令等。
- 需要明确指出可以输入什么类型的数据,例如:文本、数字、日期等。
响应异常条件:
- 这部分描述了系统在遇到异常或错误输入时的行为。例如:如果用户输入了无效的日期,系统应该如何响应?
- 可能包括错误消息、警告、日志记录等。
考虑系统的内部状态:
- 这部分描述了系统在不同状态下的行为。比如“老师-学生”在系统中的不同用户角色,要区分他们的相应权限和功能。
- 例如,老师可能能够发布作业,而学生只能提交作业。当系统识别用户角色为“老师”时,应该提供发布作业的功能。
除了上述内容,SRS还可能包括其他关键部分,如:
- 系统的总体描述:简要描述系统的目的、范围和用户。
- 性能需求:描述系统的性能指标,如响应时间、处理能力等。
- 设计约束:可能涉及到的技术、法律或合同约束。
- 接口需求:描述系统与其他系统或硬件的交互。
确保SRS是完整的、一致的和无歧义的,因为它通常作为开发团队和客户之间的正式协议,并指导整个开发过程。
虚拟仿真实验最后一个图要保存在大作业的附录
系统流程图
包含物理部件的数据流动情况。图题一定要准确,一定要明确自己画的是流程图还是系统流程图还是数据流图,明显区别在于是数据流还是控制流。
- 描述系统中各个物理部件之间的互动和流动,既可以是数据流也可以是控制流。
- 它更偏重于表示系统的物理组件(如硬件设备)和这些组件之间如何交互。
- 例如,在计算机网络中,系统流程图可能会显示路由器、交换机、服务器以及它们之间的数据包流动情况。
需求分类
在软件工程中,需求是系统应有的特性、功能和性能等方面的描述。根据其性质和描述的内容,需求可以被分类为以下几类:
-
功能需求(Functional Requirements,需求主体):
- 定义:描述了系统应当执行的任务或功能。
- 内容:它们指定了系统能够提供的服务,例如:“系统应该允许用户注册新账号”或“系统应能处理在线支付”。
- 用户方面的需求可能会出现描述不严密的情况,所以往往采用系统需求。
-
非功能性需求(Non-Functional Requirements):
- 定义:描述了系统的性能、可靠性、安全性等质量属性,而不是具体功能。
- 内容:例如,数据备份频率、系统的可用性标准、数据加密方法等。
- (大作业中增加一到两个)
-
性能需求(Performance Requirements):
- 定义:描述了系统的性能标准。
- 内容:例如,系统的响应时间、处理能力、用户并发数等。
- 解决方法:为了确保明确性,常常需要对这些需求进行量化,例如:“95%的请求应在2秒内得到响应”。
-
环境需求(Environmental Requirements):
- 定义:描述了系统运行的硬件、软件、网络和其他环境条件。
- 内容:例如,服务器的硬件配置、操作系统版本、支持的浏览器类型等。
-
质量属性(Quality Attributes):
- 定义:描述了与系统整体质量相关的需求。
- 内容:例如,可维护性、扩展性、可靠性、安全性等。
需求分类的意义
需求分类的主要目的是帮助项目团队更好地理解、沟通和满足客户的期望。明确分类可以:
- 确定需求获取方法:不同类型的需求可能需要不同的获取方法,如访谈、观察、问卷调查等。
- 明确访谈对象:例如,性能需求可能需要与系统管理员沟通,而功能需求可能需要与终端用户沟通。
通过这种方式,需求分类确保了项目团队可以全面、准确地收集和记录所有相关的需求,从而为项目的成功奠定坚实的基础。
面向数据流与快速原型法
面向数据流的分析方法与快速原型法是两种不同的需求分析和获取方法。而面向数据流分析法,是比快速原型更精细的需求获取方法。
面向数据流的分析方法(Data Flow Oriented Analysis)
-
定义:面向数据流的分析方法是一种系统分析方法,它侧重于捕获、表示和分析在系统中流动的数据的过程。通常使用数据流图(DFD)来描述系统的数据流、过程、数据存储和外部实体。
-
优点:
- 结构化:提供了一种系统的层次化和模块化表示,使其更易于理解。
- 专注于数据:这种方法强调了数据在系统中的流动和处理,这对于数据密集型的应用尤其重要。
- 清晰地定义界限:通过明确的外部实体和数据存储,可以明确地界定系统的范围和边界。
-
缺点:
- 可能不足以捕获某些复杂的用户交互或界面元素。
- 可能需要多轮迭代来完善和细化。
应用场景:
- 当系统的核心是数据流和数据处理时。
- 当项目的需求比较明确,且对数据流和数据交互有明确的要求时。
快速原型法(Rapid Prototyping)
-
定义:快速原型法是一种需求获取和验证方法,它侧重于快速创建系统的工作模型或原型,以便用户能够看到和与其交互。
-
优点:
- 直观:用户可以实际看到和体验原型,这有助于消除歧义和误解。
- 快速反馈:开发人员可以迅速获得用户的反馈,并相应地进行调整。
- 适应性:允许在开发过程中进行迭代和更改,这特别适用于需求不明确或可能发生变化的项目。
-
缺点:
- 原型可能被错误地视为最终产品,导致关键需求或结构问题被忽视。
- 如果不适当地管理,可能会导致项目范围的膨胀。
应用场景:
- 当项目的需求不是很明确或可能会发生变化时。
- 当需要快速地收集用户反馈和调整需求时。
总结
数据流分析方法通常更细致,而快速原型法更加灵活和迭代。在实际的项目环境中,这两种方法可以结合使用,以确保需求的完整性和准确性。
对于数据密集型的应用或需求明确的项目,可以首先使用面向数据流的分析方法定义和描述系统的数据流,然后使用快速原型法验证这些数据流与实际的用户交互和界面是否一致。
对于需求不明确或可能会发生变化的项目,可以首先使用快速原型法收集和验证用户需求,然后使用面向数据流的分析方法为已验证的需求提供更细致的描述。
第四章 系统设计
体系结构的起源——软件系统的复杂性
能否通过复用的方式降低软件开发的复杂性?
很多非功能需求来自于软件本身的体系结构,规格说明和结构设计大于数据结构算法。体系结构能够提升我们对于非功能性需求的要求。
软件开发阶段
软件开发经历了许多发展阶段,从简单的函数编程到现代的面向服务设计。这个演变的过程中,主要的目标是提高软件的可维护性、可复用性、可扩展性和可靠性。
以下是各个发展阶段介绍:
函数(Function)
- 早期的软件设计主要基于函数和过程。每个函数具有特定的任务或功能。
- 信息隐藏: 每个函数内部的实现细节对外部是隐藏的。
- 接口简单: 通过参数传递数据并返回结果。
- 低耦合: 通过模块化和适当的函数设计,可以实现函数之间的低耦合。
对象(Object)
- 在面向对象的设计中,软件被视为对象的集合,这些对象可以代表现实世界中的实体或概念。
- 信息隐藏: 通过私有变量和公有方法实现。
- 接口简单: 对象提供的方法定义了它与外部世界的交互方式。
- 低耦合: 通过继承、多态和封装,对象可以独立于其他对象。
构件(Component)
- 构件是独立的、可重用的模块化软件单位。它们封装了特定的功能或服务,并通过定义好的接口与其他构件交互。这些构件可以被看作是软件中的积木,它们可以组合在一起创建更大的系统或应用。
- 信息隐藏: 构件的内部实现被完全封装,用户只能看到其接口。
- 接口简单: 构件的接口应当简洁明了,提供明确的功能或服务。
- 低耦合: 通过明确定义的接口和消息传递,构件之间的交互可以降低耦合。
面向服务(Service Oriented)
- 面向服务的架构(SOA)视应用程序为一组提供特定功能的服务集合,每个服务都是独立的并专注于完成单一任务。
- 这种架构的核心思想是提供一个灵活、可扩展和可复用的设计,其中服务通常由跨网络的不同系统提供,并通过标准化的接口进行通信。
- 为了实现这种设计,开发者通常会依赖某种框架(如Web服务框架)来实现服务的创建、发布、发现和通信。
- 尽管服务各自独立,但它们的设计都重视信息的隐藏、简洁的接口和低耦合性。这确保了各服务之间可以方便地进行互操作,同时还保留了各自的独立性和可维护性。
也就是说,构件思想:系统分解,每个构件包含一定的功能;而面向服务架构思想:系统分解成各个独立的服务,每个服务对应一个任务。
构件分解: 当我们说到构件,我们是指系统中的独立、可重用的模块或单位。这些构件通常会封装特定的功能或逻辑,并通过定义好的接口与其他构件或系统进行交互。构件的设计使得它们可以在不同的应用程序或系统中重复使用,从而提高开发效率和软件质量。
服务分解: 在面向服务的架构(SOA)中,系统则是由一系列服务组成,每个服务对应一个特定的任务或功能。这些服务是独立的,可以跨网络边界进行通信,并且被设计为可复用的。例如,一个服务可能处理用户认证,而另一个服务处理支付事务。服务之间通过定义明确的接口(例如APIs)进行通信,这些接口提供了一种标准化的方式来请求服务的功能。
整体上,从函数到面向服务的演变过程体现了软件设计的核心思想,即封装细节、简化接口并降低系统间的耦合。这使得软件更加模块化、可维护和可扩展。