架构模式选型对比

一个 CTO 的纠结

2023年,我们 CTO 在选架构时纠结了整整两个月:

分层架构? → 简单,但太传统
六边形架构? → 清晰,但学习成本高
CQRS? → 听起来很厉害,但真的需要吗?
整洁架构? → Uncle Bob 的书看完了,但不知道怎么落地

最后他选择了"全部都要"——结果系统变得四不像,没人能维护。

架构选型的核心问题不是"哪个最好",而是"哪个最适合当前的问题"。


一、架构模式全景图🔴

1.1 按复杂度排序

简单 → 复杂:

1. 分层架构(Layered)
   最传统、最常见,适合大多数业务系统

2. 事件驱动架构(EDA)
   异步、松耦合,适合高并发系统

3. 微内核架构(Microkernel)
   核心 + 插件,适合平台型产品

4. 六边形架构(Hexagonal)
   端口与适配器,适合核心业务需要稳定的系统

5. 洋葱架构(Onion)
   六边形的变体,更强调依赖方向

6. 整洁架构(Clean Architecture)
   层次最清晰,适合大型复杂系统

7. CQRS + Event Sourcing
   最复杂,适合审计和高并发读场景

二、分层架构 vs 六边形架构🔴

2.1 核心区别

维度分层架构六边形架构
核心理念按技术分层按业务分层
依赖方向上层依赖下层核心不依赖外部
测试性需要 mock核心可独立测试
复杂度
适用场景中小型系统业务复杂的核心域

2.2 代码对比

// 分层架构:Controller → Service → Repository
@Controller
class OrderController {
    @Autowired private OrderService service;

    @PostMapping
    public Order create(OrderDTO dto) {
        return service.create(dto);
    }
}

@Service
class OrderService {
    @Autowired private OrderRepository repository;

    @Transactional
    public Order create(OrderDTO dto) {
        return repository.save(dto);
    }
}

@Repository
interface OrderRepository extends JpaRepository<Order, Long> {}

// 六边形架构:Port → Application → Adapter
// 端口(输入)
interface CreateOrderPort {
    Order createOrder(CreateOrderCommand command);
}

// 应用服务
class CreateOrderService implements CreateOrderPort {
    private final OrderRepository repository;

    public Order createOrder(CreateOrderCommand command) {
        return repository.save(command);
    }
}

// 适配器(驱动)
@RestController
class OrderController implements CreateOrderPort {
    private final CreateOrderService service;

    @PostMapping
    public Order create(OrderDTO dto) {
        return service.createOrder(toCommand(dto));
    }
}

// 适配器(被驱动)
interface OrderRepository {
    void save(Order order);
}

三、CQRS vs 传统 CRUD🔴

3.1 适用场景对比

维度传统 CRUDCQRS
读/写比例接近 1:1读 >> 写 或 写 >> 读
数据模型统一模型读模型 vs 写模型
复杂度
一致性强一致最终一致(读模型)
适用场景简单 CRUD复杂业务、高并发读

3.2 CQRS 的代价

// 写入侧:DDD 聚合
@Aggregate
class Order {
    public void pay(Money amount) {
        this.status = OrderStatus.PAID;
    }
}

// 读取侧:专门的读模型
record OrderDetailDTO(
    Long orderId,
    String userName,           // JOIN 用户表
    String productNames,       // JOIN 商品表
    String status,             // 状态翻译
    String formattedAmount,    // 格式化
    LocalDateTime createdAt    // 格式化
) {}

// 同步机制:事件驱动
@EventListener
class OrderProjectionUpdater {
    public void update(OrderPaidEvent event) {
        // 更新读模型
    }
}

CQRS 的问题

  1. 读写模型可能不一致
  2. 实现复杂度高
  3. 需要额外的数据同步机制
  4. 开发和维护成本翻倍
⚠️

CQRS 不是银弹。只有当你确实有"复杂查询"或"高并发读"的需求时,才考虑使用。简单业务用 CQRS 是过度设计。


四、六边形 vs 洋葱 vs 整洁架构🟡

4.1 共同点

三个架构的核心思想是一样的:让核心业务逻辑独立于外部依赖

共同特点:
1. 核心业务在最内层
2. 外部依赖只能依赖内层,不能反方向
3. 通过"端口"或"接口"与外部通信

