第 22 课:软件架构 — 六边形、微服务与决策记录

所属阶段:第四阶段「语言与框架」(第 17-22 课) 前置条件:第 21 课(API 设计) 本课收获:理解 ECC 支持的架构模式,能写一个 ADR


一、本课概述

前面几课我们学习了语言、框架、数据库和 API 设计。这些都是"怎么做"的问题。架构关注的是更高层的问题 --- "为什么这样做"和"系统的边界在哪里"。

ECC 提供了三个架构相关的 Skill 和一个专用 Agent,帮助你做出有据可查的架构决策。

本课回答三个问题:

  1. 六边形架构是什么? --- Port、Adapter、领域边界
  2. ADR 如何写? --- 记录决策的标准模板
  3. architect Agent 如何辅助决策? --- 深度推理 + 多视角分析

二、架构 Skill 全景

2.1 完整 Skill 清单

Skill 定位 核心内容
hexagonal-architecture 架构模式 Ports & Adapters、领域边界、依赖反转
architecture-decision-records 决策管理 ADR 格式、决策追踪、状态管理
codebase-onboarding 架构理解 架构地图、入口点、依赖图、新人引导

2.2 Skill 关系图

markdown 复制代码
architect Agent(Opus 模型深度推理)
     │
     ├── hexagonal-architecture
     │   (系统怎么分层?边界在哪里?)
     │
     ├── architecture-decision-records
     │   (为什么这样决定?决策记录在哪?)
     │
     └── codebase-onboarding
         (新人如何理解这个系统?)

这三个 Skill 形成了架构工作的完整闭环:设计架构 → 记录决策 → 帮助理解。


三、六边形架构详解

3.1 核心思想

六边形架构(Hexagonal Architecture),又称 Ports & Adapters 模式,由 Alistair Cockburn 提出。核心思想只有一句话:

业务逻辑不依赖基础设施。

markdown 复制代码
传统分层架构的问题:

  Controller → Service → Repository → Database
                                        ↑
                              业务逻辑依赖数据库

六边形架构的解法:

  Controller → Service → [Repository 接口] ← Database 实现
                              ↑
                    业务逻辑只依赖接口,不依赖实现

3.2 Port 和 Adapter

Port(端口) 是接口,定义了边界:

ini 复制代码
Port = 接口定义

入站 Port(Driving Port):
  外部世界如何调用我的业务逻辑
  例:UserService 接口

出站 Port(Driven Port):
  我的业务逻辑如何访问外部世界
  例:UserRepository 接口

Adapter(适配器) 是实现,连接了边界:

ini 复制代码
Adapter = 接口实现

入站 Adapter(Driving Adapter):
  HTTP Controller、GraphQL Resolver、CLI Handler、消息消费者
  → 它们调用入站 Port

出站 Adapter(Driven Adapter):
  PostgreSQL 实现、Redis 实现、S3 实现、邮件服务实现
  → 它们实现出站 Port

3.3 完整架构图

scss 复制代码
           入站 Adapter                          出站 Adapter
    ┌────────────────────┐              ┌────────────────────┐
    │  HTTP Controller   │              │  PostgreSQL Repo   │
    │  GraphQL Resolver  │              │  Redis Cache       │
    │  CLI Handler       │              │  S3 Storage        │
    │  Message Consumer  │              │  Email Service     │
    └────────┬───────────┘              └────────┬───────────┘
             │                                   ▲
             ▼                                   │
    ┌────────────────┐              ┌────────────────────┐
    │  入站 Port     │              │  出站 Port         │
    │  (Service 接口) │              │  (Repository 接口) │
    └────────┬───────┘              └────────▲───────────┘
             │                               │
             ▼                               │
    ┌────────────────────────────────────────┐
    │           Domain Core                  │
    │                                        │
    │   实体(Entity)                        │
    │   值对象(Value Object)               │
    │   领域服务(Domain Service)            │
    │   业务规则(Business Rules)            │
    │                                        │
    │   ← 不依赖任何框架和基础设施 →          │
    └────────────────────────────────────────┘

3.4 代码示例

以"用户注册"为例展示六边形架构的代码组织:

出站 Port(接口定义)

python 复制代码
# domain/ports/user_repository.py
from abc import ABC, abstractmethod

class UserRepository(ABC):
    @abstractmethod
    def find_by_email(self, email: str) -> User | None:
        pass

    @abstractmethod
    def save(self, user: User) -> User:
        pass

Domain Core(业务逻辑)

