探索敏捷团队建设:一键自动化单元测试与工程架构设计

2024-06-02
来源:网络整理

01

前言

今年的敏捷团队建设中,我通过执行器实现了一键自动化单元测试。除了执行器,还有哪些执行器呢?我的探索之旅就从这里开始啦!

架构设计按照实施流程可以分为工程架构、业务架构、部署架构等维度。一个好的系统架构标准应该具备可扩展、可维护、可靠、安全、高性能等特点。虽然这些特点大家都知道,但在实际实施中,更迫切需要知道实现这些需求的关键路径,以便将这些特点融入到架构设计中,才能保证系统能够适应未来的业务增长和交付效率。本文将重点介绍如何进行工程架构设计。

02

价值第一

要理解的话,首先它会根据模板缓存状态判断是否需要从网络获取最新的模板,当获取到模板之后就会进行加载,加载阶段会将产物转换成视图树结构,转换完成后表达式引擎会解析表达式并获取正确的值,事件解析引擎会解析用户自定义事件并完成事件绑定,解析赋值和事件绑定完成后就会进行视图渲染,最终将目标页面展示到屏幕上。

当解决方案存在模糊性时,从产品(业务)价值的角度审视解决方案并进行决策非常重要;

在技​​术上有两个常见的误区:

1、接受所有请求:产品经理提出的所有请求都是合理的,我有责任完成;

2、技术驱动:这种技术实现方式特别巧妙,让产品特性去适应技术实现。

以上两类误区很容易导致研发对产品价值的理解出现偏差,从而很容易对后续的技术迭代造成颠覆性的影响。站在产品(商业)价值的角度,协作各方能够站在平等的角度看待问题,不仅更容易达成共识,也能更好地规划业务演进和技术迭代。

软件也是一个产品,在设计系统的时候也会围绕市场、组织、资源等几个生产要素。

1、市场是产品的对象,是体系构建的基础;

2、组织是指产品交付过程中的资源协调与保障机制;

3.资源是投入产品的生产资料,例如机器、人员、时间、操作等。

软件开发是围绕投资回报率(ROI)进行的生产运营活动,可扩展性、可维护性、可靠性、安全性、高性能都是产品特性,而每一个特性的实现都需要相当大的成本。

1、跑车最显著的特点就是速度快,牺牲了道路适应性、乘坐舒适性、驾驶安全性;

2、越野车的特点是对路况的适应性强,但牺牲了速度和舒适性;

3、轿车在道路适应性、乘坐舒适性、行驶安全性、行驶速度等方面取得了相对的平衡,成为一种常见的交通工具。

俗话说:“上路将军不追兔子”,凡事都有取舍,我们不追求打造完美的复杂系统,但能在有限的条件下追求卓越!

03

架构设计

理解一下,首先它会根据模板缓存状态判断是否需要从网络获取最新的模板,当获取到模板之后就会进行加载,加载阶段会将产物转换成视图树结构,转换完成后表达式引擎会解析表达式并获取正确的值,事件解析引擎会解析用户自定义事件并完成事件绑定,解析赋值和事件绑定完成后就会进行视图渲染,最终将目标页面展示到屏幕上。

架构模式描述了软件系统中各组件之间的关系、职责以及交互方式,从而为软件设计提供了规范和约束,从而提高软件生产效率。主要体现在以下两个方面:

1.帮助开发人员更好地组织和设计软件系统;

2.促进团队之间的协作与沟通,使团队成员更容易了解和分工。

3.1 项目框架

新建系统往往从构建项目的基础工程框架开始,包括目录结构、配置文件、代码模板等工程约束,主要用于规范项目结构、职责边界、代码风格,从而提高代码质量和可维护性。具体包括以下几个方面:

1.约定各模块的依赖关系、交互方式;

2.规范接口交互协议;

3.统一异常编码、捕获和处理;

4.规范日志打印格式;

5.其他公共监管限制。

这里针对最常用的分层架构和DDD架构提出一些实用的思路。

3.1.1 分层架构

分层架构有很多种表现形式,例如MVC,六边形架构等等,它们都是随着业务和技术的发展而逐渐演化的。

在互联网早期,由于计算机硬件性能差、网速慢、存储成本高等限制,互联网产品形态比较单一,只能实现简单的门户、BBS论坛等比较简单的产品。当时的技术架构没有分层的概念,主要使用ASP、JSP、PHP等脚本语言,在这些脚本文件中混杂HTML、CSS、SQL是常有的事。随着互联网技术的发展,以及越来越复杂的业务上线需求,动态脚本语言的劣势逐渐显现出来。以JSP脚本语言为例:

