当前位置: 代码迷 >> 驱动开发 >> 分享小弟我对代码命名的一点思考和理解
  详细解决方案

分享小弟我对代码命名的一点思考和理解

热度:237   发布时间:2016-04-28 10:04:00.0
分享我对代码命名的一点思考和理解

一个软件最后都会落实到代码。而代码,其背后的架构设计或设计思想或模式固然重要,但我觉得更重要的东西则是良好的命名。混乱或错误的命名不仅让我们对代码难以理解,更糟糕的是,会误导我们的思维,导致对代码的理解完全错误。相反,良好的命名,则可以让我们的代码非常容易读懂,也能向读者正确表达事物以及逻辑的本质,从而使得代码的可维护性就大大增强,读命名好的文章是非常流畅的,会有一种享受的感觉。

另外一点也许大家还没感受到,那就是良好的命名,以及良好的命名习惯,由于我们总是对每个概念的名称要求非常苛刻,我们会思考这个名称所表达的概念是否正确,该名称是否正确表达了事物的本质或正确反映了某个行为的逻辑。所以,这种对命名的良好思考习惯,可以反过来帮助我们纠正之前的一些错误设计和代码实现;比如,你之前有一个地方可能命名不太准确,然后你发现后面有另一个地方需要用这个名字,且更合理。所以你会发现这个名字对前面的地方就不适合了,从而你会去思考前面的地方可能需要用其他的名字,或者你会发现前面的地方的设计根本就是有问题的。这种就是名字可以促使你思考你的设计是否正确的例子。

代码命名混乱或错误的主要原因:

  1. 没理解事物的本质;
  2. 理解了事物的本质,但不知道命名的重要性或者根本不屑于做好命名;
  3. 理解了事物的本质,也知道命名的重要性,但没能力命名好事物;

养成良好的命名习惯的一些想法:

  1. 对自己的严格自律,自己写代码时要有一种希望把每个名称都命名好的强烈意识和严格的自律意识;
  2. 要努力分析和思考当前被你命名的事物或逻辑的本质;这点非常关键,思考不深入,就会导致最后对这个事物的命名错误,因为你还没想清楚被你命名的事物是个什么东西;
  3. 在有自律意识和一定的分析能力基础之上,注意命名的方法技巧;要知道何时用动词,何时用名词;以及形容词放哪里,动词放哪里,名词放哪里;也就是小学时的主谓宾要会用;
  4. 你的任何一个属性的名字都要和其实际所代表的含义一致;你的任何一个方法所做的事情都要和该方法的名字的含义一致;
  5. 从代码的命名可以看出写代码的人编程时思路是否清晰,如果你对一个名字的命名不准确,很可能体现出你还没有理解这个名字背后的东西;
  6. 要让你的程序的每个相似的地方的命名风格总是一致的。不要一会儿大写,一会儿小写;一会儿全称一会儿简写;一会儿Pascal命名法,一会儿camel命名法或匈牙利命名法;
  7. 不要出现重复的命名;因为通常名称都有嵌套关系,比如类在命名空间里,方法在类里,所有如果一个概念在命名空间里表达了,那就不必再类上再表达一次;
  8. 对于属性或类名,应该总是名词在最后面,名词决定了这个属性代表什么,前面的部分都是用于修饰这个名词;比如,假如现在你有一个服务,然后又是一个关于订单的服务,那就可以命名为OrderService,这样命名就是告诉我们这是一个服务,然后是一个订单服务;再比如CancelOrderCommand,看到这个我们就知道这是一个Command,即命令,然后是什么命令呢?就是一个取消订单的命令,CancelOrder表示取消订单;
  9. 对于方法,应该总是动词开头,名词结尾;比如Order.AddItem(orderItem);这个,表示订单类有一个添加订单项的方法,Add是动词,表示添加,Item是名词表示订单项;
  10. 在C#中,我们一般用camel以及Pascal命名法,而不是匈牙利命名法。我觉得主要是两个原因:1)VS强大的智能感知提示的存在,我们没有必要突出变量的类型了,但这个我觉得只是一个次要原因;2)真正的原因,我上面有提到,一个变量,名词是放在最后的,这个名词决定了这个变量代表什么。比如有个变量叫totalCount,我们一看就知道这是一个count,然后count一定是一个int或者long,所以就不需要在强调它的类型了。再比如,remotingRequest, httpRequest,这种,我们也一看就知道他们是请求,一个是remoting的请求,一个是http的请求。remoting,http是用来修饰request的。request决定了这个变量是什么(同时就意味着我们知道了他的类型了),然后remoting,http这种是进一步说明该request的业务含义或当前上下文。就像disabledButton,我们一看就知道这是一个button,然后是一个什么Button呢,就是一个已禁用的button。所以,好的名称,本身就会让我们很容易知道该名称是什么东西,它的类型是什么,具有什么业务含义,所以没有必要再加类型缩写作为前缀;
  11. 多学习英文,多看国外优秀开源项目中的命名技巧,会对我们命名有很大帮助;

通过一些不太好的代码命名来分析一些简单的命名问题

