There are only two hard things in Computer Science: cache invalidation and naming things. — Phil Karlton
写这篇文章的起因也是前面刚把自己byetbase.com前端代码里用New/new的地方都改成了Create/create。至于具体修改的原因放在最后说,先聊聊命名这个话题。
从刚学习编程时接触的匈牙利命名法到现在写Golang的短命名法,命名作为编程界两大难题之一,始终是让我头疼的问题。写bytebase.com的过程中,最消耗脑力的是如何建模(需要设计哪几个模型分别干哪几件事情)。而在建模的过程中,给这几个模型分别起什么名字又是其中相当消耗精力的部分:
- 有时候模型拆对了,但起的名字有问题,基本也算是失败(想想是不是都碰到过分别不清男女厕所标志的经历?)。
- 有时候模型拆完了,名字总是想不出舒服的,也挺有可能是建模本身有问题。
业界的例子
PostgreSQL: The single worst mistake ever made (链接)
Kubernetes: Pluralizing rest resource names in APIs is a mistake (链接) [1]
项目管理软件的例子
项目管理软件里最基础的概念是一条需要完成的事项,这个概念无论在中文还是英文里都有许多的同义词,相应的在国内外项管软件里,这个概念也有几种不一样的表达:
- 国内软件里常见的有,工作项/任务/问题/工单
- 国外软件里常见的有,Issue/Task/Ticket/(Work) Item
如果要细细琢磨该选哪个的时候,还是一个有点复杂的问题。比如Issue是在国外比较占主流的选择,无论是GitLab, GitHub还是Jira都是用了这个术语。但Issue这个词也有一个明显的问题,就是这个词的翻译是「问题」,而不少事项只是一个todo,还谈不上是一个「问题」。从词义上来说,如果是做一个通用型项目管理软件,Task这个词更中性,适用面也就更广一些。但是Task也有一个不小的问题,就是项目管理软件里通常还会有一个流程引擎,而许多流程引擎里也有Task这个概念,就会产生混淆,所以我们接下来再看流程引擎的例子。
流程引擎的例子
因为bytebase.com也有一套流程引擎,未来也准备和其他CI/CD工具打通,所以我也研究了一下这些工具的模型。主流工具里,流程引擎的模型多为3层,也有4层的,大致是这么个对应关系:
顶层 | 顶层-1 | 顶层-2 | 顶层-3 | |
---|---|---|---|---|
GitHub | Workflow | N/A | Job | Step |
GitLab | Pipeline | Stage | Job | Step |
Octopus Deploy | Lifecycle | Phase + Task | N/A | Task |
Jenkins | Pipeline | Stage | Task/Step | N/A |
Tekton | Pipeline | N/A | Task | Step |
Spinnaker | Pipeline | Stage | Task | N/A |
我对于这些模型的理解也未必完全准确,但至少可以看出命名是一件很难的事情。这其中Google发起的Tekton项目还希望成为云原生CI/CD的标准,来统一整个模型和命名。但如果按照表里各大平台模型的比较,要达成统一还是挺有难度的。
从New到Create
其实想改这个也有一段时间了,最近开始逐步实现CRUD的后端代码,为了保证前后端代码的一致性,终于下手了。
综合来讲有这么几个原因促成了这次的改动:
- CRUD中C是代表Create,所以Create相比New更能保持所有代码文档的一致性。
- new在许多编程语言中是关键字,比如在vuejs模版里,如果组件参数是new的话,为了避免关键词冲突,代码就需要写成$props.new而不能直接写成new。
- new在英语里既能当动词,又能做形容词,有时也会用成名词,词义并不清晰。时态上也是,用createdObject可以清楚地表达这是创建完毕的Object,但是如果是newObject的话,则存在将要创建和已经创建间的二义性。
这个改动从代码层面看,我觉得是正向的。但也带来一个问题,因为我还是希望在界面上仍然保持用New而不是Create作为文案。因为New无论从字数还是音节上更加紧凑。不少服务商购还会购买xxx.new的顶级域名,作为新建的快捷入口,比如db.new就会跑到DataStax的注册界面。
写在最后
如何命名是一个经典的工程问题。有时候要根据约定俗成的规范,结合业务场景的输入,再夹杂一些个人的偏好,反复琢磨,才能想出一个内心笃定的名字。可能有人会觉得一个命名真的有那么重要么,或许开头的两个例子还不够说服力,那最后再说一个和new/create有关的故事,当年有人问Ken Thompson
What he would do differently if he were redesigning the UNIX system
Ken的回答
I’d spell creat with an e
这里的creat指的是libc中io子系统里创建文件的函数,是所有软件里都绕不开的执行路径。
当然也有人会说,那也只有像libc,PostgreSQL,Kubernetes这种系统的命名才重要吧。确实对于命名的洁癖程度因人而异,但毕竟现在连狗狗币都能上天,随便写个软件说不定也能一飞冲天呢。
[1] 针对Kubernetes的例子,网上看到的绝大多数资料都是推荐采用复数形式给REST资源命名。而我的观点和截图中作者是一致的,应该采用单数。英语单词复数的语法规则太复杂了,尤其对于英语非第一语言的人来说。有些单复数形式一致,也区别不出来到底是单还是多,还有些也不是单纯的加s。如果干脆都往单数形式后面加s后缀的话,又会造成拼写正确性和开发规范上的冲突,容易造成多人开发中的不一致。所以我的习惯是在REST这种不需要区别单复数的场景,统一使用单数形式,如果是代码中需要区分单复数的,复数表示统一在单数形式后面加上List后缀。