Screaming Architecture: 让你的代码架构会说话

Screaming Architecture: 让你的代码架构会说话

概述

在软件开发中,我们经常遇到这样的问题:当一个新团队成员查看项目代码时,需要花费很长时间才能理解这个系统是做什么的。这就像走进一座建筑,却无法一眼看出这是医院还是商场。Screaming Architecture 的核心理念就是解决这个问题 - 让系统的目的和核心业务在代码结构中清晰可见。

本文将探讨:

  • \[Screaming architecture\|Screaming Architecture\]\] 的核心概念

  • 常见的实现陷阱和解决方案
  • 在不同规模项目中的应用策略

1. 什么是 Screaming Architecture

1.1 核心概念

Screaming Architecture 这个概念最早由 Robert C. Martin (Uncle Bob) 提出。他用建筑学做了一个绝妙的类比:当你看到一所建筑的蓝图时,应该能立即知道这是一所图书馆还是一所医院。同样,当查看一个软件项目的顶层目录结构时,应该能立即理解这个系统的用途。

1.2 传统架构 vs Screaming Architecture

csharp 复制代码
// 传统的分层架构
src/
  ├── controllers/
  ├── services/
  ├── repositories/
  └── models/

// Screaming Architecture
src/
  ├── catalog/           # 产品目录管理
  ├── ordering/          # 订单处理
  ├── inventory/         # 库存管理
  └── shipping/          # 物流配送

1.3 核心优势

  • 提高代码可读性和可理解性
  • 加快新团队成员的上手速度
  • 便于系统演进和重构
  • 强化领域驱动设计的实践

实践启示

在实际项目中,完全按照业务功能组织代码可能会遇到一些挑战。比如跨功能的共享组件该如何放置,或者是否要为了保持清晰的业务结构而牺牲一些代码复用性。这需要在实践中找到平衡点。

2. 实现 Screaming Architecture

2.1 目录结构设计

让我们通过一个电子商务系统的例子来说明如何实现 Screaming Architecture:

typescript 复制代码
// e-commerce/
src/
  ├── product/
  │   ├── domain/
  │   │   ├── Product.ts          # 产品领域模型
  │   │   └── ProductService.ts    # 产品领域服务
  │   ├── application/
  │   │   ├── ProductController.ts # API 控制器
  │   │   └── ProductDTO.ts        # 数据传输对象
  │   └── infrastructure/
  │       └── ProductRepository.ts  # 数据访问层
  │
  ├── order/
  │   ├── domain/
  │   │   ├── Order.ts
  │   │   └── OrderService.ts
  │   ├── application/
  │   │   └── OrderController.ts
  │   └── infrastructure/
  │       └── OrderRepository.ts
  │
  └── shared/                      # 共享模块
      ├── types/
      ├── utils/
      └── infrastructure/

2.2 代码实现示例

下面是一个具体的实现示例:

typescript 复制代码
// src/product/domain/Product.ts
export class Product {
  private id: string;
  private name: string;
  private price: number;
  private inventory: number;

  constructor(id: string, name: string, price: number, inventory: number) {
    this.id = id;
    this.name = name;
    this.price = price;
    this.inventory = inventory;
  }

  // 领域行为
  public decreaseInventory(quantity: number): void {
    if (quantity > this.inventory) {
      throw new Error('Insufficient inventory');
    }
    this.inventory -= quantity;
  }
}

// src/product/application/ProductController.ts
@Controller('/products')
export class ProductController {
  constructor(private productService: ProductService) {}

  @Get('/:id')
  async getProduct(@Param('id') id: string): Promise<ProductDTO> {
    const product = await this.productService.findById(id);
    return ProductMapper.toDTO(product);
  }
}

2.3 关键设计决策

  1. 按业务功能组织代码
  2. 在每个业务模块内部采用分层架构
  3. 共享代码放在 shared 目录
  4. 依赖注入实现模块间的解耦

设计考量

  • 模块大小的把握:太大会导致代码难以维护,太小会增加不必要的复杂性
  • 跨模块调用的处理:是否允许直接调用,或强制通过接口
  • 共享代码的管理:什么代码应该放在 shared 目录

3. 架构演进

3.1 从传统架构迁移

分步骤迁移策略:

  1. 识别核心业务模块
  2. 创建新的目录结构
  3. 渐进式地移动代码
  4. 重构跨模块依赖

3.2 处理遗留系统

typescript 复制代码
// 过渡期的混合架构
src/
  ├── legacy/              # 遗留代码
  │   ├── controllers/
  │   └── services/
  │
  ├── product/            # 新架构
  │   ├── domain/
  │   └── application/
  │
  └── shared/             # 共享代码

实践启示

在实际项目中,很少有机会从零开始实现完美的架构。通常需要在保持系统稳定运行的同时,渐进式地改进架构。关键是要有清晰的目标架构和循序渐进的迁移计划。

总结

Screaming Architecture 不仅仅是一种代码组织方式,更是一种设计思维。它强调:

  • 业务领域应该是代码组织的主要依据
  • 系统的用途应该在代码结构中清晰可见
  • 架构应该服务于业务,而不是技术框架

练习题

  1. 给定一个传统的分层架构项目,如何将其重构为 Screaming Architecture?
  2. 在一个电子商务系统中,订单处理和支付处理是否应该是独立的顶层模块?为什么?
  3. 如何处理跨模块的业务流程?比如下单流程涉及商品、库存、订单等多个模块。
  4. 在微服务架构中,如何应用 Screaming Architecture 的原则?

延伸阅读

  • Clean Architecture by Robert C. Martin
  • Domain-Driven Design by Eric Evans
  • Building Evolutionary Architectures by Neal Ford
    • \[Ford et al. - 2022 - Building evolutionary architectures automated software governance.pdf\]

相关推荐
杨筱毅6 小时前
【底层机制】ART虚拟机深度解析:Android运行时的架构革命
android·架构·底层机制
言之。7 小时前
【数据库】TiDB 技术选型与架构分析报告
数据库·架构·tidb
GIOTTO情7 小时前
舆情处置技术深度解析:Infoseek 字节探索的 AI 闭环架构与实现逻辑
人工智能·架构
KG_LLM图谱增强大模型7 小时前
突破AI助手成本壁垒:知识图谱思维架构让小模型实现大性能
人工智能·架构·大模型·知识图谱·graphrag
喜欢吃豆7 小时前
[特殊字符] 深入解构 Assistants API:从“黑盒”抽象到“显式”控制的架构演进与终极指南
网络·人工智能·自然语言处理·架构·大模型
serendipity_hky10 小时前
【微服务 - easy视频 | day01】准备工具+gateway网关及路由至内部服务
java·微服务·架构·gateway·springcloud
小哈里12 小时前
【软考架构】2025H2系统架构设计师考试复习.jpg(软件架构、软件工程、数据库、Web开发、高项)
数据库·架构·系统架构·软件工程·后端开发
常先森15 小时前
【解密源码】 RAGFlow 切分最佳实践- naive parser 语义切块(markdown 篇)
架构·llm·agent
报错小能手15 小时前
计算机网络自顶向下方法39——网络层 中间盒 互联网架构原则(IP沙漏 端到端原则)
tcp/ip·计算机网络·架构
Hilaku17 小时前
我用AI重构了一段500行的屎山代码,这是我的Prompt和思考过程
前端·javascript·架构