以上代码中,有很多问题,我们来一一分析:

  1. 方法的参数,第一个字母,一会儿大写的P,一会儿小写的p,不一致;
  2. 第二个参数后面出现多余的空格,不应该;
  3. _paramsTable这个参数为什么要出现下划线,而其他参数没有下划线,不一致;
  4. publishRequest属于camel命名法,而iSignCounter, sStageIsOK这种属于另一种命名法,这种命名c++中用的多,不一致;
  5. foreach循环中,参数名叫instParam,但是后面的集合叫arrParams4SignActions,更对称一点的,应该叫arrInstParam;
  6. 方法的最后两行,出现多余的空格,导致代码格式排版混乱;

从上面的代码我们可以知道,仅仅是通过这些细节,就能发现很多问题。我们写代码时,只要多细心点,多注意点排版是否美观一致、命名是否统一,那代码写出来就会漂亮很多了。下面我们再看看其他的代码:

  1. 上面的代码中,两个参数的命名也不一致,projectid中,i是小写,但是publishId参数,i却是大写,应该都统一为大写;
  2. ViewData中的key,一会儿是全部大写的UPDATE,一会儿是另一种命名,不一致;
  3. 上面的两个红框标出来的if,虽然都是只有一行代码,但是一个有括号,一个没有括号,不一致;且第二个if里出现了多余的空行,格式混乱;

  1. 上面的代码中,函数中,一会儿用IList,是一个接口,一会儿用Dictionary,非接口,不一致;应该都用接口,或者都不用接口;
  2. listOriginal和receiverList命名不一致,要么全部list开头,要么全部List结尾;
  3. foreach循环中,变量的类型叫TDMSOriginalRequirement,但是变量名却叫originalItem,而集合名称又叫listOriginal,应该三者统一;比如foreach (Assembly assembly in assemblies)
  4. +“...”这个地方没有用空格,加号两边应该要空格,这属于格式混乱,不严谨;
  5. createUser这个变量取的很不理想,create是动词,createUser合起来就是创建用户的意思,而他这里要表达的意思是创建人的意思,所以应该叫createdUser或者creator;
  6. 为何originalItemFormat和originalItem的意思可以等价,不合理,如果等价,一开始就要命名为originalItemFormat;而且format是一个东西,动词放在最后,算个啥?

  1. 上面这个类的几个私有字段中,有些带命名空间,有些不带,要么都不带,要么都带;一般命名空间都是在上面声明,后续不需要出现;
  2. ILog logger;这一句有两个问题:1)logger为何没有下划线,不统一;2)为何类名叫ILog,而变量名叫logger,要统一,要么类名叫ILogger,要么变量名叫_log;

上面这两个私有方法,一个是大写开头,一个是小写开头,不一致,混乱;应该要一致;

总结

通过上面的一些例子,我们知道,在我们不经意间,多写了一个空格或者一个空行,或者一个字母的大小写不一致了,都会导致命名的不一致;如果自己没有养成这种平时注重代码命名各种一致性的习惯,那写出来的代码很可能就是像上面那样。我觉得是非常糟糕的。上面我举的例子都只是简单的命名方面的,更深层次的命名问题,比如如何做到名称和其背后的实现内容一致,这个是需要我们平时不断修炼的。不是短时间内就可以做到那个程度。

我觉得,要做好命名,归根结底:

  1. 先要意识到命名的重要性;
  2. 要端正态度,要认真的写代码;
  3. 要努力推敲每个名称和其实际做的事情是否一致,也就是命名的准确性;
  4. 要时刻注意命名的各种一致性;

养成良好的命名习惯不是为了别人,不是为了公司,而是为了提高自己的编程修养,提高自己认识事物的能力。

