0

0

为“架构”再建个模:如何用代码描述软件架构?

看不見的法師

看不見的法師

发布时间:2025-07-15 08:32:30

|

743人浏览过

|

来源于php中文网

原创

在 archguard 平台中,为了实现对架构的治理,我们需要通过代码和模型来描述所需处理的内容和数据。因此,archguard 引入了代码模型、依赖模型、变更模型等,而架构模型和架构治理模型则是两个核心的部分。其它如构建模型等,将会在后续逐步引入到系统中。

PS:本文中的架构展开是基于自动化分析需求的,模型也是基于这个动机出发的。

架构是什么?对单个语言的代码建模并不困难,因为每个语言有其特定的概念,如包、类、字段、函数等。在明确这些概念的基础上,结合业务需求,就能构建出基本的模型。采用领域驱动设计(DDD)等建模方式时,通过达成共识、提炼知识、形成概念,就能构建出模型的雏形。

起点:架构是重要的元素,然而,对于架构,业内没有统一的定义。例如,Martin Fowler 喜欢引用 GoF(设计模式的作者)之一 Ralph Johnson 对于架构的描述:

同样的,Grady Booch(UML 的发明者之一)也以类似的方式来概括架构:

这些描述让我们感觉说了等于没说,我们需要定义什么是重要的东西。而重要的东西,在不同人、不同场景下是存在差异的。哪怕是同一种类型的软件,在不同公司、不同利益相关者的背景下,重要的东西也各不相同。

原则:那么到底哪些是重要的?于是,我尝试引用最新的架构相关书籍,如在编写本文时参考的《软件架构:架构模式、特征及实践指南》,其中 Neal Ford 对架构的定义:

从模型构筑的角度来看,这本书中的定义也提供了一种灵活性。在架构特征的定义中,关注的是各种能力(ability),如互操作性、可适用性、可测试性等。

在 ArchGuard 这个业务场景下,我们难以自动化地识别出各类特征。因为从实践的层面上来说,这些能力并不一定已经实现,它们是目标架构,可能只存在于架构蓝图中。在这个层面上,这里定义的架构更偏向于设计层面的定义。

从另一方面来说,架构决策是我们在架构治理过程中关注的核心。我们可以在后续针对这些原则的规则,构建一个描述架构特征的 DSL。

重要的元素:组件、边界与通信接着,让我们回到 Bob 大叔(Robert C. Martin)的《架构整洁之道》中的定义:

从 Clean Architecture 模式来说,Bob 大叔一直强调的是:顶层抽象策略与底层实现要实现解耦。如如何划定合理的边界?如何组合相关的策略与层次?从这个模式上,我们得到了一个越来越清晰的定义。

然而,我们还面临一个更难的问题:如何定义一个组件是什么?还有关系是什么?在书的序言中,Kevlin Henney(《面向模式的软件架构》卷4、卷5的作者之一)给了一个更精确的描述词:组织结构(structure),从宏观到微观的构筑过程,其中包含了组件、类、函数、模块、层级、服务等。

对于大型软件来说,其组织结构方式异常复杂,类似于一个国家的层级关系,有一级部门、二级部门等。部门之间又有复杂的关系,正是层级关系 + 层级的构件构建成了这个复杂的系统。(PS:为了让系统能良好运行,即其中的组件(螺丝钉)按规则执行,则需要一个督察组织。)

层次结构:组件和关系软件架构已经有几十年的历史,我们已经用“模式”这一词对过去的架构进行了一系列的总结。二十年前,人们初步总结了《面向模式的软件架构》(POSA)。在这里,引述 POSA 1 的第 6 章,有一个完整的层级关系介绍:

在今天来看,从模式上来说,软件架构本身并没有发生太大的变化。只是定义发生了变化,如组件和接口。在微服务架构风格流行的今天,一个微服务也可以视为一个组件,它包含了一系列的接口,对外提供了复用的能力。而用来描述它们的关系的元素,则不再是过去的函数调用,变为了远程调用、事件触发。

现在,我们有了一个详尽的定义,在建模上,可能还欠缺一些元素,如如何分析出组件间的关系。

第 3 种架构视图:展示工程关注点在 ArchGuard 中,我们使用了 C4 架构可视化模型作为一种参考视图。这种实现的方式主要是从分析和可视化的层面来考虑的。除了 C4 之外,另外一种主流的方式是 4 + 1 视图。顺带一提,在 4 + 1 的论文《Architectural Blueprints—The “4+1” View Model of Software Architecture》中,也有一个描述架构的表示公式:Software architecture = {Elements, Forms, Rationale/Constraints}

