architecture-review
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseArchitecture 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
快速参考:架构异味
| Smell | Symptom | Impact |
|---|---|---|
| Package-by-layer bloat | | Hard to find related code |
| Domain → Infra dependency | Entity imports | Core logic tied to framework |
| Circular dependencies | A → B → C → A | Untestable, fragile |
| God package | | Dump for misplaced code |
| Leaky abstractions | Controller knows SQL | Layer boundaries violated |
| 异味类型 | 症状 | 影响 |
|---|---|---|
| 按层分包臃肿 | | 难以找到关联代码 |
| 领域层依赖基础设施层 | 实体类导入 | 核心逻辑与框架强耦合 |
| 循环依赖 | A → B → C → A | 难以测试、代码脆弱 |
| 上帝包 | | 成为乱放代码的垃圾场 |
| 抽象泄漏 | 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.javaPros: 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.javaPros: 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.javaKey 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 or
util/packages growing unboundedcommon/ - 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 domainFix: 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
undefinedPackage 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
undefinedArchitecture Review: [Project Name]
架构评审:[项目名称]
Structure Assessment
结构评估
- Organization: Package-by-layer / Package-by-feature / Hexagonal
- Clarity: Clear / Mixed / Unclear
- 组织方式:按层分包 / 按特性分包 / 六边形架构
- 清晰度:清晰 / 混合 / 不清晰
Findings
发现问题
| Severity | Issue | Location | Recommendation |
|---|---|---|---|
| High | Domain imports Spring | | Extract pure domain model |
| Medium | God package | | Distribute to feature modules |
| Low | Inconsistent naming | | Standardize to |
| 严重程度 | 问题 | 位置 | 优化建议 |
|---|---|---|---|
| 高 | 领域层导入Spring依赖 | | 抽取纯领域模型 |
| 中 | 上帝包存在 | | 将非通用逻辑迁移到对应特性模块 |
| 低 | 命名不统一 | | 统一使用 |
Dependency Analysis
依赖分析
[Describe dependency flow, violations found]
[描述依赖流向、发现的违规问题]
Recommendations
优化建议
- [Highest priority fix]
- [Second priority]
- [Nice to have]
---- [最高优先级修复项]
- [次优先级修复项]
- [优化项]
---Token Optimization
Token优化
For large codebases:
- Start with to understand structure
find - Check only domain package for framework imports
- Sample 2-3 features for pattern analysis
- Don't read every file - look for patterns
针对大型代码库:
- 优先使用命令梳理整体结构
find - 仅检查领域包的框架导入情况
- 抽样2-3个特性做模式分析
- 无需逐文件阅读,重点关注通用模式