11楼_popc
这个, 感觉是比较汗颜, 大家都知道java语言臃肿,c#语言高效,所以有时就是因为这种高效的得意劲,太过于突出自我的瞎乱命名, 我原来是.net的, 前几家公司也有可能是小的缘故,大家命名是乱七八糟的,没有这种强烈意识和严格的自律意识,后来转到java后, 感觉java代码异常臃肿,但是现在这家公司对于命名可是专门的定期代码检查,所以感觉臃肿的代码写的规范、极致,即时业务逻辑复杂但阅读起来感觉也舒畅的多。
Re: netfocus
@_popc,引用这个, 感觉是比较汗颜, 大家都知道java语言臃肿,c#语言高效,所以有时就是因为这种高效的得意劲,太过于突出自我的瞎乱命名, 我原来是.net的, 前几家公司也有可能是小的缘故,大家命名是乱七八糟的,没有这种强烈意识和严格的自律意识,后来转到java后, 感觉java代码异常臃肿,但是现在这家公司对于命名可是专门的定期代码检查,所以感觉臃肿的代码写的规范、极致,即时业务逻辑复杂但阅读起来感觉也舒畅的多。,这个我觉得和团队有关系,和语言关系不大,呵呵。归根结底还是人的因素。
10楼draculav
汤哥,你总算是把这个发出来了,不过似乎不全呢,之前你说的什么时候用ing什么的,微软命名那些没有写...
Re: netfocus
@draculav,有很多忘了,哎。算了,就这样吧。呵呵
Re: 『大雪无痕』
@netfocus,楼主,你较真啦。,,——当然,解释一下 也好。
8楼指针为空
命名,不是什么难事,难的是让团队所有人,包括几次大范围人员变动后的命名规则依然一致。,,我曾经接手过一些在线上环境跑了将近10年的asp代码,10年,动过这个代码的程序员有几十个,里面早就乱成一锅粥了,但是因为一直在线上运行的核心代码,没有人敢去对它进行重构的
7楼缪军
对于需要手工编写的代码,我们只是提出书写建议,而不强制规范,,总体来说,程序员在通过测试前,要N次的修改代码,,为了尽快通过测试,获得更多的收益,他们会自然而然的采用更加有效的方法,团队尽可能扮演的是目标激励、过程指导和技术支持的角色
Re: ~CityHunter~
@netfocus,上面说到的是名词开头或者动词开头,指的是AddItem或者ItemAdd,而不是一定以类名Order开头。你的理解有误。
Re: ~CityHunter~
@netfocus,引用@~CityHunter~,[email protected],这是角度的的不同,名词开头,会将同一对象的不同操作汇总;那么动词开头,会将不同对象的同一操作汇总。所以这不是关键问题。,当然我个人比较喜欢你说的这种。,方法如果是以类的名称开头,那就会导致名称重复。假如现在有一个订单类,Order,订单有一个添加订单项的方法,你会怎么命名这个方法呢?如果是我,那就叫AddItem,如果是以类的名称开头,那该如何命名呢?,既然你没能理解我的意思,我想还是说明白点比较好。这里所说的同一对象指的是Item,如果你一定要说它是Order,那么一般的命名是这样的:,,AddOrderUpdateOrderDeleteOrder,,这种命名当然是很好的。,,假设我们的一个类里面,不仅仅只有AddOrder,还有AddProduct(这里不深入讨论到面向对象的设计,仅仅只是举这个例子),那么,AddOrderAddProductDeleteOrderDeleteProduct,会将不同对象的同一操作汇总到一起,而:,OrderAddOrderDeleteProductAddProductDelete,会将同一对象的不同操作汇总到一起
4楼stg609
赞同楼主的观点,在开发项目的时候一定要有统一的代码命名规范,这样不仅让项目的风格保持一致,也可以为日后维护代码节省不少时间。如果一个项目使用了各种不同的命名规范,就会让维护的人感觉异常头痛。,,这里既然楼主提到了匈牙利命名法,我想顺便请教下,为什么 C# 中几乎没有这个命名法的影子?是因为智能感智已经帮助我们识别了数据类型的原因吗?
Re: netfocus
@stg609,引用赞同楼主的观点,在开发项目的时候一定要有统一的代码命名规范,这样不仅让项目的风格保持一致,也可以为日后维护代码节省不少时间。如果一个项目使用了各种不同的命名规范,就会让维护的人感觉异常头痛。,,这里既然楼主提到了匈牙利命名法,我想顺便请教下,为什么 C# 中几乎没有这个命名法的影子?是因为智能感智已经帮助我们识别了数据类型的原因吗?,是的,由于智能感知的存在,没有必要突出变量的类型了;但这个我觉得只是一个次要原因。真正的原因,我上面有提到,一个变量,名词是放在最后的,这个名词决定了这个变量代表什么。比如有个变量叫totalCount,我们一看就知道这是一个count,然后count一定是一个int或者long,所以就不需要在强调它的类型了。再比如,remotingRequest, httpRequest,这种,我们也一看就知道他们是请求,一个是remoting的请求,一个是http的请求。remoting,http是用来修饰request的。request决定了这个变量是什么(同时就意味着我们知道了他的类型了),然后remoting,http这种是进一步说明该request的业务含义。就像disabledButton,我们一看就知道这是一个button,然后是一个什么Button呢,就是一个已禁用的button。
3楼yaojunzhizhi
命名习惯,几乎可以作为一个标尺,可以衡量Coder的lever,一个项目的lever,一个团队的lever。虽然没明文的规定,至少我在在潜意识里,很强烈的使用这把标尺。楼主这个分享非常棒,顶你。
Re: netfocus
@yaojunzhizhi,是的,我也有同感,看一个程序员的修养如何,看他的命名就行了。
Re: ~CityHunter~
@netfocus,引用@~CityHunter~,[email protected],这是角度的的不同,名词开头,会将同一对象的不同操作汇总;那么动词开头,会将不同对象的同一操作汇总。所以这不是关键问题。,当然我个人比较喜欢你说的这种。,方法如果是以类的名称开头,那就会导致名称重复。假如现在有一个订单类,Order,订单有一个添加订单项的方法,你会怎么命名这个方法呢?如果是我,那就叫AddItem,如果是以类的名称开头,那该如何命名呢?,这里明显指的是AddItem或者ItemAdd,不知道你所谓的以类名Order开头是怎么理解得来的。
1楼MJ_jion
sbError 什么样的错误 能被起这个名字
Re: netfocus
@MJ_jion,引用sbError 什么样的错误 能被起这个名字,哈哈,傻B错误,呵呵。
  相关解决方案