进阶架构设计必备-特征的识别与治理

1.识别架构特征

        当决定使用软件解决某个特定问题,会收集该系统的需求列表。一个常见的软件解决方案会包.  括以下特征,那么怎么从一堆的需求中提炼出一个软件所需要具备的架构特征呢?

通常一个架构特征要满足三个条件才能识别为特征:

  • 明确非领域设计的某个注意事项;

  • 影响设计的某些结构项:

  • 是否对应用成功至关重要.

  • 明确非领域设计的某个注意事项

        在设计应用时,需求指定了应用应该做什么,架构特征指定了成功的操作和设计标准,涉及如何实现需求以及为何做出某些决策。例如,一个常见的重要架构特征为应用指定了一定的性能水平,需要支撑多少用户同时访问,而这通常不会出现在需求文档中。

  • 影响设计的某些结构项

       考虑架构中是否需要特殊的结构设计才能保证成功,以支付场景为例,我们既可以通过第三方支付平台也可以自建付款能力,那这两种结构设计就有可能对架构起到很大的影响,毕竟支付是跟用户金钱直接相关的,安全性是非常重要的。第三方付款服务: 如果集成点处理付款细节,则该架构不需要特殊的注意事项,只需要遵循服务对接的安全规范即可,不需要特殊的结构; 应用内付款服务: 如果正在设计的应用必须处理付款,则可以为目的设计特定的模块、组件或服务,从结构上隔离关键的安全问题,这样就有可能架构和设计都有影响。

  • 对于应用的成功至关重要的

       筛选出应用必须具有的架构特征尤为重要,支持的架构特征越多,设计与实现的复杂度就越高,所以需要准确地评估出来关键性最少架构特征来去实现。例如,一个2B重业务的内部应用,请求量很小,就不必为高并发等架构特征做一些做出特殊的架构设计与处理。

1.1 从领域问题中提取架构特征

常见的领域问题与对应的架构特征:

领域问题

架构特征

合作

互操作性、可伸缩性、适应性、扩展性

发布时间

敏捷性、可测试性、可部署性

用户体验

性能、可测试性、容错、可部署性、敏捷性、安全性

竞争优势

敏捷性、可测试性、可部署性、可伸缩性、可用性、容错

成本

简单性、可行性

1.2 从需求中提取架构特征

一些架构特征来自于需求文档中的显式声明, 如预期的用户数量和规模通常会出现在领域问题中,有些则需要自己的实际过往经验来做出判断,比如在做一个课程报名系统,肯定会

架构kata方法:

  • 说明: 系统尝试解决的整体领域问题

  • 用户: 系统的预期用户数量或类型

  • 要求: 域级别的需求,是否与用户提供的一致

  • 额外的上下文: 需要考虑许多未显示表达在需求中的,而是隐式问题领域知识

2.度量架构特征

        架构特征存在于整个软件系统中,从低级代码特征(如模块化)到复杂的操作问题 (例如可伸缩性和弹性)等,而且在不同组织/部门也存在很多歧义,所以需要在组织范围内对架构特征的定义达成一致,团队围绕架构创建一种普遍存在的语言,让架构特征具有可度量性。

2.1 运营性度量

       许多架构特性具有明显的直接度量,如性能或可伸缩性,主要分析用户规模与行为习惯,比如当时做的一个校园考勤应用,在早八-九点时就会有大量学生刷卡考勤,会出现请求洪峰,基于这些特殊的场景对应架构特征,做好削峰的一些设计。

2.2 结构性度量

        代码的可测量方法是复杂度,一般可由循环复杂度度量定义。循环复杂度是一种代码级度量标准,旨在为功能、方法、类或用用级别上的代码复杂度提供度量指标。 通过将图论应用于代码(尤其是决策点)来计算的,而决策点会导致不同的执行路径,例如,如果一个函数没有决策语句(例如if语句),则CC=1。如果该函数具有单个条件,则CC=2,因为存在两个可能的执行路径。用于计算单个函数或方法的CC的公式为CC=E - N + 2,其中N表示节点(代码行), E代表边(可能的决策)。如下所示,

public void test(int a, int b) {
	if (a < 100) { //决策点1
  	reutrn 0;
  } else if (a + b > 500) { //决策点2
  	return 1;
  } else {
  	return -1;
  }
}
复制代码

       CC可提供指标可让我们在开发中反思一些问题: 功能是否由于问题域或编码不良而变得复杂?代码的分离是否做的很差?是否可以将大型的方法分解为较小的逻辑块,从而将工作(和复杂性)分配给合理的方法?一般可接受10以下的CC值,如果CC值降到5以下,则认为是结构合理,内聚性较好的代码。

2.3 过程度量

一些架构特征与软件开发过程相交,例如敏捷性,其中可分为可测试性和可部署性。这对架构设计上提出了更高的要求,更好的模块化和隔离性。

  • 可测性:在所有平台上,都可通过代码覆盖率工具评估代码的测试完整性。与所有软件检查一样

  • 部署性:成功部署与失败部署的百分比、部署需要多久时间、部署引发的问题bug以及许多指标。

3.治理架构特征

        一个好的架构设计是不断演化的,其中离不开其中治理,包括了在开发过程中施加影响的任何方面,比如通过域/模块划分调整、技术分层、引进新的技术组件等等一系列动作都可对架构特征进行治理。

        模块化是大多数架构师关心的隐式架构特征,因为维护不当的模块会损害代码库的结构。每个组件都会引用到其他组件,拥有这样的组件网络会破坏模块化,因为开发人员无法重用到单个组件,而又不能一起使用其他组件。当然,如果其他组件耦合到其他组件,则该架构会越来越倾向于大泥球的反模式。

如果是Java语言可以使用JDepend工具类进行循环依赖度的检查或使用IDEA的Maven依赖工具

public class cycleTest {
		private JDepend jdepend;
    
    @BeforeEach
    void init() {
    	jdepend = new JDepend();
      jdepend.addDirectory("/path/xxxx/classes");
    }
    
    @Test
   	public void testAllPackages() {
    	Collection packags = jdepend.analyze();
    }

}
复制代码

ArchUnit(一个Java的测试框架)提供了各种预定义的这里规则,允许编写特定的测试来解决模块化的问题。

layerArchitecture()
	.layer("Controller").definedBy("..controller..")
  .layer("Service").definedBy("..service..")
  .layer("Dao").definedBy("..Dao..")
  
  .whenLayer("Controller").mayNotBeAccessedByAnyLayer()
  .whenLayer("Service").mayOnlyBeAccessedByLayers("Controller")
  .whenLayer("Dao").mayOnlyBeAccessedByLayers("Service")
复制代码

猜你喜欢

转载自juejin.im/post/7019581059482255367