architecture-review

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Architecture Review Skill

架构评审技能

Analyze project structure at the macro level - packages, modules, layers, and boundaries.
从宏观层面分析项目结构:包、模块、分层以及边界。

When to Use

适用场景

  • User asks "review the architecture" / "check project structure"
  • Evaluating package organization
  • Checking dependency direction between layers
  • Identifying architectural violations
  • Assessing clean/hexagonal architecture compliance

  • 用户提出「评审架构」/「检查项目结构」类需求
  • 评估包组织合理性
  • 检查分层之间的依赖方向
  • 识别架构违规问题
  • 评估项目对clean/hexagonal架构规范的遵循程度

Quick Reference: Architecture Smells

快速参考:架构异味

SmellSymptomImpact
Package-by-layer bloat
service/
with 50+ classes
Hard to find related code
Domain → Infra dependencyEntity imports
@Repository
Core logic tied to framework
Circular dependenciesA → B → C → AUntestable, fragile
God package
util/
or
common/
growing
Dump for misplaced code
Leaky abstractionsController knows SQLLayer boundaries violated

异味类型症状影响
按层分包臃肿
service/
目录下有50+个类
难以找到关联代码
领域层依赖基础设施层实体类导入
@Repository
注解
核心逻辑与框架强耦合
循环依赖A → B → C → A难以测试、代码脆弱
上帝包
util/
common/
持续膨胀
成为乱放代码的垃圾场
抽象泄漏Controller 直接感知SQL逻辑分层边界被破坏

Package Organization Strategies

包组织策略

Package-by-Layer (Traditional)

按层分包(传统方式)

com.example.app/
├── controller/
│   ├── UserController.java
│   ├── OrderController.java
│   └── ProductController.java
├── service/
│   ├── UserService.java
│   ├── OrderService.java
│   └── ProductService.java
├── repository/
│   ├── UserRepository.java
│   ├── OrderRepository.java
│   └── ProductRepository.java
└── model/
    ├── User.java
    ├── Order.java
    └── Product.java
Pros: Familiar, simple for small projects Cons: Scatters related code, doesn't scale, hard to extract modules
com.example.app/
├── controller/
│   ├── UserController.java
│   ├── OrderController.java
│   └── ProductController.java
├── service/
│   ├── UserService.java
│   ├── OrderService.java
│   └── ProductService.java
├── repository/
│   ├── UserRepository.java
│   ├── OrderRepository.java
│   └── ProductRepository.java
└── model/
    ├── User.java
    ├── Order.java
    └── Product.java
优点:开发者熟悉,小型项目使用简单 缺点:关联代码分散,可扩展性差,难以抽取独立模块

Package-by-Feature (Recommended)

按特性分包(推荐)

com.example.app/
├── user/
│   ├── UserController.java
│   ├── UserService.java
│   ├── UserRepository.java
│   └── User.java
├── order/
│   ├── OrderController.java
│   ├── OrderService.java
│   ├── OrderRepository.java
│   └── Order.java
└── product/
    ├── ProductController.java
    ├── ProductService.java
    ├── ProductRepository.java
    └── Product.java
Pros: Related code together, easy to extract, clear boundaries Cons: May need shared kernel for cross-cutting concerns
com.example.app/
├── user/
│   ├── UserController.java
│   ├── UserService.java
│   ├── UserRepository.java
│   └── User.java
├── order/
│   ├── OrderController.java
│   ├── OrderService.java
│   ├── OrderRepository.java
│   └── Order.java
└── product/
    ├── ProductController.java
    ├── ProductService.java
    ├── ProductRepository.java
    └── Product.java
优点:关联代码聚合存放,易于抽取模块,边界清晰 缺点:横切关注点可能需要共享内核处理

Hexagonal/Clean Architecture

Hexagonal/Clean Architecture