从通识的角度来看,采用 4 + 1 视图是一个比较理想的方式。只是,由于存在大量的 PaaS、IaaS 等 xx 即服务设计的不合理性,使得这些记录基础设计相关信息的代码,并没有与代码库一起存放,使得在辩识上存在一定的难度。

因此,从实现的层面来说,在这里,我们要引用的是《面向模式的软件架构》中提到的《Software Architecture in Industrial Applications》(也可以参考《实用软件体系结构》一书)架构视图:

概念视图:描述了整个系统需求向整个体系结构的转化。模块视图:描述了如何将系统划分成模块并将模块组织成层。执行视图:描述了系统的动态元素以及它们之间的交互。代码视图:描述了源代码的组织结构。在这个视图的定义里,它更能清晰地划分开几个不同层面的考虑因素。采用作者们在最早的论文里提到的示例:

为“架构”再建个模:如何用代码描述软件架构?

从表格的右边里,我们就可以直接对应到系统所需要的每个层面的设计因素,如编程语言等元素放在代码架构上。换句话说,在微服务、单体架构下,都能找到自己合适的位置。

概念的最后:描述模型的类型系统最后,为了保证本文在概念上的完整性,我们还需要一种方式来描述这个系统中的模型和一系列的概念,从形式上来说,它是一个类型系统。如我们在 UML 中所表示的(PlantUML 表示方式):

class Architecture {
    Component[] components
    System[] subSystems
    Relation[] relations
    ArchStyle archStyle
    Rule[] archRules
    ...
}

一个用来描述类型的系统,就是一个类型系统,和编程语言里的类型是等同的。它可以用来解释一系列的概念,以及概念之间如何连接。

Cliclic AI
Cliclic AI

Cliclic商品背景图编辑器是一款功能强大的AI工具,帮助用户快速生成具有吸引力的商品图背景。

下载

顺带一提,如果我们把编程语言看作是一个系统,那么我们就会发现其在设计上的有趣之处。类型系统与结构体(或者类)可以用于构建系统中的概念,一个个的表达式则是用于构建概念之间的关系。

建模对于概念来说,哪怕是有了如此多丰富的展开,要做一个小结也并非一件容易的事情。更何况于模型而言,它是数值上的标准化,一种接近于通用的模型形态。

设计:第一个版本的架构模型所以,我的第一个尝试是从《面向模式的软件架构》的定义下手:

class SystemArchitecture(val archStyle: ArchitectureStyle, val subSystem: List<subsystem>, var components: List<archcomponent>, val connections: List<archconnection>)

示例:对于一个系统来说,它存在一个主的架构模式,如微服务架构。而在每个微服务相当于是一个子系统或者说组件。当然了,一个子系统可以包含多个微服务。而对于个组件来说,它包含了输入和输出,以及一系列的计算逻辑。所以,它的一个模型可能是这样的:

class ArchComponent(val name: String, val type: ArchComponentType, val inbounds: List<string>, val outbound: List<string>, val components: List<archcomponent>)

而麻烦的一点在于,组件是动态的,组件之间是存在关系的,组件内部也存在关系。所以,我们还需要考虑如何表示组件间的关系?

class Connection(val connectors: String, val source: String, val target: String, var connectionType: ConnectionType, val connectorStyles: ConnectorStyle)

所以,如果以宽泛的定义来看,组件其实是树形结构的。同样的,对于架构来说,这种 Connection 也是存在的。根据上面的一系列形态展开,我们就能得到一个初始版本的架构模型。

更多模型相关内容,详见 ArchGuard Scanner 中的初始版本 Architecture.kt。

实现思路:生成架构模型ArchGuard 中的模型是通过代码来生成的。在这种业务场景下,在构建模型的时候,需要平衡设计与实现。由此,基于代码分析的视图方式更适用我们。从代码和依赖中,我们可以:

基于目录结构分析出分层关系,进而得到代码的结构视图。分析依赖管理工具,进而得到一个模块的视图。分析依赖的软件,如 Spring、Dubbo 等,进而得到一个执行的视图。分析软件中的模型,进而得到概念视图。结合之下,我们就能构建出一个更完整的架构模型。

实现:放弃第一个版本的模型设计挺美好的,但是当我开始写第一行代码的时候,发现不对劲了:我们有了一个分析的模型,但是输入呢?

仅从项目的分析来说,我们拿到的只是一个代码仓库的代码。一个代码仓库可能是一个模块,一个系统,又或者是一个服务。所以,我们的输入是什么?基于已有的分析情况,如项目依赖(依赖管理工具)、源码结构、语言等?我们缺少构建一个项目所需要的上下文。

