架构师一般从三个方面来发现架构特性:

  • 领域关注(Domain Concerns)
  • 需求
  • 隐性领域知识

在《软件架构基础 4》中我们讨论了隐性领域知识,这里将介绍另外两种。

搬运下 wikipedia 对于领域(Domain)的解释:

A domain is the targeted subject area of a computer program. It is a term used in software engineering. Formally it represents the target subject of a specific programming project, whether narrowly or broadly defined. For example, a particular programming project might have had as a goal the creation of a program for a particular hospital, and that hospital would be the domain.

简而言之,领域就是指程序的目标主题领域,假如为医院开发某个程序,那么医院就是领域。Domain 这个词常常出现在软件工程中,例如领域驱动架构(DDD)、领域模型(Domain model)。

领域关注(Domain Concerns)

架构师必须能够将领域关注的问题转化为确定、正确的架构特性。例如,可扩展性是最重要的关注点,还是容错、安全或性能?也许系统需要所有四个特性的结合。

有一个小窍门,那就是努力让最终的清单尽可能的简短。架构中一个常见的反模式是试图设计一个通用架构,支持所有的架构特性。架构所支持的每一个架构特性都会使整个系统设计变得复杂,支持过多的架构特性会导致架构师和开发人员在还没有开始解决问题之前就变得越来越复杂。

不要纠结于架构特性的数量,而是要保持设计简单的动机。

一开始就考虑系统最终的架构特性列表是愚蠢的,这不仅浪费时间还会产生挫败感和分歧。更好的办法是选出最重要的三个特性(顺序不限)

架构师谈论的是可扩展性、互操作性、容错性、可学习性和可用性,业务利益相关者谈论的是合并和收购、用户满意度、销售时间和竞争优势。两者之间可能互相不理解,下表提供一个领域关注到架构特性的转换。

领域关注 架构特性
兼并和收购 互操作性、可扩展性、适应性、可扩展性。
销售时间 敏捷性、可测试性、可部署性
用户满意度 性能、可用性、容错性、可测试性、可部署性、敏捷性、安全性。
竞争优势 敏捷性、可测试性、可部署性、可扩展性、可用性、容错性。
时间和预算 简单性、可行性。

需要注意的一个重要问题是,敏捷性不等于销售时间。相反,销售时间是敏捷性+可测试性+可部署性。这是很多架构师在翻译领域关注点时陷入的陷阱——只关注其中一个点。

例如,一个业务利益相关者可能会说:“由于监管要求,我们必须按时完成基金的日终计价”。一个无效的架构师可能只会关注性能,因为这似乎是该领域关注的主要焦点。然而,该架构师会因为很多原因而失败:

  • 首先,如果系统在需要的时候无法使用,那么系统的速度有多快都不重要;
  • 第二,随着业务的发展和更多资金,系统必须也能扩展到及时完成日终处理;
  • 第三,系统不仅要可用,而且要可靠,以便在计算日终基金价格时不会崩溃;
  • 第四,如果日终基金定价完成了 85%,系统崩溃了怎么办?它必须能够恢复并继续计算。
  • 最后,系统可能很快,但基金价格是否计算正确?

所以,除了性能之外,架构师还必须同样关注可用性、可扩展性、可靠性、可恢复性和可审计性。

从需求提取架构特

一些架构特征来自需求文档中的明确声明。例如,明确的预期用户数和规模。另一些则来自架构师的领域知识,这是领域知识对架构师总是有益的众多原因之一。

例如,假设一个架构师设计了一个为大学生处理班级注册的应用程序,为了便于计算,假设学校有 1000 名学生,注册时间为 10 小时。架构师在设计系统时,是否应该假设注册过程中的学生会随着时间推移均匀分布?或者,基于对大学生习惯和癖好的了解,架构师是否应该设计一个能够处理所有 1000 名学生在最后 10 分钟注册的系统?任何一个了解学生有多么拖延的人都知道这个问题的答案! 像这样的细节很少会出现在需求文档中,但它们确实为设计决策提供了信息。

案例学习:三明治店网上订餐系统

描述

一家全国性的三明治店想实现网上订餐(除了目前的呼叫服务外)。

用户

数千人,也许有一天会到数百万人。

需求

  • 用户下单,然后会得到一个领取三明治的时间和到店的方向(必须与几个外部地图服务整合,包括交通信息);
  • 如果店家提供送餐服务,就派司机带着三明治给用户送去;
  • 移动设备的可访问性;
  • 提供全国性的每日促销/特价活动;
  • 提供本地每日促销/特价活动;
  • 接受在线、当面或货到付款;

其它需求

  • 三明治店都是加盟店,每个店都有不同的老板;
  • 母公司近期有海外扩张计划;
  • 企业的目标是雇佣廉价的劳动力,以实现利润最大化";

鉴于以上这种情况,架构师将如何推导出架构特征?

需求的每一部分都可能有助于架构的一个或多个方面,架构师在这里并不设计整个系统,相反,架构师要寻找影响或冲击设计的东西,特别是结构性的。

首先,将候选架构特性分为显性和隐性特性。

显性架构特性

明确的架构特性作为必要的一部分出现在需求规范中,例如,一个购物网站可能支持的并发用户数量,需求中明确了这一点。架构师应该考虑需求的每个部分,看看它是否有助于架构特性。但首先,架构师应该考虑领域级的关于预期指标的估计。

首先应该引起架构师注意的细节之一是用户数量:目前是数千人,也许有一天会到数百万人(这是一家雄心勃勃的三明治商店!)。因此,可扩展性–处理大量并发用户而不严重降低性能的能力–是架构的首要特性之一。请注意,需求陈述并没有明确要求可扩展性,而是将该要求表述为预期的用户数。架构师必须经常将业务语言解码成工程等价物。