com.example.app/
├── domain/                    # Pure business logic (no framework imports)
│   ├── model/
│   │   └── User.java
│   ├── port/
│   │   ├── in/               # Use cases (driven)
│   │   │   └── CreateUserUseCase.java
│   │   └── out/              # Repositories (driving)
│   │       └── UserRepository.java
│   └── service/
│       └── UserDomainService.java
├── application/               # Use case implementations
│   └── CreateUserService.java
├── adapter/
│   ├── in/
│   │   └── web/
│   │       └── UserController.java
│   └── out/
│       └── persistence/
│           ├── UserJpaRepository.java
│           └── UserEntity.java
└── config/
    └── BeanConfiguration.java
Key rule: Dependencies point inward (adapters → application → domain)

com.example.app/
├── domain/                    # 纯业务逻辑(无框架导入)
│   ├── model/
│   │   └── User.java
│   ├── port/
│   │   ├── in/               # 用例(被驱动)
│   │   │   └── CreateUserUseCase.java
│   │   └── out/              # 仓库(驱动)
│   │       └── UserRepository.java
│   └── service/
│       └── UserDomainService.java
├── application/               # 用例实现
│   └── CreateUserService.java
├── adapter/
│   ├── in/
│   │   └── web/
│   │       └── UserController.java
│   └── out/
│       └── persistence/
│           ├── UserJpaRepository.java
│           └── UserEntity.java
└── config/
    └── BeanConfiguration.java
核心规则:依赖方向向内(适配器 → 应用层 → 领域层)

Dependency Direction Rules

依赖方向规则

The Golden Rule

黄金法则

┌─────────────────────────────────────────┐
│              Frameworks                 │  ← Outer (volatile)
├─────────────────────────────────────────┤
│           Adapters (Web, DB)            │
├─────────────────────────────────────────┤
│         Application Services            │
├─────────────────────────────────────────┤
│          Domain (Core Logic)            │  ← Inner (stable)
└─────────────────────────────────────────┘

Dependencies MUST point inward only.
Inner layers MUST NOT know about outer layers.
┌─────────────────────────────────────────┐
│              Frameworks                 │  ← 外层(易变)
├─────────────────────────────────────────┤
│           Adapters (Web, DB)            │
├─────────────────────────────────────────┤
│         Application Services            │
├─────────────────────────────────────────┤
│          Domain (Core Logic)            │  ← 内层(稳定)
└─────────────────────────────────────────┘

依赖必须仅向内指向
内层绝对不能感知外层的存在

Violations to Flag

需要标记的违规情况

java
// ❌ Domain depends on infrastructure
package com.example.domain.model;

import org.springframework.data.jpa.repository.JpaRepository;  // Framework leak!
import javax.persistence.Entity;  // JPA in domain!

@Entity
public class User {
    // Domain polluted with persistence concerns
}

// ❌ Domain depends on adapter
package com.example.domain.service;

import com.example.adapter.out.persistence.UserJpaRepository;  // Wrong direction!

// ✅ Domain defines port, adapter implements
package com.example.domain.port.out;

public interface UserRepository {  // Pure interface, no JPA
    User findById(UserId id);
    void save(User user);
}

java
// ❌ 领域层依赖基础设施
package com.example.domain.model;

import org.springframework.data.jpa.repository.JpaRepository;  // 框架泄漏!
import javax.persistence.Entity;  // 领域层出现JPA!

@Entity
public class User {
    // 领域层被持久化逻辑污染
}

// ❌ 领域层依赖适配器
package com.example.domain.service;

import com.example.adapter.out.persistence.UserJpaRepository;  // 依赖方向错误!

// ✅ 领域层定义端口,适配器实现接口
package com.example.domain.port.out;

public interface UserRepository {  // 纯接口,无JPA依赖
    User findById(UserId id);
    void save(User user);
}

Architecture Review Checklist

架构评审检查清单

1. Package Structure