我们从源码所能分析到的内容如下所示:

data class PotentialExecArch(var protocols: List<string> = listOf(), var appTypes: List<string> = listOf(), var connectorTypes: List<connectortype> = listOf(), var coreStacks: List<string> = listOf(), var concepts: List<codedatastruct> = listOf())

对应的一些分析细节:

协议信息。解析源码和 Gradle、Maven、NPM 中的依赖信息,如含 Dubbo 就视为带 RPC;如带 java.io.File 就认为带 FileIO应用类型。解析依赖信息,如包含 clikt 就视为 Kotlin 的 CLI 应用。连接类型。同上核心技术栈。根据依赖类型分析。概念模型。需要先分析潜在的分层架构模型,根据分层架构模型,就能得到概念集。当然了,这部分代码还没写完,如果有兴趣,也欢迎来加入我们。

多种架构模型于是,在 ArchGuard 的背景下,“架构”的架构模型有多种形态的:

扫描形态下的架构模型(对应到 ArchGuard Scanner)。即,从各个项目的源码中得到的架构模型,从源码、依赖、数据库等中计算出来。分析形态下的架构模型(对应到 ArchGuard Backend)。基于分析形态下的架构模型,构建出包含架构相关知识的架构模型。展示形态下的架构模型(对应到 ArchGuard Frontend)。结合可视化的知识,展示出对应的架构模型。每一个模型都是在上一步的基础上添加了领域知识,那么什么是领域知识呢?如何做好架构?

小结:挑战模型,一个开始,它需要不断地演进才能适用需要。而有了一个凑合能用的模型,只是这一系列工作的开始,我们还会遇到一系列的挑战。

描绘目标架构系统中的架构反应的只是现状,如何去描述未来的架构,并将两者进行匹配,又是一个非常有意思的话题。

衡量变化性我们还将面临的另外一个问题是,软件架构并非是不变的。

软件只要一直在开发,就会以细微地方式变化着。从宏观的层面来说,尽可能架构师都在努力地不去大范围地变动结构。而我们需要面对于这些挑战,诸如于基础设施变化,而这种变化带来的是临时性的中间状态。

如何去表示这种临时性的中间状态,就变得更加有意思。

在这里只开始了迈出了第一步,如果大家有兴趣,欢迎来 ArchGuard 为技术建模。

参考资料《整洁架构之道》《架构之美》《软件架构:架构模式、特征及实践指南》《面向模式的软件架构 卷 1:模式系统》《实用软件体系结构》《Software Architecture in Industrial Applications》《Architectural Blueprints—The “4+1” View Model of Software Architecture》

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Kotlin协程编程与Spring Boot集成实践
Kotlin协程编程与Spring Boot集成实践

本专题围绕 Kotlin 协程机制展开,深入讲解挂起函数、协程作用域、结构化并发与异常处理机制,并结合 Spring Boot 展示协程在后端开发中的实际应用。内容涵盖异步接口设计、数据库调用优化、线程资源管理以及性能调优策略,帮助开发者构建更加简洁高效的 Kotlin 后端服务架构。

126

2026.02.12

spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

161

2025.08.06

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

89

2026.01.26

Java Maven专题
Java Maven专题

本专题聚焦 Java 主流构建工具 Maven 的学习与应用,系统讲解项目结构、依赖管理、插件使用、生命周期与多模块项目配置。通过企业管理系统、Web 应用与微服务项目实战,帮助学员全面掌握 Maven 在 Java 项目构建与团队协作中的核心技能。

0

2025.09.15

dubbo和zookeeper有什么区别
dubbo和zookeeper有什么区别

dubbo和zookeeper的区别:1、功能定位;2、使用场景;3、数据存储与协调;4、集成与关系;5、性能与可靠性;6、扩展性与灵活性;7、社区与生态系统。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

236

2024.02.23

springcloud和dubbo有哪些区别
springcloud和dubbo有哪些区别

springcloud和dubbo的区别:1、定位与关注点;2、生态环境与集成性;3、调用方式与性能;4、组件与功能;5、定制性与灵活性;6、学习曲线与上手难度;7、社区支持与维护。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

134

2024.02.23

dubbo原理和机制是什么
dubbo原理和机制是什么

dubbo原理和机制的解释:1、核心组件;2、通信原理;3、集群容错;4、自动发现与注册;5、负载均衡与路由;6、序列化与传输;7、监控与日志;8、扩展性;9、安全性;10、与spring集成等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

109

2024.02.23

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

490

2025.06.09

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 10.6万人学习

Git 教程
Git 教程

共21课时 | 4.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号