1、复杂性:JSP脚本语言的开发和维护比较复杂,因为它需要处理Java代码和HTML代码的混合;

2、安全性:JSP脚本语言存在SQL注入攻击等安全漏洞,可能导致系统不稳定或者遭受攻击;

3.可扩展性:脚本语言的可扩展性有限,因为Java代码需要直接写在HTML页面中,导致系统结构不清晰。

为了解决上述问题,出现了各种框架,例如,等等。这些框架逐渐取代了JSP脚本语言,也提出了分层架构的概念。最典型的是MVC(,View和)架构模式,其主要目的是将应用程序的不同部分解耦,使其更易于维护和扩展。具体实现方法如下:

1、关注点分离:将应用程序分成三个主要部分,使得每个部分可以独立开发和测试,从而实现更好的关注点分离;

2.提高可维护性:由于三级关注点分离,使得应用程序的不同部分更容易维护和修改;

3.提高可扩​​展性:显示逻辑与业务逻辑控制的分离,使得应用程序的不同部分的扩展更加容易。

在多层架构中,视图层通常采用基于模板的框架(如、、)或者前后端分离的技术栈(如 Vue.js、)。这些技术的演进可以解决更复杂的问题,例如金融保险、电商场景,但也带来了一些新的痛点:

1、学习曲线陡峭:由于MVC架构模式要求开发人员了解和掌握多种概念和技术,因此学习曲线陡峭;

2、增加了复杂性:由于MVC架构模式要求将应用程序划分为多个部分,因此增加了应用程序的复杂性;

3. 增加开发时间:需要更多的测试和集成工作,从而增加开发时间。

为了提高产品交付效率、降低技术门槛,现代研发工作通常分为多个岗位,包括前端开发、后端开发、质量测试、运维保障等,这些岗位需要协同完成产品研发任务。为了保证多业务线、多岗位有序协作,有效控制流程风险,通常会设置项目管理岗位。

MVC 架构将关注点从整个业务实现上分离出来,但在更复杂的大型项目中,尤其是多人协作、多个业务并行的场景下,MVC 架构往往显得力不从心。这时候就需要更细粒度的拆分,实现多条业务线并行,而不会出现大的任务和资源冲突。当然,不同的业务场景会有不同的拆分方式,最常见的拆分方式就是多层架构模型,如下图所示:

图1。

水平分层架构实现了研发的分工协作,所有的经验约束都体现在这里。上图中管控层被细分了两次,也可以根据实际应用场景重新调整,比如可以在POM文件中限定web模块是否可以依赖rpc模块,这样大家就可以按照既有的工程约定去实施开发工作了。

简单描述一下各个模块层的作用:

1、数据访问层:将业务逻辑层与数据存储层解耦,属于模型层范畴,与底层数据源交互(、、),常见框架包括:、等;

2、远程调用层:又称RPC层,与DAO层平行的数据访问层,区别在于通过第三方接口或者平台服务来提供访问能力。与DAO层的区别在于数据归属和领域事务控制权;

3、事务管理层:又称通用业务处理层,它具有以下特点:

4、业务逻辑层:相对具体到业务逻辑服务层,主要负责业务流程的组装和编排,真正的灵活性和可扩展性主要体现在这里;

5、请求处理层:主要进行转发访问控制、输入参数整形、输出参数定制等,其职责直接面向各类终端或者第三方服务商;

6、开放服务层:定义对外提供的RPC服务,其功能和职责与Web层类似,还需要考虑网关安全控制、流量控制等因素。

7.终端展示层:各个终端的模板渲染及展示执行,包括、、IOS移动端等。

传统的软件设计往往导致组件之间紧耦合,使得代码难以维护和扩展。六边形架构模式是分层模式的一种变种,通过将业务逻辑与框架、库等技术细节分离,实现了松耦合的设计,使代码更易于维护和扩展。同时,六边形架构模式还能帮助开发人员更好地实现单元测试和集成测试,从而提高软件质量。这在技术中台性质的各种业务场景中非常有用,如下图所示:

图 2.

3.1.2 DDD 架构

领域驱动设计(DDD)是一种以业务领域为中心的软件开发方法,通过深刻理解业务领域知识,将业务逻辑封装在领域模型中,以实现更好的代码可维护性、可扩展性和可重用性。

