架构整洁之道

什么是软件架构

本质

软件架构本质是划分组件及组件间的交互方式,以及组件间通信方式

目的

是为了更好的支持系统的开发,维护,部署,运行。它是系统生命周期总开发成本负责的。即设计一个架构,使其易于并行开发,易于修改且可应对未来变化,易于灵活部署,同时满足系统的用例。
其终极目标是最大化程序员生产力,最小化总运营成本。

评:Bob大叔不愧是实干派,对软件架构的目标定义实在而具体,给了架构设计好坏的衡量标准。也给架构设计指明了方向。

开发

通常为最大化程序员生产力,组织架构最终会趋向于系统架构。这样每个组织职责明确,可并行开发。

但并于小团队来说,架构设计对于开发的影响就不大了,甚至为阻碍开发生产力。

运行

系统架构最基本要求是要满足系统需求。即用例。就是设计出来的架构必须可以很清楚的满足系统用例的运行。即利用系统架构元素及其交互去阐述主要系统用例的运行过程。这应该是清晰而明确的。这样的系统架构易于理解,修改与维护。减少了总运营成本

另外系统架构也必须支持非功能性需求。比如性能指标。通常来说非功能性需求对系统运行影响较大,需要提前考虑架构是否足够灵活去满足这类需求。

部署

系统必须是一键可部署的。这显化了部署成本。同时也使得系统更易于验证。

若部署成本高,极大可能带来更低的质量。因为部署成本高,验证困难,就更加难发现问题了。

维护

维护的主要成本花在探秘和风险上
探秘:为新增修改所必须了解的系统功能及确定修改的最佳位置
风险:评估修改所涉及的每个影响点,以及可能带来的新问题

通过好的架构设计将系统拆分为组件,可将影响限定在最小范围。减少探秘和风险成本。

保持可选项

将无关紧要的细节尽量推迟到最后做决定。因为需求总是越来越明确的,越是早期做出细节上的决定,越容易变更。

这里的细节主要是指软件实现技术细节,诸如数据库,web等。

所有的软件行为可分为高层策略与实现细节。
高层策略指系统的业务规则,它是系统的真正价值所在

设备无关性

诸如虚拟地址,IO等

独立性

按层解耦(水平)

通常系统切分为不同的层次,每层处理各自的功能。切分依据通常是不同层次变更原因,变更方向和速率不一致。不保持各层独立开发,功能变更互不影响,因此做了分层开发。

常见的分层模式为
接口层,用例层,领域层,持久化层。
其中领域层是业务领域普适的系统概念组合。
用例层通过组合不同的领域对象支持不同的用例。即系统行为
接口层通常是系统门面,用于接口适配。

按用例解耦(垂直)

通常引起系统变化的主要原因就是用例本身。因此可以通过将不同的系统用例隔离,如此就可以新增用例而不影响现有功能,做到了用例级的隔离

当然,每个用例可能会跨越多个水平层次,这样每个用例在每层都会切割。

这就是面向服务的软件设计思路。这种方式做到了较大程度的隔离,但也会带来诸如部署,维护方面的问题。

重复

这里强调下假重复与真重复。
首先明确,并不是代码完全一样就是真重复了。

真重复往往代表着知识的重复,即某个具体业务规则出现在多个地方,业务规则变更必将带来散弹式修改。这是真重复。

假重复是指完全相同的两段代码,虽然现在重复,但是其未来变化原因和速率都不一样。这就是假重复,强而去重反而会带来耦合。

再谈解耦

通常耦合有以下三种情况:源码层次(函数调用依赖),部署层次(部署依赖),服务层次(通信的数据结构依赖)
好的架构通常是从单体架构演变出来的。即依赖层次也应该是一种保留的可选项。通常做法是一开始做到源码层次,但保留演进到部署层次和服务层次的可选项,使其较小成本便可演进过去即可。

划分边界

划分边界是为了约定系统交互接口及交互约束。从而将不那么重要的细节限定到边界内处理。为系统保留尽可能多的可选项。

划分边界应该在不相关的组件之间。在边界线两边的组件通常有着不同的变更原因和速率。

作者提出了插件式架构。
即以业务逻辑为核心,其它细节细节诸如数据库web等都为插件。它们均依赖于业务逻辑。

Main组件

Main组件们于系统最外层,知道最多的细节。
只有操作系统依赖于main组件

main组件负责系统初始化,对象创建,相关资源申请,协调各组件的依赖关系。

main组件作为系统的插件,可以专门针对测试环境,生产环境,开发环境创建不同的main组件

服务:宏观与微观

这里的服务指:面向服务的架构与微服务

主要观点:

  1. 微服务或者面向服务的架构并不能够称之为架构。作者认为,架构设计的主要任务是要找到高层策略与底层细节之间的架构边界,并确保这些边界遵守依赖关系规则。服务本质上是比函数调用成本稍高的,分割应用的一种方式。并非所有服务边界都具有架构上的含义。

对解耦合的挑战

微服务通过部署到不同的进程甚至于服务器中,做到了一定程度的解耦,但它们实际上也通过相互交互的数据形成了间接耦合。明显的例子是如果交互数据发生了变化,那么相关服务都要改变。

对独立开发部署的挑战

微服务通过将大型系统分解为各个服务,各服务由不同团队独立开发,部署交互。这有一定道理。
但实际上不同服务间还是存在着诸如交互数据耦合、行为耦合(这非常见,一个需求通常需要多个服务共同配合完成,这就是行为耦合,可以参见作者提的cross-cutting concern问题)

大型系统一样可以采用单体架构,组件化架构。服务化并非唯一选择。

微服务的优势在于可灵活支持弹性扩展,缺点在于交互成本高,服务拆分带来的额外维护成本高。

测试边界

测试作为组件

主要观点:

  1. 测试作为独立的组件(通常仅部署在测试环境中),它通常位于最外层,依赖于生产代码。
  2. 测试组件存在是为了支持开发过程而非运行过程

可测试性设计

强调了在设计过程中一起考虑可测试性需求。
测试代码与生产代码松耦合
测试应该独立于GUI也能够验证业务逻辑

软件设计第一原则:
不要依赖于不稳定的东西

测试专用API

测试专用API是介于测试套件和被测代码之间,减少测试代码与被测代码的结构性耦合,提高测试用例的稳定性,同时也简化了测试代码编写成本。

测试代码与被代码结构性耦合:
指的是对被测代码的每个类,每个方法都有对应的测试代码。这种测试之所以脆弱在于任何方法或类的改变均可能导致一批测试的失败。

嵌入式系统架构整洁之道

作者提了几个关键概念。

构件

作者认为构件的定义应该是与代码的依赖关系有关的。即构件相对于软件来说,它对特定硬件有强依赖,是硬件能力的补充。任何依赖于特定硬件的代码都应该看作是这个硬件平台的构件

当前从代码扩展性,演进性,可变性性来说,我们应该少写构件,多写软件

为此,构建嵌入式系统需要在构件和软件之间增加一个HAL(即硬件抽象层),HAL的接口应该是由软件的需求定义。

另外为了做到嵌入式代码的独立可测性(即不依赖于特定硬件),作者还提出了OSAL(操作系统抽象性)。以屏蔽软件依赖于特定操作系统。

文章知识点与官方知识档案匹配,可进一步学习相关知识MySQL入门技能树数据库组成31787 人正在系统学习中

来源:OS_Net_DCE

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年1月15日
下一篇 2021年1月15日

相关推荐