python 复制代码
# domain/services/registration_service.py
class RegistrationService:
    def __init__(self, user_repo: UserRepository, email_sender: EmailSender):
        # 依赖接口,不依赖实现
        self.user_repo = user_repo
        self.email_sender = email_sender

    def register(self, name: str, email: str, password: str) -> User:
        # 纯业务逻辑
        existing = self.user_repo.find_by_email(email)
        if existing:
            raise EmailAlreadyRegisteredError(email)

        user = User.create(name=name, email=email, password=password)
        saved_user = self.user_repo.save(user)
        self.email_sender.send_welcome(saved_user.email)
        return saved_user

出站 Adapter(具体实现)

python 复制代码
# adapters/postgres_user_repository.py
class PostgresUserRepository(UserRepository):
    def __init__(self, db_session):
        self.db = db_session

    def find_by_email(self, email: str) -> User | None:
        row = self.db.query(UserModel).filter_by(email=email).first()
        return User.from_model(row) if row else None

    def save(self, user: User) -> User:
        model = user.to_model()
        self.db.add(model)
        self.db.commit()
        return User.from_model(model)

入站 Adapter(HTTP Controller)

python 复制代码
# adapters/http/user_controller.py
@router.post("/api/v1/users", status_code=201)
def register_user(request: RegisterRequest):
    user = registration_service.register(
        name=request.name,
        email=request.email,
        password=request.password,
    )
    return ApiResponse.success(UserDTO.from_entity(user))

3.5 六边形架构的好处

好处 说明
可测试性 Domain Core 不依赖数据库,用 Mock 实现 Port 即可测试
可替换性 从 PostgreSQL 换到 MongoDB?只改 Adapter
可理解性 业务逻辑集中在 Domain Core,不散落在 Controller 中
框架无关 从 Django 换到 FastAPI?只改入站 Adapter
并行开发 定义好 Port 后,Domain 和 Adapter 可以并行开发

3.6 何时使用六边形架构

复制代码
适合:
  ✓ 业务逻辑复杂的应用
  ✓ 需要长期维护的系统
  ✓ 可能更换技术栈的项目
  ✓ 需要高测试覆盖率的系统

不适合:
  ✗ 简单的 CRUD 应用(过度设计)
  ✗ 原型验证(速度优先)
  ✗ 短期项目(维护周期短)

四、架构决策记录(ADR)

4.1 为什么需要 ADR

六个月后,没有人记得为什么选择了 PostgreSQL 而不是 MongoDB。

ADR 解决的核心问题是:记录"为什么",而不只是"是什么"

arduino 复制代码
代码告诉你"是什么"(What)
注释告诉你"怎么做"(How)
ADR 告诉你"为什么"(Why)

4.2 ADR 标准模板

architecture-decision-records Skill 定义了标准的 ADR 模板:

markdown 复制代码
# ADR-001: 选择 PostgreSQL 作为主数据库

## 状态

已接受(Accepted)

## 上下文

我们需要为新的订单管理系统选择主数据库。系统预期处理
每日 100 万笔订单,需要 ACID 事务保证,需要支持复杂
查询和全文搜索。

候选方案:
- PostgreSQL
- MySQL 8.0
- MongoDB

## 决策

选择 PostgreSQL 作为主数据库。

理由:
1. JSONB 类型支持灵活的 Schema 演进,减少 Migration 频率
2. 原生全文搜索(tsvector)避免引入 Elasticsearch
3. RLS(行级安全)简化多租户权限控制
4. 丰富的索引类型(B-tree、GIN、GiST)覆盖所有查询模式
5. 团队有 3 年 PostgreSQL 运维经验

## 后果

正面:
- 减少技术栈复杂度(不需要额外的搜索引擎)
- 团队无需学习新技术
- 运维工具链成熟

负面:
- 单机写入性能上限约 5 万 TPS,未来可能需要分片
- 全文搜索能力不如专用搜索引擎
- 需要额外配置连接池(PgBouncer)

## 参考

- PostgreSQL vs MySQL 性能对比:[链接]
- 团队数据库经验调查结果:[链接]

4.3 ADR 状态流转

复制代码
提议(Proposed)
  │
  ├─→ 已接受(Accepted)
  │     │
  │     ├─→ 已废弃(Deprecated)→ 被新 ADR 取代
  │     │
  │     └─→ 已取代(Superseded)→ 被 ADR-XXX 取代
  │
  └─→ 已拒绝(Rejected)→ 记录拒绝原因,避免重复讨论

