方法命名的完整语义模型:前置定语 · 动词 · 介词短语

方法名不是描述实现,而是提前暴露风险与边界的工程语言


1. 回到最初的问题:为什么“动词规范”还不够?

在工程实践中,我曾系统性梳理过一个核心问题:

不同层级(Controller / AppService / Domain / Infra)
应该使用哪些动词,分别代表什么语义边界?

这解决了一个关键痛点:
👉 动词失真会直接导致架构腐化。

但在长期实践中,我逐渐意识到:
仅靠动词,仍然不足以完整表达一个方法的真实语义。


2. 一个更完整的结论

在现代工程中,一个可被长期遵守的方法命名,应当同时回答三件事:

  1. 它做什么 → 动词(Verb)
  2. 它指向哪里 / 为了谁 / 使用什么 → 介词(Preposition)
  3. 它处于什么阶段或策略下 → 前置定语(Qualifier)

因此,一个稳定的方法命名模型应为:

前置定语 + 动词 + 介词短语


3. 动词:语义承诺的核心(仍然是第一位)

动词依然是方法命名中最重要的部分,因为它直接承诺了:

  • 是否修改状态
  • 是否产生副作用
  • 是否允许 IO / 远程调用

3.1 最小可用动词集(推荐白名单)

① 纯规则 / 无副作用(Domain 优先)

动词 语义
validate 校验,失败抛异常
check 判断,返回 boolean
calculate 计算
derive 派生
parse 解析
match 匹配

❌ 禁止 IO / 禁止状态修改


② 状态演进(Domain / AppService)

动词 语义
apply 状态演进
change 明确修改
mark 标记
reset 重置
assign 建立关系

③ 用例编排(仅 AppService)

动词 语义
execute 执行一个业务用例
dispatch 分发
orchestrate 多步骤编排
trigger 触发异步

execute 只允许存在于 AppService


④ IO / 边界行为(Infra)

动词 语义
call 外部接口
fetch 读取
persist 持久化
send 发送
publish 发布事件

4. 介词:补充“方向性”,而不是补救动词

介词的作用只有一个:

在动词语义已成立的前提下,补充“指向性信息”。

4.1 允许使用的介词(严格收敛)

to —— 目标 / 外部指向

1
2
syncOrderToExternalSystem();
sendMessageToMq();

语义承诺:

  • 存在明确目标

  • 多用于跨系统、跨边界


for —— 用例 / 服务对象

1
2
calculateFeeForOrder(); 
prepareContextForCreate();

强调:为了谁 / 为了什么用例


with —— 手段 / 策略 / 上下文

1
2
executePaymentWithRetry(); 
queryStockWithLock();

限制:

  • with 后必须是具体策略名词

  • 禁止抽象占位词(Something / Logic)


4.2 明确禁止的介词

  • by

  • via

  • using

  • through

这些词会让方法名退化成“自然语言解释”,而非工程语义。


5. 前置定语:表达阶段,而不是叠加信息

前置定语用于表达:

  • 执行模型

  • 生命周期阶段

  • 批量 / 内部语义

5.1 前置定语白名单

前置定语 语义
async 异步
sync 同步
batch 批量
internal 内部
before / after 生命周期钩子

强规则

  • ❗ 最多只能有一个

  • ❗ 不得掩盖动词本身的语义


6. 前置 / 后置处理的正确姿势

6.1 仅表达时序(弱语义)

1
2
beforeExecute(); 
afterExecute();

仅适用于模板方法 / 框架钩子。


6.2 用动词直接表达语义(推荐)

1
2
3
4
validateOrder(); 
prepareOrderContext();
persistOrderState();
cleanupResources();

能不用 pre / post,就不要用。


7. 分层方法命名最终规范(收敛版)

7.1 Controller —— 表达用户意图

1
2
3
createOrder(); 
cancelOrder();
submitPayment();

❌ 禁止:

  • execute / apply / sync

7.2 AppService —— 用例编排者

1
2
3
executeCreateOrder(); 
syncOutboundOrderToLx();
triggerRefundForOrder();

7.3 Domain —— 规则与状态核心

1
2
3
validateOrder(); 
applyStockChange();
calculateTotalAmount();

❌ 禁止:

  • call / persist / send

7.4 Infra —— 外部世界边界

1
2
3
callLxApi(); 
persistOrderSnapshot();
sendMqMessage();

8. 综合示例(完整语义拆解)

1
asyncSyncOutboundOrderToLxForRetry();

拆解:

  • async:执行模型

  • sync:行为类型

  • OutboundOrder:核心对象

  • toLx:外部目标

  • forRetry:用例归属

不读实现,也能判断副作用与风险等级。


9. 速记 / 速查表

一句话口诀

先选动词,再想介词,最后加定语


动词三问法

  1. 改不改状态? → apply / change

  2. 调不调外部? → call / send

  3. 只是规则? → validate / calculate


介词速记

  • 去哪里 → to

  • 为了谁 → for

  • 用什么 → with


定语速记

  • 执行模型 → async / sync

  • 规模 → batch

  • 生命周期 → before / after


10. 结语

方法命名不是个人偏好,而是:

团队长期协作中的语义契约。

当一个方法名能让你在 Code Review 中
不用点进去,也能判断它“值不值得警惕”
它才是一个合格的工程命名。