图 3.

DDD是一种松散的分层架构,各层的职责和功能如下:

1.用户界面层:Web请求、RPC请求、MQ消息和其他外部输入请求;

2.应用层:负责编排、转发、验证等,这个不同于MVC中存储大量业务逻辑的层;

3.领域层:又称模型层,负责表达业务概念、业务状态和业务规则。包含了领域内所有复杂的业务知识抽象和规则定义,包括实体、值对象、聚合(聚合根)、领域服务、领域事件、仓储、工厂等;

4.基础设施层:为领域模型提供持久化机制和其他通用技术支撑能力,如消息通信、通用工具、配置等。

为什么 DDD 常年这么火,但在实际的系统开发中,完整实现的项目却那么少呢?换言之,MVC 风格的系统很常见,而 DDD 风格的系统却很少见。这得回到 DDD 本身:它是一种解决复杂业务问题的软件开发方法论。

如果普通的CRUD业务系统也按照该模型来实现,会增加系统的复杂度。一般来说,DDD模型适用于以下场景:

1、支持处理复杂的业务逻辑场景:当应用程序需要处理复杂的业务逻辑时,DDD可以将业务逻辑封装在领域模型中,以更好地体现业务需求和业务流程,降低系统架构的复杂性;

2、高可维护、可扩展的场景:DDD将应用程序拆分为多个子域,每个子域都有自己的领域模型,可以更好的管理业务复杂性;

3、需要快速迭代交付的场景:各个子域可以独立开发、部署、扩展,帮助团队快速迭代和交付应用。

评估业务的复杂度需要综合考虑业务流程、产品规则、数据结构、需求变更频率等多个方面。总体来说,采用这种架构模型需要慎重评估,因为实现这种开发模型会面临以下挑战:

1、需要对业务领域有深入的理解:DDD是一种以业务领域为中心的设计方法,因此要想设计出符合业务需求的领域模型,需要对业务领域有深入的理解。

2、需要跨部门协作:实施DDD需要跨部门协作,包括业务人员、开发人员、测试人员等,需要大家共同努力,达成共识;

3、技术难度高:DDD需要理解很多复杂的概念,比如领域事件、聚合根、领域服务等等,要求开发人员具备一定的技术功底。

图 4.

总之,无论是团队协作模式,还是对个人技术能力的要求,亦或是业务共识的达成,各方面都非常具有挑战性。但这并不意味着 DDD 在普通业务系统中没有立足之地,其解决复杂问题的思路依然可以让我们受益匪浅。常用的工具框架,比如 CQRS 框架、事件驱动架构、微服务框架等,都有 DDD 设计思路的影子。

以微服务架构为例,我们首先来看一下以下几个问题:

开发程序需要小数点吗_开发程序需要小程序吗_小程序开发到底需要什么

如果微服务拆分得太细,服务多了会增加运维和管理的难度;如果拆分得太粗,功能耦合度高,灵活性和扩展性不足。所以这是一个比较棘手的问题。

确定业务和应用的边界是解决微服务困境的关键,DDD很好的解决了业务边界的问题,提供了划分业务领域范围的方法论。

微服务就是将应用拆分成多个子域,每个子域以微服务的形式对外暴露自己的能力。微服务将复杂的业务流程和规则限制在某个域的范围内,即内部实现自己的领域模型和数据存储。从应用层来看,这规范和统一了领域服务的实现,大大简化了代码逻辑,更好地管理业务复杂性。

3.2 技术选择

除了基础框架之外,构建工程架构的另一个重要环节就是各类基础中间件的选型,也就是我们常说的技术选型。下面将通过实例讲解技术选型需要注意的重点。

3.2.1 业务需求

了解业务需求,明确系统的功能、性能、安全性、以及未来的扩展要求。

例子:划分系统模块时,有的系统会拆分成【WEB】+【JSF 微服务】两组应用,分开部署,而有的系统只会部署一个【WEB】应用。判断标准是什么?拆分的【JSF 微服务】有什么作用?

能力复用:微服务层具有更通用的模型设计,更强的复用多种业务场景的能力,服务运行过程中可根据业务进行垂直部署;

资源隔离:通过按业务垂直部署,可以更精细化地优化网络、机器等硬件资源。另一方面,将上层WEB应用的资源与底层微服务进行隔离,也可以实现更精细化的资源分配。

