人民币一毛钱等于10分钱,借此隐喻10分钟,在短短的10分钟,一个Web API的URL的命名发生了10多次的变更。10分钟内,袁帅和两名开发人员发生了N次对话,在这些对话中,三位对业务命名的朴实无华的追求。

标题:“可能你是因为好奇我身上的“一毛钱”点开了我,接下来我希望你愿意出资不到“一毛钱”的时间成本,跟随作者去感受程序员那些本真的东西。”

10分钟的对话成员:

  • 华仔,需求的开发人员
  • 丹娜,华仔的技术组长
  • 袁帅,软件技术教练

需求抢先看

这个是Web API接口需求,后端通过Web Service 框架Jersy提供API,需求文档里的描述是“待审核的审批前撤销查询”。

一毛钱代驾

华仔将API设计xmind文档投屏到小米电视上,丹娜和袁帅看了一小会儿,不约而同地盯上API契约部分的URL:

  1. V0.1: POST /newbiz/{userId}/query-to-audit-cancle-before-approval

袁帅:“这个接口表达什么含义?userId是指什么用户?”
华仔:“接口想表达待审核的审批前撤销查询,需求文档是这么写的。userId是第三方系统的登录用户id,在咱们系统叫userId。”

华仔麻利地切换到Word需求文档,上面写着“待审核的审批前撤销查询”,看完这段文字,袁帅微微眉头紧锁,正要破口提问,华仔就提到这里不对,应该是“待审核的审批前撤件查询”,说完华仔在文档上做了更正。

袁帅:“撤件,件是指什么?”
丹娜:“件是指新契约业务流程中的投保单。”
袁帅:“OK,所以cancle-before-approval表达的是未审批前的撤销咯,未审批前的撤件是不是就可以加一个宾实体了,比如:newbiz-cancel-before-approval,表达出撤销新契约。”

丹娜和华仔都没有反对,华仔更新了URL:

  1. V0.2: POST /newbiz/{userId}/query-to-audit-newbiz-cancel-before-approval

袁帅:“待审核的审批前撤件,to-audit表示待审核?”
华仔:“是的!”
丹娜:“如果用to-这种结构,待审核应该是to-be-audited,这样子URL就有点太长了。”

丹娜若有所思地转向自己电脑,做了一番操作,说到:“刚查了一下词典,用这个吧:unaudited。”

华仔动了下手指,URL立即瘦身:

  1. V0.3: POST /newbiz/{userId}/query-unaudited-newbiz-cancel-before-approval

袁帅为丹娜找到一个这么好的词点了个赞,随后注意力迅速后移,并自言自语道:“query-unaudited-newbiz-cancel-before-approval,从这个结构来看,有点像是unaudited-newbiz是一个主体,表达了「待审核的新契约」在审批前撤销,而不是原来的待审核的「审批前的新契约撤销」,意思是不是变了?你俩咀嚼一下。”

丹娜和华仔看了一会儿,英语还不错的丹娜看出了端倪,华仔也觉得有点不对劲。正在他俩思考时,袁帅用谷歌翻译倒腾了几番,兴奋道:“这样如何?query-unaudited-unapproved-newbiz-cancel”

华仔火速变更了URL:

  1. V0.4: POST /newbiz/{userId}/query-unaudited-unapproved-newbiz-cancel

刚改完,华仔发现cancel这个词的属性不对劲,应该用名词,于是又改了一版:

  1. V0.5: POST /newbiz/{userId}/query-unaudited-unapproved-newbiz-cancellations

丹娜有所警觉:“比刚才的要好,但是这个可能会改变主体,比如被解读成 query-unaudited-unapproved-newbiz-cancel,其实我们是想表达query-unaudited-unapproved-newbiz-cancel。”

袁帅:“嗯… 有道理!”

丹娜快速补充道:“query-unaudited-cancellations-of-unapproved-newbiz”,袁帅和华仔点头认可。URL摇身一变:

  1. V0.6: POST /newbiz/{userId}/query-unaudited-cancellations-of-unapproved-policy