然而,我们可能还需要弹性–处理突发请求的能力。这两个特性经常出现在一起,但它们有不同的限制。

可扩展性看起来像下图所示的图形:

弹性则是流量的爆发,如下图所示:

有些系统是可扩展的,但不是弹性的。例如,考虑一个酒店预订系统,如果没有特殊的销售或活动,并发用户数量可能是一致的。相反,考虑一个音乐会门票预订系统,随着新票的发售,狂热的粉丝会涌入网站,这就需要高度的弹性。通常情况下,弹性系统需要可扩展性:处理突发事件和大量并发用户的能力。

弹性的要求并没有出现在需求中,然而架构师应该将其确定为一个重要的考虑因素。一个三明治店的流量是全天一致的吗?还是在用餐时间前后会有爆棚的客流?几乎可以肯定是后者。因此,一个好的架构师应该识别这种潜在的架构特征。

架构师应该依次考虑这些业务需求中的每一个,看看是否存在架构特征。

  1. 用户下单,然后得到一个领取三明治的时间和去商店的方向(必须提供与外部地图服务整合的选项,包括交通信息)。外部地图服务意味着集成,这可能会影响可靠性等方面。例如,如果开发人员构建了一个依赖于第三方系统的系统,然而调用它却失败了,这就会影响调用系统的可靠性。但是,架构师也要警惕架构特性的过度规范,如果外部流量服务出现故障怎么办?三明治网站是否应该失败,或者只是在没有流量信息的情况下提供稍低的效率?
  2. *如果店家提供送餐服务,就派司机带着三明治给用户送去。*看起来不需要特殊的架构特性来支持这个需求。
  3. *移动设备的可访问性。*这一要求将主要影响到应用程序的设计,要做一个 portable web application 或是几个 native web applications。考虑到预算限制和应用程序的简单性,一个移动端优化的 web 应用更好。因此,架构师还要考虑为页面加载时间和移动端的性能架构特性。注意,架构师在这样的情况下不应该单独行动,而是应该与用户体验设计师、业务利益相关者和其他相关方合作,审核这样的决策。
  4. 提供全国性的每日促销/特价。
  5. *提供本地每日促销/特价活动。*这两个要求都规定了促销和特价商品的可定制性。注意,需求 1 还意味着基于地址的可定制信息,基于这三个需求,架构师可以考虑将可定制性作为一种架构特性。例如,微内核架构这样的架构风格,通过定义一个插件架构,可以极好地支持自定义行为。传统的设计也可以通过设计模式(如模板)来满足这种需求。需要架构师权衡取舍。
  6. *接受在线、当面或货到付款。网上支付意味着安全性,但这一要求没有任何内容表明安全程度特别高。 7. 三明治店都是加盟店,每个店都有不同的老板。*这个要求可能会对架构造成成本限制–架构师应该检查可行性(应用成本、时间和员工技能培训等约束条件),看看是否需要一个简单性或牺牲性的架构。
  7. *母公司近期有向海外扩张的计划。*这个要求意味着国际化,也就是 i18n。许多技术可以处理这一要求,应该不需要特殊的结构来适应。
  8. *企业的目标是雇佣廉价的劳动力以实现利润最大化。*这个要求表明可用性将是重要的,但同样是更关注设计而不是架构特点。

还有一个架构特征是性能:没有人愿意从一个性能差的三明治店购买,尤其是在高峰期。然而,性能是一个有着不同差别的概念–架构师应该为什么样的性能而设计?我们将在后续章节中介绍性能的各种细微差别。

我们还希望将性能数字与可扩展性数字结合起来定义。换句话说,我们必须在没有特定规模的情况下建立一个性能基线,并确定在一定数量的用户下,可接受的性能水平是多少。

隐形架构特性

许多没有在需求文档中指定的架构特性却非常重要。

系统可能支持的一个隐含的架构特性是可用性:确保用户可以访问三明治网站。与可用性密切相关的是可靠性:确保网站在交互过程中保持运行–没有人想从一个不断掉线的网站上购买

安全性在每个系统中都是一个隐含的特性:没有人愿意使用不安全的软件。然而,它可能会根据关键性来确定优先级

对于该三明治店的支付应该由第三方处理,因此,只要开发者遵循一般的安全(不将信用卡号码以纯文本的形式传递,不存储太多信息等),架构师应该不需要任何特殊的结构设计来适应安全问题,在应用中做好设计就足够了。

三明治店需要支持的最后一个主要架构特性:可定制性。需求的几个部分提供了自定义行为:食谱、本地销售等。通常这应该属于应用程序的设计,这个设计元素对应用的成功并不关键。

在选择架构特性的过程中,没有正确的答案,只有不正确的答案:

架构没有错误的答案,只有昂贵的答案。

架构师可以设计一个在结构上不适应可定制性的架构,要求应用本身来支持这种行为。架构师不应该过于强调发现完全正确的架构特性集–开发人员可以用各种方式来实现功能。当然,正确识别重要的结构元素可能会促进更简单或更优雅的设计。

架构师还必须优先朝着找到最简单的集合的方向发展。团队在确定架构特性方面一个有用的尝试是找到最不重要的一个特性,如果你必须消除一个,那会是哪个?一般来说,架构师更有可能剔除显性的架构特征,因为许多隐性的特征是一个应用想成功最基本的特性。

在三明治店的案例中,哪个架构特性是最不重要的?(不存在绝对正确的答案)

在这种情况下,解决方案可能会失去可定制性性能。我们可以取消可定制性作为架构特性,并计划将该行为作为应用设计的一部分来实现。性能可能是成功的最不关键因素,当然,开发人员并不是要构建一个性能糟糕的应用,而是要构建一个不将性能优先于其他特性(如可扩展性或可用性)的应用。