总结一下:如果你的服务不需要多终端复用和资源操作,就没必要拆分部署,增加呼叫链路和机器资源投入,相反,服务拆分会带来更大的收益。

3.2.2 技术特点

评估不同技术的特点,包括可用性、性能、安全性、可扩展性、可维护性等。

例子:我曾经遇到过一个系统,底层存储层使用了db4o(一个开源的面向对象数据库),这个中间件有很多优点:

但这里不建议使用,因为它采用的是分布式集群服务,数据库文件只能存放在单机上,也就是存在单点故障问题,这是最致命的。有时候为了弥补类似的缺陷,可能需要花费更多的成本。另一方面,如果作为嵌入式数据库,应用在一些单片机上,它的优势就能够显现出来了。

3.2.3 社区支持

考虑社区对该技术的支持程度,包括是否有活跃的社区、是否有大量的文档和教程、是否有成熟的第三方库等。

例子:它是最早开源的分布式调度框架之一,但是已经很久没人维护了,如果在普通业务中轻度使用,应用层监控好的话应该没什么问题。但是如果作为基础中间件大规模使用,显然在调度过程的可观测性、zk重连机制、调度异常自动恢复等方面亟待升级优化。但现实是社区早就停止维护了,这也是一个比较麻烦的事情。

3.2.4 团队技能

根据团队的技术水平选择合适的技术非常重要,避免使用过于复杂或者不熟悉的技术,否则后续的维护成本和迭代效率提升都会成为大问题。

示例:该语言是 20 世纪 70 年代在金融行业广泛使用的一种编程语言。它可以处理大量数据和复杂计算,可靠性和安全性很高。到 2015 年,它运行着全球 43% 的银行系统和 95% 的 ATM。

然而,2023年3月,日本宣布计划将所有银行系统切换为JAVA。原因是精通这种古老语言的技术人员非常稀缺,生态系统无法跟上机器学习和云集成等新发展。整个系统的维护成本和迭代效率远低于现代JAVA生态系统。

3.2.5 成本效益

评估不同技术的成本效益,包括开发成本、运营维护成本、许可费用等。

1、如果有成熟的开源插件可以使用,应该尽量使用,而不是重新发明轮子;

2.对于其他团队已经完成的任务,需要考虑是否可以重复使用。

例子:目前大部分技术中间件都需要JDK8以上版本的支持,所以在技术选型时需要考虑合适的JDK版本。随着Boot 3的发布,默认支持的JDK版本为17,不再支持JDK8。对于新系统来说,选择新版本似乎更合适。对于已有系统,需要考虑升级到新版本的成本是否与系统带来的收益相匹配,而不是盲目追求新技术。

3.2.6 风险评估

评估不同技术的风险,包括技术成熟度、安全漏洞、依赖性等。

例:它是一个开源的 JSON 解析库,可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化,具有执行效率高,应用范围广等特点。现在在技术选型时需要谨慎,因为它近两年频繁曝出安全漏洞,依赖的应用需要跟着频繁升级版本修复漏洞,这只是表象,更深层次的原因是缺乏安全保障,这是技术选型时必须要考虑的因素。

3.2.7 总结

在选择技术方案时,没必要执着于最新最流行的技术,应综合考虑业务需求、团队技能储备等多方面因素,选择最合适的方案。当然,为了适应不断变化的业务需求和技术发展趋势,也要有及时进行技术评估和更新的意识。

04

规范共识

理解一下,首先它会根据模板缓存状态判断是否需要从网络获取最新的模板,当获取到模板后就会进行模板加载,加载阶段会将产物转化为视图树结构,转换完成后表达式引擎会解析表达式并获取正确的值,事件解析引擎会解析用户自定义事件并完成事件绑定,解析赋值和事件绑定完成后进行视图渲染,最终目标

共识的重要性在于保证团队成员之间的沟通和理解一致,通过建立规范和流程,可以减少重复工作和错误,避免冲突和误解,有利于提高研发效率和质量。

4.1 数据分层

4.1.1 对象转换

在分层架构中,各层之间相互依赖、引用,通过参数对象传递数据。为了保证各层内部结构的稳定性,需要进行防腐设计。这是实现高内聚、低耦合的关键。

例如:模型层的一个表有20个字段,那么对应的PO对象就有20个属性。但是终端展示层只需要展示10个字段,请求处理层(Web)获取数据时,没必要把整个PO对象传回来,这种情况下,可以使用只有这10个属性的DTO对象将结果传递给请求处理层,不会暴露服务端的表结构和一些敏感数据。