正当要竣工时,袁帅的头脑活跃起来:“我理解,最前头的/newbiz咱们内部的规范,只是为了区分这是新契约模块下的API,那么在新契约模块下未审批的投保单现在的业务术语叫什么?”

丹娜和华仔同声回应:“policy

华仔这次自作主张把URL调整了:

  1. V0.7: POST /newbiz/{userId}/query-unaudited-cancellations-of-unapproved-policy

“等等,我刚才快速看了一下系统,未审批的承保单叫这个比较合适:uninsured-policy。”丹娜话音刚落,华仔就调整好了URL:

  1. V0.8: POST /newbiz/{userId}/query-unaudited-cancellations-of-uninsured-policy

丹娜:“这里是一个数据查询,使用了POST动作,我理解是因为查询参数过多,使用GET不方便。之前教练讲过一种资源抽象方式,当查询参数非常多的时候,可以使用POST请求,抽象成创建一个查询的资源,这样就更靠近RESTful风格提倡的形式。”

华仔听完有点迷茫,只见丹娜示意华仔把键盘给她,修改了一版:

  1. V0.9: POST /newbiz/{userId}/unaudited-cancellations-of-uninsured-policy-queries

“既然是根据诸多查询条件来查询一个数据列表,那这个userId其实也完全可以当做一个查询参数,放入到Request Body中。”丹娜边思考边敲着键盘:

  1. V1.0: POST /newbiz/unaudited-cancellations-of-uninsured-policy-queries

袁帅:“赞啊,要是看成资源的话,撤件cancellation是不是可以看成一个资源,属于承保单policy的子资源呢?”

丹娜直接在华仔的电脑上打开代码库搜索到了撤件确实在现在系统有独立的实体。“对的,这样子我们的URL就更优雅了”,随即她调整了URL:

  1. V1.1: POST /newbiz/uninsured-policies/unaudited-cancellations-queries

“新契约模块处理的承保单是不是就代表未审批的?” 袁帅的问题没完没了。

“是的,那这样子uninsured-policies就可以是policies,太好了,又能瘦一些!” 华仔这次快速捕获到了关键信息并做出调整:

  1. V1.2: POST /newbiz/policies/unaudited-cancellations-queries

回顾总结

文字书写下来看起来有些冗长,其实整个过程不到10分钟。看完这个过程,不知道你是否捕获到我想表达的三个点(稍作闭目养神,想想哪三个点后再往下看):

  1. 命名很重要!
  2. 命名贴近业务更重要!
  3. 做到以上两点特别重要!

虽整洁代码的书有很多本,可我一直觉得整洁代码是一件很朴实无华的事情,一个程序员能把名字起好就已经很了不起。可能你已经看到整个过程,一定的英语基础能够事半功倍,再者好用的汉英词典和翻译助手也应该是程序员的手边工具。

文章啰嗦那么多,如果你能带走两个点,我愿意它们是:

  1. 实用的工具是提升个人效率的帮手,要勤用。
  2. 必要的社交是提升团队认知的活动,要勤做。

如果只能带走一点,我更愿意是:保持对命名的琢磨,琢磨表达业务的名字。

命名“典故”

这么多年,每当碰到软件命名问题时,在我脑海里就会浮现出多年前我在Thoughtworks一个下午的10分钟,恰巧也是“一毛钱”:2个10多年 + 1个近10年 经验的Senior Tech Lead带我花了近10分钟琢磨一个方法的命名。

image.png

附加说明

软件设计通常没有标准答案,即没有对错之分,只有当前上下文下的合适与不合适,一个方案的好与不好也是基于现实资源和约束的权衡。

抛开实际上下文,单方面追求完美的设计,非常适合练功,比如RESTFul风格的API命名其实是有改进空间的,这个任务留给有兴趣的你,欢迎留言!