代码就是程序员的孩子,给“孩子”取个好听的名字很重要!
我们在项目开发中,接触到的变量、函数、类多数都是项目自己定义的,往往都是为了解决一些特定的领域的问题,引入了各种各样的概念,代码里面的名字 就对应着问题领域或方案领域的这些概念,所以,对于一个命名良好,代码规范,设计简洁的系统,要想非常快的理解一个系统,最直接的方式就是 RTFC(Read The Fucking Code)。对于一个不断演进的系统,代码的可读性至关重要,首要要解决的问题就是名字,变量名、函数名、类名等都需要仔细斟酌,认真对待,一个能够简 洁,能够清晰表达概念和意图的名字就显得尤为重要。
阅读《代码整洁之道》这本书后发现其中说的内容在我们自己项目中比比皆是,随便拿出一块代码都可以当做反面教材给大家讲半天。长时间积累,导致代码 发霉变质,取名也是毫无章法,信手拈来。阅读这样的代码,撞南墙的心都有了。下面结合自己项目中的问题和《代码整洁之道》谈谈关于命名相关的原则。
1. 原则:名副其实
- 选名字是件严肃的事情,选个好名字很重要。
- 如果名字需要注释来补充,那就不是个好名字。
- 最重要的是要名副其实,名字能表达出概念和意图。
BAD:
int t = currentTime.elapse(e); // 消逝的时间,以毫秒计 ... if (t > timeout_value) { Zebra::logger->debug("---一次循环用时 %u 毫秒-----", t); }
GOOD:
int elapsed_ms = currentTime.elapse(e); ... if (elapsed_ms > timeout_value) { Zebra::logger->debug("-----一次循环用时 %u 毫秒---", elapsed_ms); }
2. 原则:避免误导
- 必须避免留下掩藏代码本意的错误线索
- 避免使用与本意相悖的词
- 提防使用不同之处较小的名称
- 拼写前后不一致就是误导
BAD:
std::vector<int> account_list; // _list就是一个误导, accounts会更好 bool sendToZoneServer(); // 和下面的函数差别很小 bool sendToZoneServers(); // sendToAllZoneServers会好点
3. 原则:做有意义的区分
- 代码是写给人看的,仅仅是满足编译器的要求,就会引起混乱
- 以数字系列命名(a1,a2,...),纯属误导
- 无意义的废话: a, an, the, Info, Data
BAD:
void copy(char a1[], char a2[]) { for (size_t i = 0; a1[i] != '\0'; i++) a2[i] = a1[i]; }
GOOD:
void copy(char source[], char dest[]) { for (size_t i = 0; source[i] != '\0'; i++) dest[i] = source[i]; }
4. 原则:使用可读的名字
- 避免过度使用缩写
- 可读的名字交流方便
猜一猜下面的类是干什么的?和别人怎么说这几个类?
根据这些简直变态的缩写,如果没有注释基本上很难知道是干什么的,当你和别人交流的时候,你就不得不一个一个字母来念“X-L-Q-Y”、“L- T-Q Manager”,鬼知道你说的是什么?PS. XLQY-XianLvQiYuan(仙履奇缘), LTQ-LiaoTianQun(聊天群),有这样的名字也是醉了。
BAD:
class XLQY; class FCNV; class LTQManager;
5. 原则:使用可搜索的名字
- 避免使用Magic Number
- 避免使用单字母,或出现频率极高的短字母组合(注意度的把握)
BAD:
if (obj->base->id == 4661) // 4661是啥玩意? { usetype = Cmd::XXXXXXX; } int e; // 怎么查找? XXXX:iterator it; // 变量作用的范围比较大的时候,也不见得是个好名字
GOOD:
#define OJBECT_FEEDBACK_CARD 4661 if (OJBECT_FEEDBACK_CARD == obj->base->id) { usetype = Cmd::XXXXXXX; }
6. 原则:避免使用编码"
- 匈牙利标记法:
- Windows API时代留下的玩意
- 形如:
wdXX, dwXXX, strXXX
- 类型变换导致名不副实,就有可能出现明明是个
DWORD
,变量名却是qwNum
。
PS.匈牙利命名对于我们这些在Linux下摸爬滚打的好多年的来说,看着真心别扭。
- 成员前缀:
- 形如:
m_name, m_xxx
- 基本上都无视,为何要多次一举
- 形如:
PS.说到这一点,可能有些同学有不同意见了,“我这样写是为了区分成员变量和临时变量啊!”,好像这样写也没什么大不了,遵循代码规范即可。如Google的C++代码规范,私有变量形如:xxx_
,加后缀_
,其目的除了让你知道这货是个私有变量,还有一点就是防止有些人图省事把带私有变量直接public掉,因为谁也不喜欢在代码里面看到大量这些带把的玩意。
- 接口和实现:
- 接口名形如:IXXX, I-接口修饰前缀
- 类名形如:CXXX, C-类修饰前缀
- 这些修饰多数时候都是废话
7. 原则:名字尽量来自解决方案领域或问题领域
- 使用解决方案领域名称:
写代码的同学多数都是都出自CS,术语、算法名、模式名、数学术语尽管用。如AccountVisitor:Visitor模式实现的Account类。
- 使用问题领域的名称
我们代码里面多数都是这些名称,不明白找策划问问,基本上都是功能相关的名称。
8. 原则:适当使用有意义的语境
- 良好命名的类、函数、名称空间来放置名称,给读者提供语境
- 只有两三个变量,给名称前加前缀
- 事不过三,变量超过三个考虑封装成概念,添加struct或class
BAD:
// 看着整齐?使用方便? DWORD love_ensure_type_; //当前的爱情保险类型 DWORD love_ensure_ret_; //购买爱情保险回应标示 DWORD love_ensure_total_; //现在已经盖章数目 DWORD love_ensure_..._; //... DWORD love_ensure_..._; //...
最后:我们的C++命名规范
- 文件名:
- 首字母大写,多个词组合起来
- 如:
SceneUser.h Sept.h
- 类名/名称空间名:
- 首字母大写,多个词组合起来
- 使用名词或名词词组
- 避免使用C前缀,如:
CSept
- 如:
SceneUser SeptWar
- 函数名:
- 首字母小写
- 使用动词或动词词组
- 避免使用孤立的全局函数,可以封装在类或名称空间里面
- get, set, is前缀的使用
- 如:
fuckYou(), levelup()
- 变量名:
- 全部字母小写,多个词以下划线分隔
- 私有成员变量加后缀
_
,公有变量不用 - 避免使用孤立的全局变量,可以封装在类或名称空间里面
- 如:
quest_id, questid_
取名是一件严肃的事情,我们需要认真对待,名字代表着一个个概念,名字代表着你想表达的意图,好名字是可读代码的首要条件:
- 写下任何一行代码的时候,心里都要想着自己的代码是给别人看的。
- 为函数、变量、类取个好名字,遵循规范和原则。
- 见到不符合规范和原则的名字,确毫不留情的干掉它,特别是功能性的代码。
原文:http://game-lab.org/posts/zoc-cleancode-2/
相关推荐
刚安装好的MySql包含一个含空密码的root帐户和一个匿名帐户,这是很大的安全隐患,对于一些重要的应用我们应将安全性尽可能提高,在这里应把匿名帐户删除、 root帐户设置密码,可用如下命令进行: use mysql; delete...
换言之,很可能数个使用者在执行某个 Stateless Session Bean 的 methods 时,会是同一个 Bean 的 Instance 在执行。从内存方面来看, Stateful Session Bean 与 Stateless Session Bean 比较, Stateful Session ...
【强制】所有的MySQL数据库除历史原因外,都必须采用UTF8编码 【建议】一个表的某列与另一表有关联关系的时候, 请在应用程序维护外键关系,如果在数据库建立外键约束请遵循以下几点: 尽量少使用外键,在高并发下...
刚安装好的MySql包含一个含空密码的root帐户和一个匿名帐户,这是很大的安全隐患,对于一些重要的应用我们应将安全性尽可能提高,在这里应把匿名帐户删除、root帐户设置密码,可用如下命令进行: use mysql; ...
如果需要生成一个大的、稀疏的集,那么显式罗列就很讨厌。幸运地是许多稀疏集的成员都满足一些条件以和非成员相区分。我们可以把这些逻辑条件看作过滤器,在LINGO生成派生集的成员时把使逻辑条件为假的成员从稠密...
换言之,很可能数个使用者在执行某个 Stateless Session Bean 的 methods 时,会是同一个 Bean 的 Instance 在执行。从内存方面来看, Stateful Session Bean 与 Stateless Session Bean 比较, Stateful Session ...
arp 查看和处理ARP缓存,ARP是名字解析的意思,负责把一个IP解析成一个物理性的MAC地址。arp -a将显示出全部信息 start 程序名或命令 /max 或/min 新开一个新窗口并最大化(最小化)运行某程序或命令 mem 查看cpu...
不错的PDF电子书,共3个分卷,点我名字可以找全 第1部分 逆向101 第1章 基础 3 1.1 什么是逆向工程 3 1.2 软件逆向工程:逆向 4 1.3 逆向应用 4 1.3.1 与安全相关的逆向 5 1.3.2 软件开发中的逆向 8 1.4 底层软件 9...
RAR 是一个让你在命令行模式中管理压缩文件的控制台应用。RAR 提供压缩、加 密、数据恢复和许多其它此手册中描述的其它功能。 RAR 只支持 RAR 格式压缩文件,它默认有 .rar 扩展名。不支持ZIP 和其他格 式。即使...
这个项目可指定让AGP装置来使用的系统内存大小,这取用大小是PCI内存地址范围的一部份,可分配给图形内存的空间。 Init Display First: 这个项目可选择当系统开机时先行对AGP或是PCI插槽来做初始化的动作。 [AGP...
数据库设计 数据库设计 1 第 1 部分 - 设计数据库之前 3 第 2 部分 - 设计数据库表 3 第...如果表的名字由 3 个单词组成,你不妨从头两个单词中 各取一个然后从最后一个单词中再取出两个字母,结果还是组成 4 字 母长的
下面的138道题目,在二级考试中命中率极高。 一、选择题 (1) 下面叙述正确的是(C) A. 算法的执行效率与数据的存储结构无关 B. 算法的空间复杂度是指算法程序中指令(或语句)的条数 C. 算法的有穷性是指算法必须能...
6.17 有个很好的窍门,如果我这样写:intrealarray[10];int*array=&realarray[-1];我就可以把“array”当作下标从1 开始的数组。 函数和多维数组 6.18 当我向一个接受指针的指针的函数传入二维数组的时候,...
5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...
5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...