1. 包结构

  • Clear organization strategy (by-layer, by-feature, or hexagonal)
  • Consistent naming across modules
  • No
    util/
    or
    common/
    packages growing unbounded
  • Feature packages are cohesive (related code together)
  • 有清晰的组织策略(按层、按特性、六边形架构)
  • 模块间命名统一
  • util/
    common/
    包没有无限制膨胀
  • 特性包高内聚(关联代码聚合存放)

2. Dependency Direction

2. 依赖方向

  • Domain has ZERO framework imports (Spring, JPA, Jackson)
  • Adapters depend on domain, not vice versa
  • No circular dependencies between packages
  • Clear dependency hierarchy
  • 领域层完全没有框架导入(Spring、JPA、Jackson)
  • 适配器依赖领域层,而非反之
  • 包之间没有循环依赖
  • 依赖层级清晰

3. Layer Boundaries

3. 分层边界

  • Controllers don't contain business logic
  • Services don't know about HTTP (no HttpServletRequest)
  • Repositories don't leak into controllers
  • DTOs at boundaries, domain objects inside
  • Controller不包含业务逻辑
  • 服务层不感知HTTP相关逻辑(无HttpServletRequest依赖)
  • Repository逻辑不泄漏到Controller层
  • 边界处使用DTO,内部使用领域对象

4. Module Boundaries

4. 模块边界

  • Each module has clear public API
  • Internal classes are package-private
  • Cross-module communication through interfaces
  • No "reaching across" modules for internals
  • 每个模块有清晰的公开API
  • 内部类为包私有权限
  • 跨模块通信通过接口实现
  • 没有跨模块直接访问内部实现的情况

5. Scalability Indicators

5. 可扩展性指标

  • Could extract a feature to separate service? (microservice-ready)
  • Are boundaries enforced or just conventional?
  • Does adding a feature require touching many packages?

  • 可将单个特性抽取为独立服务?(具备微服务改造基础)
  • 边界是强制约束还是仅靠约定遵循?
  • 新增特性是否需要修改多个包的代码?

Common Anti-Patterns

常见反模式

1. The Big Ball of Mud

1. 大泥球架构

src/main/java/com/example/
└── app/
    ├── User.java
    ├── UserController.java
    ├── UserService.java
    ├── UserRepository.java
    ├── Order.java
    ├── OrderController.java
    ├── ... (100+ files in one package)
Fix: Introduce package structure (start with by-feature)
src/main/java/com/example/
└── app/
    ├── User.java
    ├── UserController.java
    ├── UserService.java
    ├── UserRepository.java
    ├── Order.java
    ├── OrderController.java
    ├── ... (100+ files in one package)
修复方案:引入包结构(优先从按特性分包开始)

2. The Util Dumping Ground

2. Util垃圾场

util/
├── StringUtils.java
├── DateUtils.java
├── ValidationUtils.java
├── SecurityUtils.java
├── EmailUtils.java      # Should be in notification module
├── OrderCalculator.java # Should be in order domain
└── UserHelper.java      # Should be in user domain
Fix: Move domain logic to appropriate modules, keep only truly generic utils
util/
├── StringUtils.java
├── DateUtils.java
├── ValidationUtils.java
├── SecurityUtils.java
├── EmailUtils.java      # 应放在通知模块
├── OrderCalculator.java # 应放在订单领域层
└── UserHelper.java      # 应放在用户领域层
修复方案:将领域逻辑迁移到对应模块,仅保留真正通用的工具方法

3. Anemic Domain Model

3. 贫血领域模型

java
// Domain object is just data
public class Order {
    private Long id;
    private List<OrderLine> lines;
    private BigDecimal total;
    // Only getters/setters, no behavior
}

// All logic in "service"
public class OrderService {
    public void addLine(Order order, Product product, int qty) { ... }
    public void calculateTotal(Order order) { ... }
    public void applyDiscount(Order order, Discount discount) { ... }
}
Fix: Move behavior to domain objects (rich domain model)
java
// 领域对象仅承载数据
public class Order {
    private Long id;
    private List<OrderLine> lines;
    private BigDecimal total;
    // 仅包含getter/setter,无业务行为
}

