Architecture as Code:以编程方式定义你的系统设计
在软件工程中有一个每隔几年就会重复出现的规律。一个原本手动和可视化的实践被代码化、纳入版本控制和自动化——然后一切都变得更好了。
基础设施经历了这个过程。我们从在云控制台中点击操作转变为编写 Terraform 文件。配置管理经历了这个过程。我们从在服务器上编辑配置文件转变为在 Kubernetes manifest 中声明期望状态。数据库 Schema 也经历了这个过程。我们从手动运行 SQL 脚本转变为编写 migration 文件。
现在轮到了架构文档。Architecture as Code 是以编程方式定义系统设计的实践——使用结构化文本文件,可以进行版本控制、审查、测试,并通过与应用代码相同的流水线进行部署。
本指南涵盖了你需要了解的关于 Architecture as Code 的一切:它是什么、为什么重要、与纯可视化方法的比较,以及如何在实践中实施。
什么是 Architecture as Code?
Architecture as Code (AaC) 是在机器可读、人类可编写的文本文件中定义软件架构的实践。你不是在可视化工具中画方框和箭头,而是以 YAML、JSON 或专用 DSL 等结构化格式描述你的系统、容器、组件及其关系。
以下是一个用 YAML 定义的架构简单示例:
version: "1.0"
project:
name: "Payment Platform"
description: "Handles all payment processing for the organization"
systems:
- name: Payment Platform
type: software_system
description: "Core payment processing system"
containers:
- name: Payment API
type: api
description: "REST API for payment operations"
technologies: [Go, gRPC, OpenAPI]
- name: Payment Processor
type: service
description: "Processes payment transactions"
technologies: [Go]
- name: Transaction Database
type: database
description: "Stores transaction records"
technologies: [PostgreSQL]
- name: Payment Queue
type: queue
description: "Async payment processing queue"
technologies: [Kafka]
- name: Stripe
type: external_system
description: "Third-party payment gateway"
relationships:
- from: Payment API
to: Payment Processor
label: "Forwards payment requests"
type: uses
- from: Payment Processor
to: Transaction Database
label: "Persists transactions"
type: writes_to
- from: Payment Processor
to: Payment Queue
label: "Publishes payment events"
type: publishes_to
- from: Payment Processor
to: Stripe
label: "Charges cards via"
type: uses
这个文件就是架构的完整唯一事实来源。Archyl 等工具读取它,构建 C4 模型,渲染交互式图表,并保持一切同步。文件就存放在你的 Git 仓库中,与它所描述的代码紧密相邻。
为什么纯可视化方法存在不足
在 Architecture as Code 之前,团队通常使用可视化工具来记录架构——Lucidchart、draw.io、Miro 或 Figma。这些工具非常适合头脑风暴和初始设计会议,但作为长期文档存在根本性的局限。
没有版本控制
可视化图表以二进制或专有文件格式存储,无法进行有意义的 diff。当有人修改了图表,你可以看到它变了,但看不到变了什么。draw.io 文件没有等同于 git diff 的功能。你无法像审查代码变更那样在 Pull Request 中审查图表变更。
使用 Architecture as Code,每个变更都是文本 diff。添加一个新服务就是几行 YAML。重命名一个组件就是一行变更。审查者可以准确看到变了什么、为什么变了(从 commit message 中),并批准或请求修改。
没有自动化
可视化图表孤立存在。它们无法触发操作、验证规则或与 CI/CD 流水线集成。如果你的图表显示有 10 个服务,但 Kubernetes 集群运行着 12 个,没有任何机制能检测到这种差异。
Architecture as Code 使自动化成为可能。你可以编写验证规则,检查你的架构定义是否与实际基础设施一致。你可以从架构文件生成文档。你可以在架构文件与现实偏离时触发告警。
无法大规模协作
当两个人同时编辑同一个可视化图表时,冲突通常通过一个人的修改覆盖另一个人来解决。可视化文件没有合并策略。
使用 Architecture as Code,标准的 Git 合并工作流适用。两个团队可以修改架构文件的不同部分,Git 会干净地合并它们。当确实出现冲突时,它们以与代码冲突相同的方式解决——通过讨论和有意识的决策。
没有一致性保证
可视化图表可以包含任何内容。方框可以标注不一致。箭头在同一张图的不同部分可以表示不同含义。没有 Schema、没有验证、没有命名规范的强制。
Architecture as Code 文件有 Schema。工具在每次变更时验证文件。如果你引用了一个不存在的容器,验证会捕获它。如果你使用了无效的关系类型,它会在变更合并之前被标记。
锁定和可移植性
可视化图表通常被锁定在创建它们的工具中。从 Lucidchart 迁移到 draw.io 意味着手动重建每一张图。从一个 Architecture-as-Code 工具迁移到另一个是格式转换——自动化且可重复。
Architecture as Code 的优势
唯一事实来源
当你的架构定义在一个文件(或一组文件)中时,只有一个地方需要查看。不再有哪张图是最新的、哪个 Confluence 页面有最新版本、或者上个月有人邮件发来的 PDF 是否还准确的困惑。
架构变更的代码审查
这可能是最具变革性的优势。当架构变更通过 Pull Request 时,它们获得与代码变更相同的审查力度。资深架构师可以在服务拆分发生之前审查提案。团队可以在引入新依赖之前讨论其影响。
+ - name: Notification Service
+ type: service
+ description: "Handles email, SMS, and push notifications"
+ technologies: [Python, Celery, Redis]
+
+ - from: Order Service
+ to: Notification Service
+ label: "Triggers order notifications"
+ type: uses
这个 diff 讲述了一个清晰的故事:有人正在添加一个 Notification Service 并将其连接到 Order Service。审查者可以提问、建议替代技术或提出不同的服务边界——所有这些都在编写任何一行应用代码之前。
Git 历史就是架构历史
每一次对架构文件的 commit 都创建了架构演进的永久记录。你可以回答这样的问题:
- Search Service 是什么时候添加的?
- 谁批准了从 MySQL 到 PostgreSQL 的迁移?
- 六个月前的架构是什么样的?
- 服务数量随时间是如何增长的?
这段历史对于理解系统的演进和新团队成员的入职都是无价的。
CI/CD 集成
Architecture as Code 自然地集成到持续集成和持续部署流水线中。在每个 Pull Request 上,你可以:
- 根据 Schema 验证架构文件
- 检查合规性规则(例如,每个服务必须有已记录的负责人)
- 生成更新后的图表
- 检测文档化架构与运行系统之间的漂移
- 将架构发布到你的文档平台
这使架构文档成为一个活的产物,而不是一个逐渐衰变的静态文档。
重构和自动化
因为架构定义是结构化数据,你可以编写脚本来操作它们。需要在所有关系中重命名一个服务?在 YAML 文件中简单查找替换。需要生成所有使用 PostgreSQL 的服务报告?解析 YAML 并按技术过滤。需要强制执行命名规范?编写一个 linter。
Architecture as Code 的格式和 DSL
存在多种用于定义 Architecture as Code 的格式和 DSL。以下是最常见方法的概述。
Structurizr DSL
由 Simon Brown(C4 模型的创建者)创建,Structurizr DSL 是最早的 Architecture-as-Code 格式之一。它使用自定义 DSL 语法:
workspace {
model {
user = person "User"
softwareSystem = softwareSystem "My Software System" {
webapp = container "Web Application" "Delivers content" "Java"
database = container "Database" "Stores data" "PostgreSQL"
}
user -> webapp "Uses"
webapp -> database "Reads from and writes to"
}
views {
systemContext softwareSystem {
include *
autolayout lr
}
}
}
Structurizr 开创了 C4 模型的 Architecture as Code 概念。然而,其自定义 DSL 语法有一定的学习曲线,而且需要 Structurizr 专用工具来渲染。
基于 YAML 的方法
YAML 已经成为 DevOps 中声明式配置的事实标准(Kubernetes、Docker Compose、GitHub Actions,Terraform HCL 除外)。使用 YAML 定义架构具有熟悉性的优势——大多数开发者已经知道如何读写 YAML。
Archyl 的 archyl.yaml 格式采用了这种方法:
version: "1.0"
systems:
- name: E-Commerce Platform
type: software_system
containers:
- name: Web Frontend
type: webapp
technologies: [React, TypeScript, Next.js]
- name: API Service
type: api
technologies: [Go, gRPC]
components:
- name: Auth Handler
type: handler
technologies: [JWT, OAuth2]
- name: Product Handler
type: handler
technologies: [REST]
- name: Product Database
type: database
technologies: [PostgreSQL]
relationships:
- from: Web Frontend
to: API Service
label: "Makes API calls to"
- from: API Service
to: Product Database
label: "Reads/writes product data"
嵌套结构直接镜像 C4 层次:系统包含容器,容器包含组件。关系使用人类可读的名称,通过点标记法来消除歧义。该格式可 grep、可 diff,且无需专用工具即可阅读。
JSON 和其他格式
一些工具使用 JSON、TOML 或其他结构化格式。具体格式并不重要,重要的是原则:架构定义应该是基于文本的、可版本控制的、机器可解析的。
实施 Architecture as Code:实用工作流
以下是在你的团队中采用 Architecture as Code 的分步工作流。
步骤 1:从现有状态开始
不要试图在第一天就记录你的整个架构。从 Container 图开始——服务全景。列出每个可部署的服务、其技术栈以及服务之间的关键关系。
如果你使用 Archyl,你可以在 UI 中可视化地创建模型然后导出为 archyl.yaml,也可以从头编写 YAML 文件。两种路径都能达到相同的结果。
步骤 2:提交到代码仓库
将架构文件放在你主要代码仓库的根目录(或者如果你的代码库分布在多个仓库中,则放在专门的架构仓库中)。位置不如原则重要:文件应该存放在 Git 中并经过代码审查。
my-platform/
archyl.yaml # 架构定义
src/
docker-compose.yml
.github/
workflows/
architecture.yml # 架构 CI 流水线
步骤 3:设置 CI/CD 同步
配置你的 CI/CD 流水线,在每次合并到主分支时将架构文件与 Archyl 同步。这确保了 Archyl 中的可视化图表和交互式文档始终反映最新提交的架构。
一个 GitHub Actions 工作流可能如下所示:
name: Sync Architecture
on:
push:
branches: [main]
paths: [archyl.yaml]
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Sync to Archyl
run: |
curl -X POST https://api.archyl.com/v1/sync \
-H "Authorization: Bearer ${{ secrets.ARCHYL_TOKEN }}" \
-H "Content-Type: application/yaml" \
--data-binary @archyl.yaml
步骤 4:通过 Pull Request 进行架构变更
从此以后,架构变更遵循与代码变更相同的工作流:
- 创建分支
- 修改
archyl.yaml文件 - 打开 Pull Request
- 由团队审查
- 合并到主分支
- CI/CD 将变更同步到 Archyl
这赋予了架构变更与代码变更相同的可见性、责任制和可追溯性。
步骤 5:添加合规性规则
随着你的 Architecture-as-Code 实践成熟,添加自动验证架构定义的合规性规则。例如:
- 每个容器必须至少指定一项技术
- 每个外部系统必须有描述
- 不允许孤立容器(每个容器必须至少有一个关系)
- 遵循命名规范(例如,服务以"Service"结尾)
Archyl 的合规性规则引擎可以自动评估这些规则,并在 CI 流水线或 Archyl 仪表板中报告违规情况。
步骤 6:随时间演进定义
从系统和容器开始。当特定服务变得足够复杂需要内部文档时添加组件。在做出重要架构决策时添加 ADR。在确定服务边界时添加 API 契约。
架构文件随你的系统有机增长。不需要预先加载每一个细节。
Architecture as Code vs. Infrastructure as Code
Architecture as Code 和 Infrastructure as Code (IaC) 是互补但不同的实践。
Infrastructure as Code (Terraform, Pulumi, CloudFormation) 定义的是部署什么以及如何配置。它是操作性的:配置服务器、设置网络、管理云资源。
Architecture as Code 定义的是系统的样貌以及各部分如何关联。它是描述性的:记录概念结构、技术选择和服务边界。
理想的设置将两者结合:
- 你的 Terraform 文件定义基础设施
- 你的
archyl.yaml定义架构 - 合规性规则检查两者是否保持一致
当你的 Terraform 添加了一个新服务但架构文件中没有提及时,漂移检测会捕捉到这种差异。
Architecture as Code 与 AI 助手
Architecture as Code 最引人注目的优势之一是 AI 助手能够读取并推理它。当你的架构以结构化文本定义时,Claude Code 和 Cursor 等工具可以:
- 通过查询 YAML 文件回答关于你架构的问题
- 基于当前状态建议架构变更
- 生成符合文档化架构的代码(例如,为正确的服务使用正确的数据库)
- 检测代码与架构定义之间的不一致
Archyl 通过其 MCP Server 更进一步。AI 助手不仅仅是读取架构文件——它们可以查询实时架构模型、遍历关系,甚至提出修改建议。架构变成了一个可编程的、可查询的数据源,而不是一个静态文档。
常见陷阱
过度设计格式
当 YAML 或现有格式就能满足需求时,不要设计自定义 DSL。目标是采用,而当格式是熟悉的时候采用就更容易。大多数开发者已经从 Docker Compose、Kubernetes 和 CI/CD 配置中了解了 YAML。
试图捕捉一切
Architecture as Code 应该捕捉系统的结构性方面:存在什么、事物如何连接、使用了什么技术。不要试图在架构文件中嵌入操作细节(如扩缩策略)、运行时配置(如环境变量)或行为规范(如 API 响应格式)。
不强制执行工作流
Architecture as Code 只有在变更通过既定工作流时才有效。如果人们绕过架构文件直接在可视化工具中进行修改,文件就会过时。建立关于哪个方向是权威的明确约定。
忽视可视化输出
Architecture as Code 不是可视化图表的替代品——它是产生可视化图表的更好方式。文本文件是事实来源,但渲染的图表才是人们日常实际查看的。确保可视化输出是可访问的、及时更新的且易于浏览的。
开始使用 Archyl
Archyl 从一开始就是为支持 Architecture as Code 而设计的。平台提供:
- 基于 YAML 的 DSL,涵盖完整的 C4 模型,包括系统、容器、组件、关系和技术
- 双向同步——在 UI 中可视化建模并导出为 YAML,或编写 YAML 并同步到 UI
- CI/CD 集成,在每次 commit 时自动同步
- 合规性规则,验证架构定义是否符合你的标准
- MCP Server,使架构可被 AI 助手查询
- 协作功能,包括代码审查、评论和团队所有权
无论你是从零开始还是从可视化图表迁移,Archyl 让 Architecture as Code 对任何规模的团队都切实可行。
开始使用 Architecture as Code,为你的架构文档带来与你已经为基础设施和应用代码所带来的同等严谨性。