在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、前置思考

1.1 为什么架构会腐烂?

架构腐烂的五个信号:
  → 改一行代码要动五个文件 (耦合)
  → 没人说得清模块边界 (职责混乱)
  → 新功能越来越慢 (熵增)
  → 测试写不进去 (依赖地狱)
  → 新人上手要三个月 (认知负担)

腐烂的根源: 需求在变,架构没跟上
  → 架构不是画一次就完事,而是持续演进的过程

1.2 架构复盘的本质

复盘不是"重写"而是"重构":
  → 保持对外行为不变,逐步调整内部结构
  → 每一小步都可编译、可测试、可上线
  → 大爆炸式重写 = 高风险 + 业务停滞

演进路径: 单体混乱 → 分层 → 模块化 → Clean Architecture

二、核心原理

2.1 三层分层架构

┌──────────────────────────────┐
│ Presentation 表现层            │  ← UI/页面/组件
│   @Component / @Builder        │
├──────────────────────────────┤
│ Domain 领域层                  │  ← 业务规则/用例
│   Entity / UseCase / 领域服务  │
├──────────────────────────────┤
│ Data 数据层                    │  ← 数据来源
│   Repository / 本地/远程实现    │
└──────────────────────────────┘

依赖方向: 外层依赖内层,内层不依赖外层
  → 表现层依赖领域层
  → 领域层依赖数据层的"接口"而非实现

2.2 Clean Architecture 五层

┌─────────────────────────────┐
│ Entities     企业业务实体      │
├─────────────────────────────┤
│ Use Cases   应用用例           │
├─────────────────────────────┤
│ Interface Adapters 接口适配器  │  ← 控制器/网关
├─────────────────────────────┤
│ Frameworks  框架/驱动          │  ← ArkUI/数据库/网络
└─────────────────────────────┘

依赖规则: 只向内依赖,外层变化不影响内层
  → 换数据库/换 UI 框架,业务核心代码不动

2.3 DDD 领域驱动设计核心

战术设计要素:
  Entity: 有唯一标识、有生命周期的对象 (订单)
  Value Object: 无标识、不可变的值 (金额)
  Aggregate: 聚合根 + 一致性边界 (订单+订单项)
  Repository: 聚合的存储接口
  Domain Service: 跨聚合的业务逻辑

战略设计要素:
  Bounded Context: 领域边界 (订单域/库存域)
  Context Map: 上下文之间的集成关系
  Ubiquitous Language: 统一语言 (业务与代码同词)

2.4 模块解耦手段

1. 依赖倒置 (DIP): 依赖抽象不依赖具体
2. 接口隔离: 每个模块只暴露最小接口
3. 事件解耦: 模块间用事件通信而非直接调用
4. 路由解耦: 页面跳转走路由表,不直接 import
5. 数据模型隔离: 各层用自己的模型,禁止直接透传

三、源码/API 深度解析

3.1 分层目录结构落地

entry/src/main/ets/
├── pages/                  # Presentation: 页面 (薄层)
├── components/             # 表现层组件
├── domain/                 # 领域层
│   ├── entities/           # 业务实体
│   ├── usecases/           # 用例
│   └── repositories/       # 仓储接口 (抽象)
├── data/                   # 数据层
│   ├── repositories/       # 仓储实现
│   ├── sources/            # 本地/远程数据源
│   └── models/             # 数据模型 (DTO)
└── di/                     # 依赖注入/组装根

关键: 依赖箭头永远指向 domain,domain 不 import 任何框架

3.2 依赖倒置示例

// domain/repositories/UserRepository.ets —— 接口 (依赖方向: 向外)
export interface UserRepository {
  getUser(id: string): Promise<UserEntity>;
  saveUser(user: UserEntity): Promise<void>;
}

// data/repositories/UserRepositoryImpl.ets —— 实现
import { UserRepository } from '../domain/repositories/UserRepository';
import { rdb } from '@kit.ArkData';

export class UserRepositoryImpl implements UserRepository {
  async getUser(id: string): Promise<UserEntity> {
    // RDB 实现
    const row = await queryUserFromDb(id);
    return rowToEntity(row);
  }
}

// 表现层只依赖接口:
//   const repo: UserRepository = di.get<UserRepository>();
//   → 换实现 (缓存/网络/数据库) 只改 di 组装,不动业务

3.3 用例层封装业务规则

// domain/usecases/PlaceOrderUseCase.ets
export class PlaceOrderUseCase {
  constructor(private orderRepo: OrderRepository,
              private stockRepo: StockRepository) {}

  async execute(userId: string, items: OrderItem[]): Promise<OrderEntity> {
    // 1. 校验库存
    for (const it of items) {
      const stock = await this.stockRepo.getStock(it.skuId);
      if (stock < it.quantity) {
        throw new Error('库存不足: ' + it.skuId);
      }
    }
    // 2. 创建订单 (聚合根)
    const order = OrderEntity.create(userId, items);
    // 3. 持久化
    await this.orderRepo.save(order);
    return order;
  }
}
// 业务规则在领域层,UI/数据库怎么变都不影响它