4.2 区别

维度六边形洋葱整洁
层数2层(核心+适配器)多层4层
依赖注入构造函数注入DI容器DI容器
领域模型普通对象有聚合根实体+值对象
复杂度
学习曲线最陡

4.3 整洁架构层次

由内到外:

第4层: Entities(实体)
  - 核心业务规则
  - 不依赖任何东西

第3层: Use Cases(用例)
  - 应用业务规则
  - 只依赖 Entities

第2层: Interface Adapters(接口适配器)
  - Controllers, Gateways, Presenters
  - 把数据转换为用例可用的格式

第1层: Frameworks & Drivers(框架和驱动)
  - Web, DB, External Services
  - 最外层,不属于业务逻辑

五、微内核架构🟡

5.1 适用场景

场景是否适合微内核
IDE(VS Code、IntelliJ)✅ 插件系统天然适合
浏览器✅ 扩展程序
操作系统✅ 内核 + 驱动/服务
电商平台(不同商家不同规则)✅ 业务插件
银行核心系统❌ 核心规则必须稳定
简单 CRUD 系统❌ 过度设计

5.2 结构

// 核心系统
class OrderCore {
    private final Map<String, Plugin> plugins = new HashMap<>();

    public void registerPlugin(String name, Plugin plugin) {
        plugins.put(name, plugin);
    }

    public void process(Order order) {
        for (Plugin plugin : plugins.values()) {
            if (plugin.supports(order)) {
                plugin.execute(order);
            }
        }
    }
}

// 插件接口
interface Plugin {
    boolean supports(Order order);
    void execute(Order order);
}

// 插件实现
class DiscountPlugin implements Plugin {
    @Override
    public boolean supports(Order order) {
        return order.getType().equals("DISCOUNT");
    }

    @Override
    public void execute(Order order) {
        // 折扣计算
    }
}

六、架构选型决策框架🔴

6.1 决策树

系统复杂度:
├── 简单 CRUD?
│   └── 分层架构足够

├── 中等复杂度,有核心业务域?
│   │
│   ├── 核心域需要长期稳定?
│   │   └── 六边形架构
│   │
│   ├── 读多写少,或写多读少?
│   │   └── 考虑 CQRS
│   │
│   └── 需要灵活扩展?
│       └── 微内核架构

└── 复杂系统,团队大?
    ├── 关注点是业务还是技术?
    │   ├── 业务 → 整洁架构
    │   └── 技术 → 六边形/洋葱

    └── 需要审计追溯?
        └── Event Sourcing

6.2 团队因素

团队成熟度推荐的架构
初创团队,小而快分层架构
有经验,快速迭代分层 + 简单 DDD
大型团队,复杂业务六边形 + CQRS
平台型产品微内核

6.3 成本评估

架构开发成本维护成本扩展成本学习成本
分层1x1x
六边形1.3x0.9x
整洁2x0.7x
CQRS2.5x1.5x

【架构权衡】 没有"最好"的架构,只有"最合适"的架构。选择架构时要考虑:业务复杂度、团队能力、时间约束、维护成本。最差的架构是"过度设计",其次是"设计不足"。


七、实战案例

7.1 案例一:电商订单系统

初始状态:传统三层架构,Service 5000 行

分析

  • 业务复杂(多种订单类型、促销规则、退款流程)
  • 团队 10 人
  • 需要长期维护

选型:六边形 + 简单 CQRS

结果

  • 核心业务逻辑与外部依赖解耦
  • 新增订单类型只需要加新的适配器
  • 读模型独立优化,查询性能提升 5 倍

7.2 案例二:内部工具平台

初始状态:没有架构,增删改查

分析

  • 业务简单
  • 团队 3 人
  • 需要快速上线

选型:简单分层架构 + DDD 部分实践

结果

  • 快速开发
  • 没有过度设计
  • 后续扩展预留了接口

八、面试总结

8.1 核心追问

  1. "你用过哪些架构模式?" —— 结合项目经验
  2. "分层和六边形的区别?" —— 核心是否独立
  3. "什么情况下用 CQRS?" —— 读写分离需求
  4. "整洁架构的层次是什么?" —— 4 层结构

8.2 级别差异

级别期望回答
P5能区分各种架构模式
P6能根据场景选择合适的架构
P7能设计复杂系统的整体架构