层楼

Write codes that work and speak

0%

【译】代码中的命名

译自:Naming Things in Code

引言

当我在设计软件时,我会花很多时间去考虑命名。对我而言,命名是设计过程中重要的一部分。命名就是在定义。

In the beginning was the Word, and the Word was with God, and the Word was God.
—— 约翰福音

我知道设计到位的一种感受,就是命名正确了。这可能需要一些时间(我在刚开始命名时往往会反复),但没关系,良好的设计需要付出。

当然,好的命名并不代表好的设计,但是糟糕的命名绝对会毁了一个好的设计。基于此,下面我分享了我在命名时的一些准则。虽然示例是C++的,但是对面向对象的语言或多或少有点参考价值。

类型(class,interface,struct)

名称应该是一个名词短语。

1
2
Bad:  Happy
Good: Happiness

不要使用命名空间的前缀,因为这是命名空间的作用。

1
2
Bad:  SystemOnlineMessage
Good: System::Online::Message

使用恰如其分的形容词来明确含义。

1
2
Bad:  IAbstractFactoryPatternBase
Good: IFactory

不要在类型名称中使用”Manger”、”Helper”这种无意义的单词。如果一种类型有这种词,要么是命名失败要么是设计失败。类型应该是不言自明的。

1
2
3
4
Bad:  ConnectionManager
XmlHelper
Good: Connection
XmlDocument, XmlNode, etc.

如果一个类不代表具体的东西,考虑使用隐喻。

1
2
3
4
5
6
Bad:  IncomingMessageQueue
CharacterArray
SpatialOrganizer
Good: Mailbox
String
Map

如果使用隐喻,请一以贯之。

1
2
Bad:  Mailbox, DestinationID
Good: Mailbox, Address

函数(function,procedure)

简单明了。

1
2
Bad:  list.GetNumberOfItems();
Good: list.Count();

别过于简洁。

1
2
Bad:  list.Verify();
Good: list.ContainsNull();

缩写正确。

1
2
Bad:  list.Srt();
Good: list.Sort();

用动词命名执行操作的函数。

1
2
3
4
Bad:  obj.RefCount();
Good: list.Clear();
list.Sort();
obj.AddReference();

像问问题一样命名返回布尔值的函数。

1
2
3
Bad:  list.Empty();
Good: list.IsEmpty();
list.Contains(item);

用名词命名只返回值不改变状态的函数。

1
2
Bad:  list.GetCount();
Good: list.Count(); (C#中应该用properties)

不要让名称与参数重复。

1
2
3
4
Bad:  list.AddItem(item);
handler.ReceiveMessage(msg);
Good: list.Add(item);
handler.Receive(msg);

不要让名称和执行的对象重复。
Don’t make the name redundant with the receiver.

1
2
Bad:  list.AddToList(item);
Good: list.Add(item);

只有在返回值类型有多种重载时才强调它。

1
2
3
4
Bad:  list.GetCountInt();
Good: list.GetCount();
message.GetIntValue();
message.GetFloatValue();

不要在命名里使用“and”和“or”。如果一个名称中有连词,该函数可能承担了过多的职责,不妨将其拆解开来并分别命名。考虑给一个函数或类进行命名,可以帮你思考这是否是一个原则操作。

1
2
3
Bad:  mail.VerifyAddressAndSendStatus();
Good: mail.VerifyAddress();
mail.SendStatus();

这重要吗?

对我来说,这个问题的答案显而易见。一个命名良好的模块很快就能告诉你它的作用,仅仅阅读一小部分,你就能快速构建起对整个系统的认知模型。如果系统中有“MailBox”,即使你不读代码,你也会期望看到“Mail”、“Addresses”这种概念。

命名良好的代码可以帮助你更好地和其他同事沟通,这有助于代码知识的传播。没有人想在沟通的时候一直重复类似 “ISrvMgrInstanceDescriptorFactory” 这种名字。

另一方面,糟糕的命名就像给你加了一堵空气墙,强迫你努力在脑海里运行这些代码,思考它的目的,然后转化到你自己的话语体系下。“哦,DoCheck()看起来是在遍历检查connection是否都live着,那我不如叫它AreConnectionsLive()”,整个过程缓慢并且没办法共享。

从我看过的代码来看,模块内命名的一致性和模块的一致性往往是相辅相成的。当我感觉命名很难时,很有可能是这个东西本身设计就有问题,可能是违背了单一职责原则,或者是缺少了某些部分。

很难说我们的设计好或者坏,但是我很确信的一点就是当命名困难时,设计往往是错误的。现在我在设计时会尝试关注这一点,一旦我觉得命名不错,通常来说我对设计也比较满意。