四、企业级实战落地

4.1 演进路径对照

阶段 特征 问题 演进动作
单体混乱 所有代码一个页面 改一处全崩 先分三层
三层分层 UI/业务/数据分离 层内仍耦合 按业务切模块
模块化 按业务域拆分 模块间强依赖 接口化 + 事件解耦
Clean 依赖向内 组装复杂 引入 DI 容器

4.2 完整示例:架构演进演示

@Entry
@ComponentV2
struct ArchitectureRefactorDemo {
  @Local stage: string = '待开始';
  @Local metrics: string[] = [];
  @Local logs: string[] = [];

  private runEvolution(): void {
    this.logs = [];
    this.stage = '单体混乱';
    this.metrics = [];
    this.log('🏚️ 阶段1: 单体混乱架构');
    this.log('   全部逻辑在页面里: 网络+缓存+业务+UI 混写');
    this.log('   指标: 单文件 3000 行 · 无法单测');

    this.stage = '三层分层';
    this.log('🏗️ 阶段2: 三层分层');
    this.log('   pages/components | domain | data 分离');
    this.log('   业务规则抽到 UseCase,可独立测试');
    this.log('   指标: 耦合度下降 60% · 单测覆盖率 70%');

    this.stage = '模块化';
    this.log('🧩 阶段3: 模块化拆分');
    this.log('   按业务域: order/pay/user/stock 独立模块');
    this.log('   模块间用接口 + 事件通信');
    this.log('   指标: 模块独立构建 · 并行开发');

    this.stage = 'Clean';
    this.log('✨ 阶段4: Clean Architecture');
    this.log('   domain 零框架依赖,可整体迁移');
    this.log('   换 UI/换数据库不动业务核心');
    this.log('   指标: 技术债清除 · 新功能提速 3 倍');
  }

  build() {
    Column({ space: 12 }) {
      Text('🏛️ 架构演进复盘演示').fontSize(20).fontWeight(FontWeight.Bold)
      Text('阶段: ' + this.stage).fontSize(13).fontColor('#0969DA')

      Row({ space: 8 }) {
        Button('▶ 模拟架构演进').layoutWeight(1).height(40).fontSize(12)
          .onClick(() => this.runEvolution())
        Button('清空').height(40).fontSize(12)
          .onClick(() => this.logs = [])
      }
      .width('100%')

      Scroll() {
        Column() {
          ForEach(this.logs, (l: string) => {
            Text(l).fontSize(11).lineHeight(18).fontColor('#24292F').width('100%')
          }, (l: string, i: number) => l + i)
        }.width('100%')
      }
      .layoutWeight(1).width('100%').scrollBar(BarState.Off)
    }
    .width('100%').height('100%').padding(16)
    .backgroundColor('#F6F8FA')
  }
}

4.3 架构复盘清单

1. 画现状依赖图: 找出环状依赖和上帝类
2. 定义目标边界: 按业务域划分,不按技术分层硬切
3. 小步重构: 一次移动一个模块,保持可编译
4. 用测试兜底: 重构前写行为测试,重构后验证
5. 持续演进: 架构评审纳入常规流程,防止再次腐烂

五、问题排查与性能优化

问题 原因 解决
重构后功能回归 行为测试缺失 先写契约测试再重构
分层后性能下降 过度抽象/透传 批量接口 + 避免逐层代理
模块间循环依赖 边界不清 依赖图分析 + 接口下沉
DDD 过度设计 无脑套概念 从价值高的核心域开始
事件风暴难排错 链路不可观测 事件链路 ID 透传
重构拖太久 步子太大 持续集成 + 小步合入

5.1 架构质量度量

1. 耦合度: 模块间依赖数量 (目标: 低)
2. 内聚度: 模块内职责相关性 (目标: 高)
3. 测试性: 核心逻辑单测覆盖率
4. 变更影响面: 改一个需求动的文件数
5. 交付速度: 新功能平均开发时长 (架构回报的终极指标)

六、高阶总结与最佳实践

  1. 架构是演进的:从单体到 Clean 是渐进过程,每步可编译可上线。
  2. 依赖向内:domain 不碰框架,是 Clean Architecture 的灵魂。
  3. 模块按业务切:不是按技术分层切,边界要贴合业务变化。
  4. 测试兜底重构:没有行为测试的重构是赌博。
  5. 复盘常态化:架构评审进流程,防止熵增回归。

一句话记住:架构复盘 = 承认腐烂 → 分层解耦 → 领域建模 → Clean 演进,小步快跑、测试兜底、依赖向内,让架构跟上业务的呼吸。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