一篇短文谈下我对编程中「起名字」这个事的看法和感悟。
一句话总结:用词要达意、保持一致性 和 整体的简洁性。
展开来说有 7 点:
用词讲究表意准确、言简意赅
对程序描述的事物理解越深刻,命名就越凝练、越精准。
一个例子是
fork
函数,意为 “分叉”,既简洁又准确 (fork man page)。再比如,冒泡排序
BubbleSort
、堆的上浮Swim
和 下沉Sink
过程的命名都很形象。命名要「名副其实」,不可诱人误解。 比如 C++ 中的 std::exchange 函数, 看名字似有交换之意,实际并不然 💔。
名字风格应符合社区惯例、项目约定
几乎每个编程语言都有官方的、或社区流行的命名风格约定, 例如:Python PEP8、 Effective Go 和 Google C++ Style Guide 等。
用何种风格有时众口难调,但是 风格统一比风格本身的美丑更重要。
约定俗成的名字更胜一筹
计算机是有历史的,就会有其独特的用词意境。比如,迭代变量
i
和j
, 交换函数通常叫swap
, 哈希hash
(why?) 等。在一个编程语言内,也有其约定俗称的用词。比如,对于 Go 语言,经常用
b
表示Buffer
,r
表示Reader
,w
表示Writer
等。保持命名的一致性很重要,同一事物尽量用相似的名字。
比如,在一个项目内,如果大多代码都用
conn
来表示Connection
实例,新代码就要避免另造新词。 如果你有多个连接实例要起名字,可以用conn1, conn2
或者conn_sever1, conn_server2
之类的名字来区分, 这样它们仍然是相似的。简写的短名字有时更直观,比如常用的
max, min, pow, abs, eof
等。 具体项目中,可以对高频概念发明一些短名字, 比如用msg
来表示消息Message
,用o
来表示订单Order
, 用w
来表示仓库Warehouse
, 标品standard_product
可以叫sp
等。放到项目所处的业务环境中看,这些短名字并不会晦涩难懂, 并进一步成为「约定俗成」。在表意清晰的情况下,我更偏好短的名字。 比如说,
acquire
比take_ownership
更好。对象的用途不同、名字形式不同
我总结了几点,并非绝对,权供参考:
函数用动词,形如
Do()
或者DoSomething()
func Write([]byte) int {} func MakeOrder(req MakeOrderRequest) MakeOrderResponse {} func ReadFrom(r Reader) (n int, e error){}
类、对象、变量、结构体等用名词, 且区分单复数:
type Buffer struct {} buf := &Buffer{} // 单数 parts := strings.Split(",") // 复数
布尔值和判断函数,命名以
is/has/should/contains/check
等开头 (is
最常用):var isExist bool func IsUserLogin() bool {} func HasPrefix() bool {}
此条并不绝对,只要用词有「是否」之意即可,比如
found
:func Contains(s, part string) (found bool)
只做数据增删改查的函数,考虑用
Get/Set/Query/List/Update/Delete
等字眼:GetValue() // 查询单个 SetValue() // 设置单个 QueryValues() // 查询多个值 ListValues() // 列出多个值 UpdateValue() // 更新单个值 DeleteValue() // 删除单个值
注意动词的时态:
Status.Moving // 移动中 Status.Paid // 已支付 order.CreatedAt // 下单时间
不必要在名字中携带类型信息
大多数情况,不必要透出对象的类型信息,因为上下文环境,阅读代码的人很容易知道其类型:
// bad counter_integer := 0 content_string := "abcdefg" Encode(dst_bytes, src_bytes []byte) Trim(str string, prefix_str string) // better counter := 0 content := "abcdefg" Encode(dst, src []byte) Trim(s, prefix string)
相比而言,名字中的业务和功能信息,更为重要。
简洁的好名字留给高频场景
举例说,现在有两种映射表,一种是有序的、一种是无序的。现在有三个名字:
ordered_map
,unordered_map
和map
。如何从中选出两个名字 ?就这个问题而言,无序表的使用场景更多,所以我偏向于这样起名字:
ordered_map
给有序表map
给无序表
有趣的是,在 C++ 中,可能由于历史原因, 命名方式是完全与此相反的,
map
是基于红黑树的有序表,unordered_map
是无序的哈希表, 但是显然无序表更常用 💔。关注整体的简洁性
局部变量、尤其临时变量、高频使用的变量,尽量采用简短的名字,会有助于整体的简洁性。
其实就是,排版会更整洁,更容易整体阅读。
对比下面的两对代码片段,你更喜欢左边的、还是右边的呢?
我是比较喜欢右边,整体排版更简洁。
Golang 是推崇短名字的,一些链接:
关于命名,就谈到这里,欢迎评论区交流。
(完)
相关阅读: 浅谈编程中的打日志(短文)
本文原始链接地址: https://writings.sh/post/naming