// 所有逻辑都放在「service」中
public class OrderService {
    public void addLine(Order order, Product product, int qty) { ... }
    public void calculateTotal(Order order) { ... }
    public void applyDiscount(Order order, Discount discount) { ... }
}
修复方案:将业务行为迁移到领域对象中(实现富领域模型)

4. Framework Coupling in Domain

4. 领域层与框架耦合

java
package com.example.domain;

@Entity  // JPA
@Data    // Lombok
@JsonIgnoreProperties(ignoreUnknown = true)  // Jackson
public class User {
    @Id @GeneratedValue
    private Long id;

    @NotBlank  // Validation
    private String email;
}
Fix: Separate domain model from persistence/API models

java
package com.example.domain;

@Entity  // JPA注解
@Data    // Lombok注解
@JsonIgnoreProperties(ignoreUnknown = true)  // Jackson注解
public class User {
    @Id @GeneratedValue
    private Long id;

    @NotBlank  // 校验注解
    private String email;
}
修复方案:将领域模型与持久化/API模型拆分

Analysis Commands

分析命令

When reviewing architecture, examine:
bash
undefined
评审架构时,可执行以下命令排查问题:
bash
undefined

Package structure overview

包结构概览

find src/main/java -type d | head -30
find src/main/java -type d | head -30

Largest packages (potential god packages)

最大的包(潜在上帝包)

find src/main/java -name "*.java" | xargs dirname | sort | uniq -c | sort -rn | head -10
find src/main/java -name "*.java" | xargs dirname | sort | uniq -c | sort -rn | head -10

Check for framework imports in domain

检查领域层是否存在框架导入

grep -r "import org.springframework" src/main/java//domain/ 2>/dev/null grep -r "import javax.persistence" src/main/java//domain/ 2>/dev/null
grep -r "import org.springframework" src/main/java//domain/ 2>/dev/null grep -r "import javax.persistence" src/main/java//domain/ 2>/dev/null

Find circular dependencies (look for bidirectional imports)

查找循环依赖(排查双向导入)

Check if package A imports from B and B imports from A

检查是否存在A包导入B同时B包导入A的情况


---

---

Recommendations Format

建议输出格式

When reporting findings:
markdown
undefined
提交结果时参考以下格式:
markdown
undefined

Architecture Review: [Project Name]

架构评审:[项目名称]

Structure Assessment

结构评估

  • Organization: Package-by-layer / Package-by-feature / Hexagonal
  • Clarity: Clear / Mixed / Unclear
  • 组织方式:按层分包 / 按特性分包 / 六边形架构
  • 清晰度:清晰 / 混合 / 不清晰

Findings

发现问题

SeverityIssueLocationRecommendation
HighDomain imports Spring
domain/model/User.java
Extract pure domain model
MediumGod package
util/
(23 classes)
Distribute to feature modules
LowInconsistent naming
service/
vs
services/
Standardize to
service/
严重程度问题位置优化建议
领域层导入Spring依赖
domain/model/User.java
抽取纯领域模型
上帝包存在
util/
(23个类)
将非通用逻辑迁移到对应特性模块
命名不统一
service/
services/
并存
统一使用
service/
命名

Dependency Analysis

依赖分析

[Describe dependency flow, violations found]
[描述依赖流向、发现的违规问题]

Recommendations

优化建议

  1. [Highest priority fix]
  2. [Second priority]
  3. [Nice to have]

---
  1. [最高优先级修复项]
  2. [次优先级修复项]
  3. [优化项]

---

Token Optimization

Token优化

For large codebases:
  1. Start with
    find
    to understand structure
  2. Check only domain package for framework imports
  3. Sample 2-3 features for pattern analysis
  4. Don't read every file - look for patterns
针对大型代码库:
  1. 优先使用
    find
    命令梳理整体结构
  2. 仅检查领域包的框架导入情况
  3. 抽样2-3个特性做模式分析
  4. 无需逐文件阅读,重点关注通用模式