数据防腐设计常见的一种做法是在每一层定义自己的数据结构,常见的有:

1.VO(View):视图对象,主要对应界面上显示的数据对象;

2.DTO(Data):数据传输对象,主要用在需要传输大量对象的地方,比如远程调用;

3.DO():领域对象,是从现实世界中抽象出来的有形或者无形的业务实体;

4.PO():持久对象,与持久层(通常是数据库)的数据结构形成对应的映射关系。

在实际开发中,为了方便起见,没必要为每个服务层定义自己的数据对象,可以根据实际情况灵活处理。比如在一些简单的业务场景下,可以跳过DO层对象,直接将PO对象转化为VO对象。

4.1.2 对象重用

在一个经过长期迭代的系统中,很容易遇到部分对象作用域失控的问题,其典型特征是:

1. 一个输入对象被多种方法共享,调整一个属性值定义影响范围广,风险高。

2、直接把Map容器​​作为你服务的输入或者输出参数,没有人知道容器里面到底有多少内容。

3.一个对象定义中会有多个类似的属性定义,当有新的需求时,为了降低风险,只需重新定义一个,然后循环即可。

对象范围失控的问题会导致系统整体稳定性和迭代效率的大幅下降,这种问题通常是一个缓慢积累的过程,在不知不觉中形成,其弊端往往会在系统大调整时集中爆发。

解决此类问题,可以从以下几个方面入手:

1、预防:在架构设计时给出明确的规范定义;

2.发现:定期进行设计和代码审查,发现问题及时纠正;

3、止损:若发现这样的系统,应考虑进行微重构,防止继续腐败;

4、评审:定期及时对体系进行评审,鼓励好的演进,引导不足,培养良好的技术氛围。

4.2 异常管理

4.2.1 捕获异常

异常捕获很容易走向两个极端,一种是每个方法都有try-,一个方法里有多个组,另一种是整个链接都没有try-,就是裸状态。那么异常捕获应该如何进行呢?我们先来看捕获异常的目的:

1.预测并处理异常以允许流程继续进行;

2、快速发现、定位问题,保证系统稳定性。

根据异常处理的目的,相应的处理策略明确:

1. 如果要继续执行流程,必须捕获异常,并在相应节点进行处理;

2.如果是为了快速发现和定位问题,那么可以在调用入口处进行统一的捕获和处理,异常堆栈会有详细的异常原因。

总之,异常是需要捕获的,但是在哪里捕获、如何捕获,可以根据目的灵活处理。

4.2.2 处理异常

1、业务和系统异常应该留下痕迹,方便日后问题定位、统计分析,比如日志、消息等;

2.对各类异常进行规律的编码,可以快速定位问题,方便制定应急预案,规则可以参考HTTP请求与响应的编码;

3、打印异常堆栈信息,这是快速定位问题原因的重要手段;

4、对异常数据进行纵向统计与对比,方便识别系统健康状况。

4.3 日志管理

1、统一的日志框架,建议使用日志门面框架,以及具体实现选择等;

2、配置日志框架,包括日志输出格式、输出位置、输出级别、输出方式(异步打印)等。

3、使用不同的层级记录不同类型的信息,分别打印到不同的文件中;

4、定期检查、清理日志文件,避免占用过多的磁盘空间;

5、根据需要,可以将日志信息发送到其他系统或者进行分析处理,以便更好的对系统进行监控和管理;

6.建立在必要时动态调整日志级别的能力。

4.4 监测和管理

1.系统性能监视:例如,CPU,内存,磁盘,网络和应用程序的运行状态等系统资源的使用;

2.日志监视:监视系统和应用程序的日志信息,介绍业务身份ID,并在时间上检测异常情况。

3.安全监视:例如,监视系统和应用程序的安全状态,并及时检测潜在的安全威胁。

4.业务监视:监视业务系统的各种指标,例如访问量,响应时间,错误率等,并立即发现业务异常。

5.呼叫链接跟踪:它可以在整个分布式系统中跟踪请求的呼叫链接,记录每个服务节点的处理时间和状态,并汇总此信息以形成完整的呼叫链接图,以方便分析和故障排除。

6.监视和预警:各种监控工具是帮助快速找到问题的有效方法,以便尽快找到问题,必须改善有效的预警接触机制,例如电子邮件,公司微信,SMS,电话等。

4.5协作共识

分享