命名,顾名思义,就是对代码,即变量,类,等进行命名。
要想出一个简洁又准确的名字不是那么容易的。
正确的命名能帮你写出好的代码。如果不能为一个变量或者函数想出一个清晰又简洁的名字,那可能是你的代码有问题。那样的话,你就得考虑重写或者进行代码重构了。
有人说,有注释,其实,注释的目的是为了弥补代码自身在表达上的不足。
网摘
列举例子,说明什么是“不好的代码”,什么是“清楚的代码”
命名要能揭示意图
如何命名,在编程中这永远都是个老大难问题。有些程序员喜欢简化、缩短或加密名称,使得只有他们自己能懂。下面让我们看一些例子:
不好的代码:
1
2
3
4
5
|
int
d;
// 天数
int
ds;
int
dsm;
int
faid;
|
“d”可以表示任何东西。作者使用注释来表明他的意图,却没有选择用代码来表示。而“faid”很容易导致误解为ID。
清楚的代码:
1
2
3
4
|
int
elapsedTimeInDays;
int
daysSinceCreation;
int
daysSinceModification;
int
fileAgeInDays;
|
命名时避免含义引起误解的信息
错误的信息比没有信息更糟糕。有些程序员喜欢“隐藏”一些重要信息,有时候他们也会写出一些让人误解的代码。
不好的代码:
1
2
|
Customer[] customerList;
Table theTable;
|
变量“customerList”其实不是个list。它是一个普通的array(或客户集合)。除此之外,“theTable”是一个Table类型的对象(你可以用IDE容易的发现它的类型),“the”这个词是个不必要的干扰。
清楚的代码:
1
2
|
Customer[] customers;
Table customers;
|
命名要有合适的长度
在高级编程语言中,变量名的长度通常不太限制。变量名几乎可以任何长度。虽然如此,这也可能使代码变得闹心。
不好的代码:
1
2
|
var theCustomersListWithAllCustomersIncludedWithoutFilter;
var list;
|
好的名称应该只含有必要的词汇来表达一个概念。任何不必要的字词都会使名称变长、难于理解。名称越短越好,前提是能在上下文中表达完整的意思(下订单这个场景中,“customersInOrder” 要比 “list” 好)。
清楚的代码:
1
2
|
var allCustomers;
var customersInOrder;
|
命名时编码规范保持一致,让规范帮助理解代码
所有的编程技术(语言)都有自己的“风格”,叫做编码规范。程序员应该在写代码时遵循这些习惯,因为其他的程序员也知道这些,并按这种风格编写。下面我们看一个没有明显规范的不好的代码例子。下面的这段代码没有遵循很好的已知的“编码规范”(比如PascalCase, camelCase, Hungarian规范)。更糟糕的是,这有一个毫无意义的bool变量“change”。这是个动词(用来描述动作),但这里的bool值是来描述一个状态,所以,这里应该用一个形容词更合适。
不好的代码:
1
2
3
4
5
6
|
const
int
maxcount = 1
bool
change =
true
public
interface Repository
private
string NAME
public
class
personaddress
void
getallorders()
|
一段代码,只看它的一部分,你就应该直接明白它是什么类型,只需要看它的命名方法。
例如:你看到了“_name”,你就能知道它是个私有变量。你应该在任何地方都利用这种表示方法,没有例外情况。
清楚的代码:
1
2
3
4
5
6
|
const
int
MAXCOUNT = 1
bool
isChanged =
true
public
interface IRepository
private
string _name
public
class
PersonAddress
void
GetAllOrders()
|
命名时相同的概念用相同的词表达
定义概念很难。在软件开发过程中,很多时间都花在分析业务场景、思考正确的定义里面所有的元素。这些概念永远都是让程序员头痛的事。
不好的代码:
1
2
3
4
5
6
7
|
//1.
void
LoadSingleData()
void
FetchDataFiltered()
Void GetAllData()
//2.
void
SetDataToView();
void
SetObjectValue(
int
value)
|
首先:
代码的作者试图表达“get the data”的概念,他使用了多个词“load”,“getch”,“get”。一个概念只用一个词表达就行了(在同一个场景中)。
第二:
“set”这个词用在了2个概念里:第一是“data loading to view”,第二个是“setting a value of object”。这是两个不同的概念,你应该使用不同的词。
清楚的代码:
1
2
3
4
5
6
7
|
//1.
void
GetSingleData()
void
GetDataFiltered()
Void GetAllData()
//2.
void
LoadDataToView();
void
SetObjectValue(
int
value)
|
命名时使用跟业务领域相关的词
程序员写的所有代码都是跟业务领域场景逻辑相连的。为了让所有关系到这个问题的人都能更好的理解,程序中应该使用在领域环境中有意义的名称。
不好的代码:
1
2
3
4
5
|
public
class
EntitiesRelation
{
Entity o1;
Entity o2;
}
|
当在编写针对某个领域的代码时,你应该始终考虑使用领域有联系的名称。在将来,当另外一个人(不仅是程序员,也许是测试人员)接触你的代码时,他能轻松的理解这个业务领域里你的代码是什么意思(不需要业务逻辑知识)。你首先考虑的应该是业务问题,之后才是如何解决。
清楚的代码:
1
2
3
4
5
|
public
class
ProductWithCategory
{
Entity product;
Entity category;
}
|
命名时使用在特定环境里有意义的词
代码里名称都有自己的上下文。上下文对于理解一个名称非常重要,因为它能提供额外的信息。让我们来看看一个典型的“地址”上下文:
不好的代码:
1
2
3
|
string addressCity;
string addressHomeNumber;
string addressPostCode;
|
在大多数情况中,“Post Code”通常是地址的一部分,很显然,邮政编码不能单独使用(除非你是在开发一个专门处理邮编的应用)。所以,没有必要在“PostCode”的前面加上“address”。更重要的,所以的这些信息都有一个上下文容环境,一个命名空间,一个类。
在面向对象编程中,这里应该用一个“Address”类来表达这个地址信息。
清楚的代码:
1
2
3
4
5
6
|
class
Address
{
string city;
string homeNumber;
string postCode;
}
|
命名方法总结
概述起来,做为一个程序员,你应该:
1、在每个代码范围内使用足够短和足够长的名称:例如循环计算器用一个字符就可以了,如i;条件和循环变量用一个单词,方法名1-2个单词,类名2-3个单词,全局变量3-4个单词组成
2、为变量指定一些专门名称,不要使用例如 “value”, “equals”, “data” 这样的变量名
3、变量名要使用有意义的名称,通过变量名能大概反映出其具体的用途
4、不要在变量名前加前缀,例如 o_, obj_, m_ 之类
5、服从公司命名规范,在命名时使用一致的做法,例如:txtUserName、lblUserName、cmbSchoolType, … 除非是大大降低了可读性
6、服从编程语言本身的规范,不要使用不连贯的小写和大写混合名称,例如:userName、 UserName、 USER_NAME、m_userName、 username, …
▲对 Java 而言:
▲类名使用驼峰命名方式,如:VelocityResponseWriter
▲包名小写:com.jobbole.project.ui
▲变量名小写开始的驼峰命名,例如:studentParentName
▲常量名用全大写:MAX_PARAMETER_COUNT = 100
▲枚举类名参考普通类名,枚举变量使用全大写
▲不使用任何带下划线的命名方式,除非是常量或者是枚举值
7、不要在同一个类的不同上下文中重用相同的变量名
8、不要在一个方法内用同一个变量做不同的用途
9、不要使用非 ASCII 字符的变量,例如中文变量
10、不要使用太长的变量名,例如50个字符,这很难阅读,而且可能超出一些编译器的限制
11、确定并坚持使用固定的一种自然语言的命名方式,例如不要使用拼音和英文混合的命名方式
12、方法名要使用有意义的名称,能通过方法名大概了解该方法的用途,而且方法名要以动词开始,例如createPasswordHash
13、方法名要符合公司统一的规范,例如:getTxtUserName(), getLblUserName(), isStudentApproved()
14、方法名要遵循编程语言规范
15、方法的参数名要使用有意义的名称
————————————————————————————————————————
一个软件最后都会落实到代码。而代码,其背后的架构设计或设计思想或模式固然重要,但我觉得更重要的东西则是良好的命名。混乱或错误的命名不仅让我们对代码难以理解,更糟糕的是,会误导我们的思维,导致对代码的理解完全错误。相反,良好的命名,则可以让我们的代码非常容易读懂,也能向读者正确表达事物以及逻辑的本质,从而使得代码的可维护性就大大增强,读命名好的文章是非常流畅的,会有一种享受的感觉。
另外一点也许大家还没感受到,那就是良好的命名,以及良好的命名习惯,由于我们总是对每个概念的名称要求非常苛刻,我们会思考这个名称所表达的概念是否正确,该名称是否正确表达了事物的本质或正确反映了某个行为的逻辑。所以,这种对命名的良好思考习惯,可以反过来帮助我们纠正之前的一些错误设计和代码实现;比如,你之前有一个地方可能命名不太准确,然后你发现后面有另一个地方需要用这个名字,且更合理。所以你会发现这个名字对前面的地方就不适合了,从而你会去思考前面的地方可能需要用其他的名字,或者你会发现前面的地方的设计根本就是有问题的。这种就是名字可以促使你思考你的设计是否正确的例子。
以上代码中,有很多问题,我们来一一分析:
从上面的代码我们可以知道,仅仅是通过这些细节,就能发现很多问题。我们写代码时,只要多细心点,多注意点排版是否美观一致、命名是否统一,那代码写出来就会漂亮很多了。下面我们再看看其他的代码:
上面这两个私有方法,一个是大写开头,一个是小写开头,不一致,混乱;应该要一致;
通过上面的一些例子,我们知道,在我们不经意间,多写了一个空格或者一个空行,或者一个字母的大小写不一致了,都会导致命名的不一致;如果自己没有养成这种平时注重代码命名各种一致性的习惯,那写出来的代码很可能就是像上面那样。我觉得是非常糟糕的。上面我举的例子都只是简单的命名方面的,更深层次的命名问题,比如如何做到名称和其背后的实现内容一致,这个是需要我们平时不断修炼的。不是短时间内就可以做到那个程度。
我觉得,要做好命名,归根结底:
养成良好的命名习惯不是为了别人,不是为了公司,而是为了提高自己的编程修养,提高自己认识事物的能力。