架构设计规范
AI 友好架构、模块划分与边界、设计模式与重构
规则:架构设计须遵循”高内聚、低耦合、可演进、可观测”四大原则,优先选择简单、清晰、可维护的方案。
[Requirement] 模块之间通过接口/契约通信,禁止跨模块直接访问内部数据结构或私有方法。
[Requirement] 新增功能优先扩展而非修改已有代码(开闭原则),修改须评估对现有调用方的影响。
[Standard] 单一职责:一个模块/类只负责一个业务领域,超过 3 个职责须拆分。
[Standard] 依赖方向单向:上层依赖下层抽象,禁止下层反向依赖上层。
[Default] 默认采用分层架构(Controller → Service → Repository),复杂领域可引入 DDD 分层。
[Caution] 不为”未来可能”提前设计扩展点,保持架构可重构即可,避免过度设计。
AI 友好架构原则:
AI 辅助开发时代,架构设计须额外考虑”让 AI 能高效理解和修改”:
| 原则 | 说明 | 实践 |
|---|---|---|
| 命名自解释 | 模块、类、函数命名即文档 | 避免 util、helper、common 等模糊命名 |
| 边界清晰 | 模块职责单一,输入输出明确 | 每个模块有清晰的 public API |
| 契约显式 | 接口定义完整,含类型与异常 | 用接口/类型签名替代隐式约定 |
| 上下文可获取 | 相关代码与文档集中存放 | 模块目录内包含 README、接口文档 |
| 变更局部化 | 修改一个功能不波及其他模块 | 通过抽象隔离变化点 |
[Suggestion] 模块根目录放置 README.md,说明模块职责、对外接口、依赖关系,便于 AI 和新人快速理解。
反模式:
- ❌ 一个
CommonService包含 50 个方法,什么业务都往里塞。 - ❌ Controller 直接操作数据库,跳过 Service 层。
- ❌ 模块间通过共享全局变量通信,调用关系隐式不可见。
规则:模块按业务领域划分,不按技术层划分;模块边界对应业务边界,而非代码分层。
[Requirement] 模块按业务领域命名(如 payment、user、order),禁止按技术层命名(如 service、dao、util 作为顶层模块)。
[Requirement] 每个模块须有明确的对外接口(public API),模块内部实现对外不可见。
[Standard] 模块大小控制在 5-20 个文件,超过 20 个文件须评估是否拆分子模块。
[Standard] 模块间依赖须显式声明(如 Maven 依赖、import 语句),禁止隐式依赖。
[Default] 默认采用”领域模块 + 分层”结构:领域模块内部再分 controller/service/repository。
推荐的目录结构:
src/├── payment/ # 支付领域模块│ ├── README.md # 模块说明│ ├── controller/ # 对外接口层│ ├── service/ # 业务逻辑层│ ├── repository/ # 数据访问层│ ├── model/ # 领域模型│ └── api/ # 对外暴露的接口定义├── order/ # 订单领域模块└── user/ # 用户领域模块模块划分判断标准:
| 判断维度 | 合格 | 不合格 |
|---|---|---|
| 命名 | 表达业务含义(payment/order) | 表达技术含义(service/common) |
| 职责 | 单一业务领域 | 多个不相关业务混在一起 |
| 对外接口 | 有明确的 public API | 所有类都是 public |
| 依赖 | 依赖方向清晰、单向 | 循环依赖、隐式依赖 |
| 规模 | 5-20 个文件 | >30 个文件或 <1 个文件 |
反模式:
- ❌ 顶层目录按
controller/service/dao分层,改一个业务要跨 3 个目录找文件。 - ❌ 一个
common模块包含工具类、常量、异常、配置,什么都往里放。 - ❌ 模块 A 直接 import 模块 B 的内部实现类,导致修改 B 必改 A。
规则:模块间通过显式接口通信,接口是模块的契约,定义须完整、稳定、向后兼容。
[Requirement] 模块对外暴露的能力必须通过接口(Interface/API)定义,禁止调用方直接依赖实现类。
[Requirement] 接口定义须包含:方法签名、参数类型、返回类型、可能抛出的异常。
[Standard] 接口变更须遵循向后兼容原则:新增方法/参数不影响已有调用方,删除/修改须走废弃流程。
[Standard] 跨模块调用须经过接口层,禁止跨模块直接操作数据库表。
[Default] 默认接口方法不超过 7 个,超过则说明接口职责过多,须拆分。
接口定义示例:
// payment 模块对外接口
public interface PaymentService {
/**
* 创建支付订单
* @param orderId 订单 ID
* @param amount 支付金额(分)
* @return 支付单号
* @throws OrderNotFoundException 订单不存在
* @throws InvalidAmountException 金额非法
*/
String createPayment(Long orderId, Long amount)
throws OrderNotFoundException, InvalidAmountException;
/**
* 查询支付状态
* @param paymentNo 支付单号
* @return 支付状态
*/
PaymentStatus queryStatus(String paymentNo);
}接口边界检查清单:
| 检查项 | 要求 |
|---|---|
| 方法命名 | 动词开头,表达业务动作(createPayment) |
| 参数 | 业务含义明确,禁止传 Map/Object 当万能参数 |
| 返回值 | 类型明确,禁止返回 Object 让调用方强转 |
| 异常 | 声明受检异常,禁止吞异常返回 null |
| 注释 | 每个方法有 Javadoc,说明参数、返回值、异常 |
反模式:
- ❌ 接口方法返回
Object,调用方自己强转,类型不安全。 - ❌ 接口参数传
Map<String, Object>,调用方不知道要传什么 key。 - ❌ 跨模块直接
@Autowired对方的 Repository 操作表,绕过接口。
规则:设计模式是解决特定问题的工具,须按需选用,禁止为了用模式而用模式。
[Standard] 选用设计模式前须确认问题场景与模式意图匹配,不匹配则不用。
[Standard] 优先使用简单方案,只有当简单方案无法满足扩展性需求时才引入设计模式。
[Caution] 一个类同时使用超过 2 种设计模式,须重新评估是否过度设计。
[Suggestion] 引入设计模式时在代码注释中说明使用了什么模式、解决什么问题。
常用模式适用场景:
| 模式 | 适用场景 | 不适用场景 |
|---|---|---|
| 策略模式 | 多种算法/业务规则可互换 | 只有 1-2 种且不会增加 |
| 工厂模式 | 对象创建逻辑复杂、需屏蔽创建细节 | new 一下就够的简单对象 |
| 观察者模式 | 一对多依赖,状态变更需通知多方 | 一对一直接调用即可 |
| 单例模式 | 全局唯一实例(配置、连接池) | 有状态、需多实例的对象 |
| 模板方法 | 流程固定,步骤实现不同 | 流程不固定或只有一个实现 |
| 适配器 | 兼容旧接口/第三方接口 | 接口本身可控,直接改即可 |
示例:策略模式适用场景
# 正确:多种支付方式,且未来可能新增
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount: int) -> bool: ...
class WeChatPay(PaymentStrategy): ...
class Alipay(PaymentStrategy): ...
class PaymentService:
def __init__(self):
self._strategies = {"wechat": WeChatPay(), "alipay": Alipay()}
def pay(self, channel: str, amount: int) -> bool:
return self._strategies[channel].pay(amount)反模式:
- ❌ 只有
if/else两个分支,且不会增加,硬上策略模式 + 工厂 + 注册器。 - ❌ 为了”显得高级”,在简单 CRUD 里套 MVC + 策略 + 观察者 + 责任链。
- ❌ 单例模式滥用,把有状态的业务 Service 做成单例,导致并发问题。
规则:重构是持续改进代码质量的手段,须小步、安全、有测试保障,禁止”大爆炸式”重构。
[Requirement] 重构前必须有测试覆盖(单元测试或集成测试),无测试覆盖的代码禁止大规模重构。
[Requirement] 重构须保持外部行为不变,重构前后功能等价,只改善内部结构。
[Standard] 重构须小步提交,每次提交只做一件事,便于 review 和回滚。
[Standard] 重构须有明确目标(消除重复、降低复杂度、改善命名),禁止”为了重构而重构”。
[Caution] 重构与新功能开发分离,不在同一个 PR 里既重构又加功能,避免 review 困难。
[Default] 默认采用”童子军规则”:离开时让代码比来时更干净,顺手改善看到的坏味道。
重构触发条件:
| 坏味道 | 触发重构 | 目标 |
|---|---|---|
| 重复代码 | 相同逻辑出现 3 次以上 | 抽取公共方法/类 |
| 过长方法 | 方法超过 50 行 | 拆分方法 |
| 过大类 | 类超过 300 行 | 按职责拆分类 |
| 过深嵌套 | if/for 嵌套超过 4 层 | 提前返回/抽取方法 |
| 魔法值 | 硬编码数字/字符串 | 抽取常量/枚举 |
| 长参数列表 | 参数超过 5 个 | 封装为参数对象 |
重构流程:
1. 确认有测试覆盖 ──→ 2. 跑通现有测试 ──→ 3. 小步重构 ↑ │ └──────────── 4. 跑测试验证 ───────────────┘反模式:
- ❌ 没有测试就重构,改完不知道功能对不对。
- ❌ 一次重构 50 个文件,review 不了,出问题找不到原因。
- ❌ 重构和新功能混在一个 PR,review 时分不清哪些是行为变更。