我们将学到什么
在这篇文章中,我们将讨论。
- 什么是非功能需求,为什么了解它们可以帮助我们更好地设计系统,满足客户和最终用户的需求。
- 非功能需求与功能需求如何比较。
- 处理非功能需求的最佳实践。
什么是非功能需求?
功能性需求描述了系统应该做什么(即:用例或功能),非功能性需求(有时称为约束或行为需求)描述了系统应该是什么(即:系统级属性)。
对于功能需求,如果我们遵循功能驱动的文件夹结构,就可以比较容易地追踪到我们应用中的各个功能片或模块。
然而,非功能需求--这些是系统级属性。由于它们描述的是整个系统,所以要追踪到代码库中的某个位置要难得多(有时甚至不可能)。
非功能需求的类型
没有一个有效的非功能需求的明确列表。其中一些也可以被看作是相关的或在彼此的保护伞内(例如:我们可以把性能或速度定义为效率内的NFR)。
为了让我们开始,这里有一个简短的列表。
- 容量 - 我们能存储多少数据?我们的存储空间会不会用完?
- 监管 - 地方、区域、省或州的法律或法规是否规定了我们在法律上允许做的某些方面?
- 可移植性--我们应该期望软件能在哪些浏览器、操作系统和版本上运行?它是跨平台的吗?
- 可靠性--我们可以期望系统多长时间可以使用?它是如何处理关键故障的?系统在发生故障后需要多长时间才能重新上线?
- 性能--请求的处理速度应该有多快?在任何时候我们能处理多少个请求?当系统处于重载时,我们对响应时间应该有什么期望?
- 本地化 - 系统能否适应其他州或省的测量系统、时区和其他当地的特定概念?
非功能需求的例子
假设一个交易应用程序的功能需求是确保当用户执行getOffers
用例时,他们会看到一个报价清单,那么一个更大范围的非功能需求可能会说。
- 可扩展性、性能、效率。"网站应该在4秒或更短的时间内处理每个请求,99%的时间。"
- 可扩展性,性能。在标准的网络条件下,当网站的同时用户总数超过50,000人时,网站应在5秒内完全加载。"
- 安全性、数据完整性、容量。"每一个对资源的未经授权的请求都必须被记录下来,并在未来5年内储存起来供审计。"
执行与演变的质量
因为有这么多不同的非功能需求,思考它们的一个好方法是把它们看作是执行质量或演变质量。请允许我解释一下其中的区别。
- 执行质量。这些是只能在运行时观察到的方面,如安全性、可用性和效率(性能、速度)。
- 进化质量。这些方面与它如何影响我们随着时间的推移进化代码和结构的能力有关,如代码是否可测试、灵活、可维护和可扩展。
功能性需求与非功能性需求
让我们确保真正理解这两者之间的区别。
功能性需求 | 非功能需求 | |
---|---|---|
描述 | 描述了系统应该做什么 | 限制了功能需求,描述了 "系统应该如何"。 |
强制性 | 是的。 | 不是,但有些比其他更重要 |
范围 | 作为一个用例/特征--组件级 | 作为一个系统级的属性,针对整个系统。 |
定义的难易程度 | 简单明了 | 更加困难(要使定性的属性变成定量的可能很困难--我们有时不得不用指标来代替)。 |
测试类型 | 单元、集成、验收、端到端测试 | 性能、压力、安全、可用性测试(例如) |
例子 | 鉴于用户没有创建账户,当他们注册时,应该创建一个新的用户并向他们发送一封电子邮件。 | (1) 该网站应该能够在6秒内处理99.9%的请求。(2)电子邮件应在触发事件后不晚于20分钟内发送。 |
为什么我们要学习非功能需求
我的第一个创业项目被几百个用户使用。直到它在一个受欢迎的网站上获得了适量的媒体报道,我才知道它并不适合现实世界的生产流量。随着成千上万的人同时注册,这个网站--托管在一个微小的AWS EC2微型实例上,无法满足性能、效率和可靠性的非功能性要求--悲惨地死去,让许多用户感到恼火......再也没有回来。
它是项目失败的主要原因之一
很多时候,即使我们得到了所有的功能,非功能需求也是决定一个项目是成功还是失败的关键因素。我花了一些时间才意识到这一点,但这是非常真实的。
一个缓慢的社交网站有什么用?谁会去玩一个总是崩溃的游戏?如果项目是在没有测试的情况下编写的,而且每当我们增加或改变一个功能时,我们都担心会破坏远处模块的现有功能,那么这个项目真的会成功吗?如果人们甚至不知道如何使用它呢?
它对架构有巨大影响(执行质量)
非功能需求提供了提示,说明我们需要什么样的架构组件(如队列和缓存)和模式(设计模式和架构模式),以便成功地使系统成为某种方式--拥有我们需要的设计标准。
例如,像Instagram或YouTube这样的媒体密集型网站允许用户上传媒体。这就是功能上的要求。但在非功能方面,我们希望在用户上传媒体的时候,能够让他们继续在网站上移动。
这个简单的可用性非功能需求引入了对一些组件的需求,这些组件能够将面向用户的UploadMedia
命令与要完成的工作(如处理媒体、编码、注释、添加字幕等)解耦。因此,我们很可能会从一个基于事件的架构中受益,并增加一个工作/任务队列作为重要的架构组件。
用对象设计来填补非功能上的空白。我只是自动知道我们需要什么样的组件吗?虽然对模式、工具和服务以及它们所解决的问题的熟悉程度有帮助,但是有一种结构化的设计方法可以发现什么样的组件需要被发明或集成到我们的应用架构中。这就是所谓的对象设计(或者正如我喜欢说的如何正确地进行面向对象的编程)。对象设计教我们如何发现和划分必要的需求(包括功能需求和非功能需求)到协作对象的邻居中。在第五部分--来自solidbook.io的带测试的对象设计中,我们学习责任驱动设计和系统设计的基础技能。
使得良好的设计技术成为必要(演化质量)
我们之所以使用这样的东西,很大的原因是。
- 测试(验收、E2E、集成、单元)。
- 设计模式
- 设计原则
- 架构风格
- 架构模式
- 领域驱动的设计
...是因为它们能带来更多可测试、灵活和可维护的代码。进化的品质。这几乎是我们专注于驯服后端复杂性的网络开发人员的目标。因此,遵循上面列出的许多良好的编码实践,可以导致代码可以更容易进化,寿命更长,更容易理解,等等。
处理非功能需求的最佳实践
- 尽早发现非功能需求。由于NFR对架构的影响,尽早发现它们是很重要的。一旦你知道了功能需求,就向客户(或你自己)提出探测性问题,以确定存在哪些非功能需求来约束功能需求。它应该有多快?用户期望它的行为如何?如果用户的账户里有大量的数据,会发生什么?是否有审计要求?什么会使这个项目失败?负担能力对你来说是什么样子的?它的改变会有多容易?我们能指望用户知道该怎么做吗?
- 让需求尽可能地可衡量。这里有一个你无法真正测试或测量的非功能需求的例子:"它应该快得要命"。如果我们把它量化,说 "它应该在3秒内响应95%的请求 "呢?那就更好了,不是吗?
- 使用流行的产品作为质量基线。每隔几年,用户就会期待更好的网站体验。更快,更实时,更多令人惊叹的因素等等。为了得到一个非功能要求的基准,请客户告诉你他们喜欢其他网站的什么。它可能只是感觉一致或有大量的空白空间。这些都是对功能需求的限制。
总结
- 非功能需求描述系统应该是什么,而不是系统应该做什么。它是关于系统级的属性。
- 非功能需求可以分为两个粗略的类别:执行质量和进化质量。
- 我们应该学习非功能需求,因为不能满足它们是项目失败的主要原因之一,它们对架构有巨大的影响,它们为良好的编码实践如TDD和DDD以及更高级的概念如设计模式和架构风格提供了坚实的基础。