Appearance
本文规定领域模型层与应用服务层的业务语义注释标准:哪些元素必须写、写到什么程度、哪些写法无效。类级注释、公有方法注释等通用要求见仓库根目录 AGENTS.md;本文在其之上补充字段级标准,不重复通用条款。
AGENTS.md
代码能表达"是什么",表达不了"业务上为什么、口径是什么、边界在哪"。合格的业务语义注释只承载三类信息:
实付金额:平台优惠后金额,与 platformDiscount 同币种
只推进物流状态,不改动支付状态与订单生命周期状态
记录 ADD_ITEM 操作,不发布事件
以下内容不属于注释职责:实现步骤、伪代码、类型复述、示例代码、需求编号与版本历史。这些信息由代码本身、设计文档与 Git 历史承载。
{Action}Input
本规范只覆盖上表元素。值对象、领域事件、参数对象(IParamObject)与接口层 DTO 的注释,按 AGENTS.md 的通用要求执行,不在本文强制范围。
IParamObject
字段采用非自解释才必填原则。命中以下任一类,必须写业务口径注释:
Money
BigDecimal
LocalDateTime
Instant
code
status
type
名称已完整表达业务口径、且不命中上表的字段,注释可省略——productId、receiverPhone 属于此类。
productId
receiverPhone
⚠️ 重要约束:同一类内风格必须一致。不能一半字段有注释、一半没有;命中清单的必须写,未命中的可省,但"可省"不等于"随手补一句翻译"。可执行判定法:把字段名交给不熟悉该业务的人,若他无法说出"这个字段在业务上是什么口径",就属于必须注释。
⚠️ 重要约束:同一类内风格必须一致。不能一半字段有注释、一半没有;命中清单的必须写,未命中的可省,但"可省"不等于"随手补一句翻译"。
可执行判定法:把字段名交给不熟悉该业务的人,若他无法说出"这个字段在业务上是什么口径",就属于必须注释。
/** 商品标识 */ private Long productId;
// ✅ 推荐:状态字段写清赋值时机(Order) /** * 订单生命周期状态:仅在创建 / 取消 / 关闭 / 完成等生命周期动作中显式赋值。 */ private OrderStatus status; // ✅ 推荐:外部回填字段写清来源(Order) /** * 库存预占单号:外部库存系统预占成功后的事实回填。 */ private String reserveNo; // ✅ 推荐:派生字段写清派生关系(OrderItem 补充后) /** * 订单项小计,由 price 与 quantity 相乘派生,随数量或单价变更同步刷新。 */ private Money subtotal; // ❌ 反例:同义反复,不提供任何业务信息 /** 商品 ID。 */ private Long productId; // ❌ 反例:派生字段未写派生关系,读者无法判断何时刷新(OrderItem 原始写法) private Money subtotal;
公有业务方法必须回答三件事:
recordOperation
collectEvent
@param 只写参数的业务口径;参数名已表达含义时省略,不写 @param quantity 数量 这类复述。
@param
@param quantity 数量
// ✅ 推荐:动作 + 副作用 + 状态边界(Order) /** * 标记订单已发货并记录物流信息,并发布订单发货事件。 * 只推进物流状态,不改动支付状态与订单生命周期状态。 * * @param logisticsInfo 物流信息 */ public void ship(LogisticsInfo logisticsInfo) { // ... } // ✅ 推荐:说明与相邻动作的差异,防止误用(Order) /** * 修正已录入的物流信息,并发布物流信息修正事件。 * 仅替换物流信息用于纠错,不推进物流状态、不改动支付状态与订单生命周期状态。 */ public void correctLogisticsInfo(LogisticsInfo logisticsInfo, String reason) { // ... } // ❌ 反例:裸方法,读者无法判断是否会刷小计、是否发事件 public void changeQuantity(int quantity) { // ... }
业务方法遵循"纯赋值"原则(见聚合设计原则 §3.3)。注释因此不写守卫条件、字段组装、格式转换等内容——这些职责不在业务方法内。
protected
/** * 基于初始化数据创建订单并持有初始订单项,发布订单创建事件。 * * @param data 订单初始化参数 * @param orderId 订单标识 */ public Order(OrderInitData data, Long orderId) { // ... } /** * 仅供持久化框架重建,空实现。 */ protected Order() { }
每个 {Action}Input 的类注释必须写清三件事:
Factory
Updater
// ✅ 推荐:三要素齐备(ShipOrderInput) /** * 订单发货入参:业务语义、与协议无关、自有扁平结构。 * 不引用领域值对象 LogisticsInfo,由 OrderShipUpdater 转换为领域 LogisticsInfo。 * 时间字段使用 LocalDateTime(业务本地发货时间,与 LogisticsInfo.shippedAt 对齐)。 */ @Data public class ShipOrderInput { // ... }
Input 字段是外部调用方与领域模型之间的契约,字段注释写调用方必须知道的口径,而不是转换后的领域结构。
必写场景(在 §1.3 基础上补充):
companyCode
// ✅ 推荐:金额与币种成组说明(AddOrderItemInput) /** * 单价币种。 */ private String currency; /** * 单价金额。 */ private BigDecimal unitPrice; // ✅ 推荐:编码型字段写清来源(ShipOrderInput 补充后) /** * 快递公司编码,由物流服务商提供。 */ private String companyCode; // ❌ 反例:金额与币种分离,且未写两者关系(CreateOrderItemInput) private BigDecimal unitPriceAmount; private String unitPriceCurrency;
CreateOrderInput.orderItems 的字段注释应说明元素语义与转换归属,例如"下单商品项,由 OrderFactory 转换为领域 OrderItem 列表"。
CreateOrderInput.orderItems
//
/** ... */
<p>
@version
@since
/** 商品 ID */
代码注释规范(领域模型与应用服务)
1. 定位与适用范围
1.1 注释承载什么
代码能表达"是什么",表达不了"业务上为什么、口径是什么、边界在哪"。合格的业务语义注释只承载三类信息:
实付金额:平台优惠后金额,与 platformDiscount 同币种只推进物流状态,不改动支付状态与订单生命周期状态记录 ADD_ITEM 操作,不发布事件以下内容不属于注释职责:实现步骤、伪代码、类型复述、示例代码、需求编号与版本历史。这些信息由代码本身、设计文档与 Git 历史承载。
1.2 适用范围与强度
{Action}Input类1.3 什么时候必须写
字段采用非自解释才必填原则。命中以下任一类,必须写业务口径注释:
Money/BigDecimal/ 数值LocalDateTime/Instant/ 时间戳code/status/type名称已完整表达业务口径、且不命中上表的字段,注释可省略——
productId、receiverPhone属于此类。2. 领域模型层
2.1 字段注释:写业务口径
/** 商品标识 */ private Long productId;)、持久化细节(列名、字段长度)、与代码重复的类型说明。2.2 业务方法注释:意图 + 状态迁移 + 副作用
公有业务方法必须回答三件事:
recordOperation、是否collectEvent、是否触发数据同步。@param只写参数的业务口径;参数名已表达含义时省略,不写@param quantity 数量这类复述。2.3 构造方法注释
recordOperation/collectEvent)。protected重建构造:一句话说明"仅供持久化框架重建",不写业务逻辑。3. 应用服务层
3.1 Input 类注释:三要素
每个
{Action}Input的类注释必须写清三件事:Factory/Updater转换为领域对象。3.2 Input 字段注释:写协议看不出来的口径
Input 字段是外部调用方与领域模型之间的契约,字段注释写调用方必须知道的口径,而不是转换后的领域结构。
必写场景(在 §1.3 基础上补充):
companyCode为快递公司编码)Money)CreateOrderInput.orderItems的字段注释应说明元素语义与转换归属,例如"下单商品项,由 OrderFactory 转换为领域 OrderItem 列表"。4. 注释形式规范
//与行尾块注释/** ... */;多句或含边界说明用多行块。同一个类内保持一致<p>分隔@version/@since/ 日期 / 需求号@param只写业务口径,禁止复述参数名和类型;无额外口径时省略5. 常见反模式
/** 商品 ID */)@param复述参数名6. 自检清单
7. 下一步