4.4 ADR 文件组织

perl 复制代码
docs/adr/
├── 001-use-postgresql.md
├── 002-adopt-hexagonal-architecture.md
├── 003-use-jwt-for-authentication.md
├── 004-choose-kubernetes-over-ecs.md
└── README.md                            # ADR 索引

4.5 好的 ADR vs 差的 ADR

维度 好的 ADR 差的 ADR
上下文 说明了约束条件和需求 只说"我们需要一个数据库"
候选方案 列出了 2-3 个备选 只有最终选择
理由 解释了为什么选 A 而不选 B 只说"A 更好"
后果 包含正面和负面 只有正面
可追溯 链接到相关讨论和数据 无参考链接

五、codebase-onboarding Skill

5.1 架构地图

codebase-onboarding Skill 帮助团队创建可读的架构文档:

架构地图模板

markdown 复制代码
# 系统架构地图

## 入口点
- HTTP API: `src/adapters/http/` → 端口 8080
- Worker: `src/adapters/worker/` → 消息队列消费
- CLI: `src/adapters/cli/` → 管理命令

## 核心模块
- 用户管理: `src/domain/user/`
- 订单处理: `src/domain/order/`
- 支付集成: `src/domain/payment/`

## 外部依赖
- PostgreSQL → 主数据库
- Redis → 缓存 + 会话
- S3 → 文件存储
- Stripe → 支付处理

## 依赖图
  User ←── Order ←── Payment
              │
              └──── Inventory

5.2 新人引导清单

codebase-onboarding 推荐为新成员准备以下内容:

  1. 5 分钟概览 --- 系统做什么、服务谁、核心流程
  2. 架构地图 --- 模块关系、入口点、外部依赖
  3. 本地环境 --- 一键启动脚本、环境变量模板
  4. 第一个任务 --- 一个简单但端到端的修改任务
  5. ADR 列表 --- 阅读最近 5 个 ADR 理解历史决策

六、architect Agent

6.1 Agent 特点

architect Agent 是 ECC 中最重量级的 Agent:

维度 说明
模型 Opus(最深度推理能力)
用途 系统设计、架构决策、技术选型
触发 涉及架构决策时自动触发,或手动调用
输出 架构方案 + ADR 草稿 + 风险分析

6.2 architect 的工作方式

architect Agent 采用多视角分析:

arduino 复制代码
输入:架构问题(如"是否应该拆分为微服务?")
     │
     ├── 视角 1:技术可行性
     │   评估技术复杂度、团队能力、工具链成熟度
     │
     ├── 视角 2:业务适配性
     │   评估业务增长预期、变更频率、独立部署需求
     │
     ├── 视角 3:运维成本
     │   评估监控、日志、链路追踪、故障排查复杂度
     │
     └── 视角 4:演进路径
         评估从当前架构迁移的步骤和风险
     │
     ▼
输出:ADR 草稿 + 推荐方案 + 风险清单

6.3 与其他 Agent 的协作

css 复制代码
architect(架构决策)
  │
  ├── planner(将架构方案拆解为实施步骤)
  │
  ├── security-reviewer(审查架构的安全性)
  │
  └── code-reviewer(审查架构实现的代码质量)

七、Skeleton Projects 模式

7.1 patterns.md 中的定义

rules/common/patterns.md 定义了 Skeleton Projects 模式 --- 在实现新功能时,先寻找成熟的骨架项目作为基础:

markdown 复制代码
Skeleton Projects 四步法:

1. 搜索(Search)
   寻找经过验证的骨架项目
   → GitHub、公司内部模板、框架官方 Starter

2. 评估(Evaluate)
   用并行 Agent 从多个维度评估:
   - 安全性评估
   - 扩展性分析
   - 相关度评分
   - 实施规划

3. 克隆(Clone)
   选择最佳匹配作为基础

4. 迭代(Iterate)
   在成熟的结构上迭代开发

7.2 评估维度

维度 评估内容 Agent
安全性 依赖漏洞、认证方案、密钥管理 security-reviewer
扩展性 模块化程度、插件机制、配置灵活性 architect
相关度 与需求的匹配程度、定制成本 planner
代码质量 测试覆盖、文档完整、CI/CD 配置 code-reviewer

7.3 常见骨架项目

