前言
关于代码命名,我相信是经常困扰很多小伙伴的一个问题,尤其是对于强迫症晚期患者。怎么说呢,每次在写代码之前,总会在想啊想啊,用什么命名法好呢?对于经常在C++、Java、Python等主流语言上切换的强迫症来说,换个语言换种命名风格简直不要太混乱。规范的命名可以让你在代码调试的过程中快速的知道当前变量的功能和定义时的目的。而不需要在这个文件看到一个变量,又要赶紧翻到别的文件去看看这个变量定义来是干嘛的。
今天就来梳理一下常见的代码命名规范以及适用范围。
1 常见命名规范
为什么需要命名规范呢?世界级软件大师 Martin Fowler 大神都说过 CS 领域有两大最难的事情,一是缓存失效,一是程序命名。

《Clean Code》这本书明确指出:
代码的注释不是越详细越好。实际上好的代码本身就是注释,我们要尽量规范和美化自己的代码来减少不必要的注释。若编程语言足够有表达力,就不需要注释,尽量通过代码来阐述。
要想让你的编程语言足够有表达力,良好的命名规范是必不可少的。同时,花几分钟学学规范的命名,也能让你的代码看起来赏心悦目,何乐而不为呢。
1.1 驼峰命名法(CamelCase)
骆驼式命名法(Camel-Case)又称驼峰式命名法,是电脑程式编写时的一套命名规则(惯例)。正如它的名称CamelCase所表示的那样,是指混合使用大小写字母来构成变量和函数的名字。程序员们为了自己的代码能更容易的在同行之间交流,所以多采取统一的可读性比较好的命名方式。
它又可以分为以下几种。
1. 小驼峰命名法(lowerCamelCase)
除第一个单词之外,其他单词首字母大写。方法名、参数名、成员变量、局部变量需要使用小驼峰命名法(lowerCamelCase)。比如:
getUserInfo()
createCustomThreadPool()
findAllByUserName(String userName)
TaskRepository taskRepository;
2. 大驼峰命名法(CamelCase)
相比小驼峰法,大驼峰法(即帕斯卡命名法)把第一个单词的首字母也大写了。常用于类名,命名空间等。如:
class TaskDateToSend{}
class TaskLabelToSend{}
SettingRepository
1.2 蛇形命名法(snake_case)
蛇形法是全由小写字母和下划线组成,在两个单词之间用下滑线连接即可。测试方法名、常量、枚举名称需要使用蛇形命名法(snake_case)。如:
first_name
last_name
MAX_ITERATION
LAST_DATA
1.3 串式命名法(kebab-case)
在串式命名法中,各个单词之间通过下划线“-”连接,比如:
hello-world
first-project
建议项目文件夹名称使用串式命名法(kebab-case),比如 dubbo 项目的各个模块的命名是下面这样的:
2 语言场景
给出各个场景下的命名规则,大家要养成习惯。事实上,如果经常在各个语言上切换的话,真的可能搞混。所以今天就Mark一下吧。
2.1 Java命名规范
1. 总体命名规范
- 类名需要使用大驼峰命名法(UpperCamelCase)风格。
- 方法名、参数名、成员变量、局部变量需要使用小驼峰命名法(lowerCamelCase)。
- 测试方法名、常量、枚举名称需要使用蛇形命名法(snake_case) ,比如
test_get_user()
、TIME_LIMIT
。并且,测试方法名称要求全部小写,常量以及枚举名称需要全部大写。 - 项目文件夹名称使用串式命名法(kebab-case),比如
dubbo-registry
。 - 包名统一使用小写,尽量使用单个名词作为包名,各个单词通过 “.” 分隔符连接,并且各个单词必须为单数。
- 抽象类命名使用 Abstract 开头。如:
public abstract class AbstractClient extends AbstractEndpoint{}
。 - 异常类命名使用 Exception 结尾。如:
public class NoSuchMethodException extends RuntimeException{}
。 - 测试类命名以它要测试的类的名称开始,以 Test 结尾。如:
public class AnnotationUtilsTest{}
。
2. 包名命名规范
Java的包名由小写单词组成,包的路径符合所开发的系统模块的定义,以便通过包名可得知其属于哪个模块,从而方便到对应包里找相应的实现类。
3. 常规包名
为了保障每个Java Package命名的唯一性,在Java编程规范中要求开发人员在自己定义的包名前加上唯一的前缀。由于互联网上的域名称是不会重复的,所以多数开发人员采用自己公司在互联网上的域名称作为自己程序包的唯一前缀。例如:com.sun.swt...
- 公司项目 com:公司项目,copyright由项目发起的公司所有.。包名:
com.公司名.项目名.模块名..
- 团队项目 team:团队项目,指由团队发起,并由该团队开发的项目,copyright属于该团队所有。包名:
team.团队名.项目名.模块名..
4. 自定义包名
一般公司命名为com.公司名.项目名.模块名…那我们个人的项目又怎么命名呢?个人的英语单词有individual、personal、private、one-man,进一步对以上四个单词词意进行分析并在保证了唯一性,继而使用每个单词的前4个字母作为前缀,与com也做了区分。示例如下所示:
- indi:个体项目,指个人发起,但非自己独自完成的项目,可公开或私有项目,copyright主要属于发起者。包名:
indi.发起者名.项目名.模块名..
- pers:个人项目,指个人发起,独自完成,可分享的项目,copyright主要属于个人。包名:
pers.个人名.项目名.模块名..
- priv:私有项目,指个人发起,独自完成,非公开的私人使用的项目,copyright属于个人。包名:
priv.个人名.项目名.模块名..
- onem:与indi相同,推荐使用indi。
了解更多,请阅读:Java命名规范参考
2.2 Python命名规范
类:总是使用首字母大写单词串。如MyClass、ClassName。内部类可以使用额外的前导下划线。
函数和方法:小写+下划线,如method_name。
函数参数:小写+下划线,如function_parameter_name
。如果一个函数的参数名称和保留的关键字冲突,通常使用一个后缀下划线,如random_。
全局变量:对于from M import *
导入语句,如果想阻止导入模块内的全局变量可以使用旧有的规范,在全局变量上加一个前导的下划线,如_var_name。应避免使用全局变量。
变量:小写,由下划线连接各个单词。如color、this_is_a_variable。注意:
1. 不论是类成员变量还是全局变量,均不使用 m 或 g 前缀。
2. 私有类成员使用单一下划线前缀标识。
3. 变量名不应带有类型信息,因为Python是动态类型语言。如 iValue、names_list、dict_obj 等都是不好的命名。
常量:常量名所有字母大写,由下划线连接各个单词如MAX_OVERFLOW
,TOTAL
。
异常:以“Error”作为后缀。
文件名:全小写,可使用下划线
包:应该是简短的、小写的名字。如果下划线可以改善可读性可以加入,如mypackage。
模块:与包的规范同,如mymodule。
缩写:命名应当尽量使用全拼写的单词,缩写的情况有如下两种:
- 常用的缩写,如XML、ID等,在命名时也应只大写首字母,如XmlParser。
- 命名中含有长单词,对某个单词进行缩写。这时应使用约定成俗的缩写方式。例如:function 缩写为 fn text 缩写为 txt object 缩写为 obj count 缩写为 cnt number 缩写为 num,等。
前导后缀下划线:
- 一个前导下划线:表示非公有。
- 一个后缀下划线:避免关键字冲突。
- 两个前导下划线:当命名一个类属性引起名称冲突时使用。
- 两个前导和后缀下划线:“魔”(有特殊用图)对象或者属性,例如
__init__
或者__file__
。绝对不要创造这样的名字,而只是使用它们。注意:关于下划线的使用存在一些争议。
特定命名方式:主要是指 xxx 形式的系统保留字命名法。项目中也可以使用这种命名,它的意义在于这种形式的变量是只读的,这种形式的类成员函数尽量不要重载。如 class Base(object): def init(self, id, parent = None): self.id = id self.parent = parent def message(self, msgid):
其中 id、parent 和 message 都采用了系统保留字命名法。
Python推荐使用蛇形命名法,因为 Python 是蟒蛇啊,理所当然是用蛇形命名……
综合各方面考虑,驼峰式命名法比较好,优势明显,事实上,目前使用驼峰式命名法的人也真的越来越多了。
了解更多,请阅读:Python命名规则
2.3 C/C++命名规范
1. 命名通则
- 在所有命名中,都应使用标准的英文单词或缩写。不得使用拼音或拼音缩写,除非该名字描述的是中文特有的内容,如半角、全角, 声母、韵母等。
- 所有命名都应遵循望文知义原则,即名称应含义清晰、明确。
- 所有命名都不易过长,应控制在规定的最大长度以内。
- 所有命名都应尽量使用全称。
- 如果命名使用缩写,则应该使用《通用缩写表》中的缩写;原则上不推荐使用《通用缩写表》以外的缩写,如果使用,则必须对其进行注释和说明。
2. 具体规范
(1)工程名:不强制统一。
(2)文件名:
- 基于工程名,开头3个字母应表明与哪一个工程相关。
- 后面的字母应能够区别不同的功能。
- 不区分大小写。
- 长度不限于8.3格式,建议不多于30个字符。
- 若文件用于定义和实现类,建议文件名与类名保持一致。
(3)函数名:
- 参照 Windows API 的命名规范。
- 推荐使用动宾结构。函数名应清晰反映函数的功能、用途。
- 函数名最长不得超过30个字符。
- 函数名第一个字母必须大写。
- 全局函数必须以小写前缀"g"开头。
(4)变量名:
- 原则上,变量名的命名遵从匈牙利记法。即:前缀 + 类型 + 变量名
1)格式
[m_|s_|g_] type [class name|struct name] variable name
作用域前缀:作用域前缀标明一个变量的可见范围。作用域可以有如下几种:
前缀 | 说明 | 例子 |
无 | 局部变量 | |
m_ | 类的成员变量(member) | Int m_width |
ms_ | 类的静态成员变量(static member) | static int ms_initValue; |
s_ | 静态变量(static) | static int s_initValue; |
g_ | 外部全局变量(global) | int g_howManyPeople; |
sg_ | 静态全局变量(static global) | |
gg_ | 进程间共享的共享数据段全局变量(global global) |
说明:作用域前缀不同于下面的类型前缀,应该坚决执行。原因是:
1)变量作用域和链接性改变的情况是很少的,例如,很少的情况下会把一个成员变量改成静态变量
2)编程中使用的工具常常不会直观的显示变量的作用域和链接性
类型前缀:作用域前缀标明一个变量的可见范围。类型前缀标明一个变量的类型,有如下几种:
前缀 | 说明 | 例子 |
b | 布尔型变量(bool, BOOL) | bEnable |
ch | 字符型变量(char TCHAR) | chName |
lpsz | LPSTR、LPCSTR、LPCTSTR | lpszName |
n | 整型和位域变量(int, UINT,__int32,__int64) | nLength |
l | long | lOffset |
by | BYTE | |
w | WORD | wPos |
dw | DWORD | dwRange |
f | 浮点型变量(float) | |
d | double | |
p | 指针型变量和迭代子(pointer) | pDoc |
lp | 远指针 | |
e | 枚举型变量(enumeration) | |
pfn | 特别针对指向函数的指针变量和函数对象指针(pointer of function) | |
g | 数组(grid) | |
h | handle Windows对象句柄 | hWnd |
(5)类名:
- 必须以大写"C"开头,后面字母反映具体含义,以清晰表达类的用途和功能为原则。
- 接口必须以大写"I"开头,代表 Interface 。
- 当名称由多个单词构成时,每一个单词的第一个字母必须大写。
(6)结构体名、宏名、枚举名、联合名:
- 全部大写。
- 枚举名加小写前缀"enum"。
例:
typedef enum _CFILE_OPEN_MODE
{
enumOPEN_READONLY = 0,
enumOPEN_READWRITE = 1,
enumCREATE_ALWAY = 3
} CFILE_OPEN_MODE;
//·宏名加小写前缀"def"。
例:
#define defMAXNUMBER 100
- 结构名加小写前缀"tag",之后必须以大写"C"开头。
例:
typedef struct tagKPOINT
{
int x;
int y;
} KPOINT;
//·联合名加小写前缀"uni"。
例:
typedef union _VARIANT{
char unichVal;
int uninVal;
long unilVal;
float uniftVal;
...
} VARIANT;
了解更多,请阅读:C/C++代码规范
补充:
命名易读性规范
-
为了能让命名更加易懂和易读,尽量不要缩写/简写单词,除非这些单词已经被公认可以被这样缩写/简写。比如
CustomThreadFactory
不可以被写成。CustomTF
-
命名不像函数一样要尽量追求短,可读性强的名字优先于简短的名字,虽然可读性强的名字会比较长一点。
-
避免无意义的命名,你起的每一个名字都要能表明意思。
正例:UserService userService
; int userCount
;
反例: UserService service
int count
-
避免命名过长(50 个字符以内最好),过长的命名难以阅读并且丑陋。
-
不要使用拼音,更不要使用中文。 注意:像 alibaba 、wuhan、taobao 这种国际通用名词可以当做英文来看待。
正例:discount
反例:dazhe
最后,大家是在命名有困难可以上一个神奇的网站:https://unbug.github.io/codelf/
参考
- 聊聊编程命名规范:https://blog.csdn.net/qq_34337272/article/details/106673833
- Java命名规范参考:https://www.cnblogs.com/liqiangchn/p/12000361.html
- Python 为什么推荐蛇形命名法?:https://www.cnblogs.com/pythonista/p/13155167.html
- C++命名规则:https://www.jianshu.com/p/bb160b0f8a14
- C++命名规范:https://zhuanlan.zhihu.com/p/377183341
- 每个程序员需掌握的20个代码命名小贴士:https://blog.csdn.net/lz201234/article/details/44774647