技术栈 推荐骨架 特点
Next.js create-next-app 官方模板,App Router
Django django-cookiecutter 生产级配置
Spring Boot Spring Initializr 依赖选择器
Go go-kit/kit 微服务工具集
Kotlin/Ktor ktor-project-generator 插件选择器

八、架构反模式

8.1 常见反模式

反模式 问题 ECC 如何帮助
大泥球(Big Ball of Mud) 无边界、无分层 hexagonal-architecture 定义边界
过度微服务 复杂度爆炸、网络调用多 architect Agent 评估拆分必要性
无文档决策 六个月后无人记得原因 architecture-decision-records
简历驱动开发 选技术看简历而非需求 ADR 强制记录技术选型理由
分布式单体 微服务但强耦合 hexagonal-architecture 强调接口边界

8.2 如何判断需要重构架构

markdown 复制代码
信号(可能需要重构):
  □ 一个小功能需要改 5 个以上的文件
  □ 团队之间频繁出现代码冲突
  □ 部署一个服务需要同时部署其他服务
  □ 测试覆盖率持续下降
  □ 新成员入职需要超过 2 周才能提第一个 PR

行动:
  1. 用 architect Agent 分析当前架构问题
  2. 写 ADR 记录重构决策
  3. 用 planner Agent 制定渐进式重构计划
  4. 不要"大爆炸"重构 --- 逐步演进

九、本课练习

练习 1:查看架构 Skill(10 分钟)

bash 复制代码
ls skills/hexagonal-architecture/
ls skills/architecture-decision-records/
ls skills/codebase-onboarding/

回答问题:

  • hexagonal-architecture 中的 Port 和 Adapter 分别对应什么?
  • architecture-decision-records 中 ADR 的必填字段有哪些?

练习 2:写一个 ADR(25 分钟)

这是本课最重要的练习。

为你当前项目的一个技术决策写一个 ADR。选择以下任一主题(或自定义):

  • 选择某个数据库
  • 选择某个框架
  • 选择单体还是微服务
  • 选择某个认证方案

要求:

  1. 使用第四节中的 ADR 标准模板
  2. 至少列出 2 个候选方案
  3. 理由部分至少有 3 条
  4. 后果部分包含正面和负面

练习 3:画六边形架构图(15 分钟)

为你当前项目(或你熟悉的项目)画一个六边形架构图,标注:

  • Domain Core 中有哪些实体和业务规则
  • 入站 Port 和 Adapter 有哪些
  • 出站 Port 和 Adapter 有哪些

练习 4(选做):思考题

六边形架构和 Clean Architecture(Bob 大叔的洋葱架构)有什么相同点和不同点?它们解决的核心问题是一样的吗?


十、本课小结

你应该记住的 内容
六边形架构 Port 是接口,Adapter 是实现;业务逻辑不依赖基础设施
ADR 记录"为什么"而不只是"是什么";标准模板:状态/上下文/决策/后果
architect Agent Opus 模型深度推理,多视角分析,输出 ADR 草稿
Skeleton Projects 搜索 → 评估 → 克隆 → 迭代,不从零开始
架构反模式 大泥球、过度微服务、无文档决策、简历驱动开发

十一、下节预告

第 23 课:DevOps 工作流 --- CI/CD 与部署模式

下节课我们将从代码架构上升到交付流程。你将学习 ECC 的 deployment-patternsdevops-workflow Skill,掌握 CI/CD 管线配置、蓝绿部署、金丝雀发布等现代交付实践。

预习建议 :提前浏览 skills/deployment-patternsskills/devops-workflow 目录。

相关推荐
王小酱3 小时前
第 4 课:Rules(上)— 通用规则体系
openai·ai编程·aiops
王小酱3 小时前
第 8 课:Skills(上)— 结构与本质
openai·ai编程·aiops
王小酱3 小时前
第 5 课:Rules(下)— 语言特定规则与实战
openai·ai编程·aiops
王小酱3 小时前
第 6 课:Agents(上)— 文件格式与 Frontmatter
openai·ai编程·aiops
王小酱3 小时前
第 3 课:上手体验 — 安装与目录漫游
openai·ai编程·aiops
王小酱3 小时前
第 9 课:Skills(下)— 编程 Skill 地图与编写实战
openai·ai编程·aiops
王小酱3 小时前
第 7 课:Agents(下)— 系统提示词设计
openai·ai编程·aiops
孟健4 小时前
对不起,OpenClaw,我选择 Hermes!
ai编程
王小酱4 小时前
第 1 课:设计哲学 — ECC 为什么存在
openai·ai编程·aiops