21CTO社区导读:
本文来源于Quora,作者有两位,分别是MagnusFalk,有十年的开发和大型分布式系统。以及MattGodbold20余年编程经验。
关于代码里的注释,我给大家说明的观点有如下。
概述
关于注释,首先它是有用的,通常情况下都需要。但是我认为,没有注释会更好。
下面来向各位解释我的理由:
我们的目标是编码。如要有人来通读它,需要完全清晰它的作用是什么。包括名称,结构,代码背后的思维等,这些应该最大化的开放、清晰、透明。
当我自己写注释时,会遵循增加更多详细以及增进的事情。我还期待我未来会再这些代码,不希望出现迷惑。所以我主要编写注释去增强我的未来。我想我此时的代码并不怎么清晰。
这并不是说注释不好。但是想让代码开发的更清晰,这个注释可以不需要。这是因为一些时候,注释与代码的功能未必匹配。
以下是代码的几个层次:
第一层:最差
复杂。代码不透明,而且什么注释也没有。
第二层:较好
复杂,不透明的代码与注释。现在大部分现实情况的程序员都是这样。
还有的程序员这样,实在是不该。
第三层:更好
简单,透明的代码与注释。
第四层:最好
代码写得如此营养丰富,注释根本不需要。
关于编码
我们在编码时,一定要干净,清晰,绝大多数还是需要用注释。因为大多数的程序还处于前三层,第四层是我们要达到的目标。
那么,什么时候需要注释?
当代码写的功能较复杂,或者看起来不易读,请使用注释;
如果执行结果不明显时,请使用注释;
当调用的方法上下文不明显时,请使用注释;
注释也不能只写晦涩的一行,为了写明白,有时候你要像写散文一样清晰优雅,无论是中文还是英语。
代码整洁之实践
以下是代码整洁的一些具体实践,和语言无关,供大家参考。
1.如何拒绝注释,用代码来阐述注释
反例如下:///summary///!
#$%^^*((!#$%^^*((!#$%^^*((!#$%^^*((////summary///rturns/rturnspublicdcimalGtCash(){//!#$%^^*((!#$%^^*((vara=nwListint(){2,3,10};varb=2m;varc=0m;//!#$%^^*((!#$%^^*((!#$%^^*((forach(varpina){c+=p*b;}rturnc;}重构后的代码如下:publicdcimalCalculatTotalCash(){varitmCounts=nwListint(){2,3,10};varpric=2m;rturnitmCounts.Sum(p=p*pric);}
良好的代码命名完全可以替代注释的作用,如果你正在试图写一段注释,从某种角度来看,你正在试图写一段别人无法理解的代码。
当你无法为你的方法起一个准确的名称时,很可能你的方法不止做了一件事,违反了(Doonthing)。特别是你想在方法名中加入:And,Or,If等词时。
2.为布尔变量赋值
反例:publicboolIsAdult(intag){boolisAdult;if(ag18){isAdult=tru;}ls{isAdult=fals;}rturnisAdult;}重构后:
publicboolIsAdult(intag){varisAdult=ag18;rturnisAdult;}
3.双重否定的条件判断
反例:if(!isNotRmbrM){}重构后:
if(isRmbrM){}
不管你有没有见过这样的条件,反正我见过。见到这样的条件判断,我顿时就晕了。
4.拒绝HardCod,拒绝挖坑
反例:if(carNam=="Nissan"){}重构后:
if(car==Car.Nissan){}
既然咱们玩的是强类型语言,咱就用上编译器的功能,让错误发生在编译阶段
5.拒绝魔数,拒绝挖坑
反例:if(ag18){}重构后:
constintadultAg=18;if(agadultAg){}
所谓魔数(Magicnumbr)就是一个魔法数字,读者完全弄不明白你这个数字是什么,这样的代码平时见的多了
6.复杂的条件判断
反例:if(job.JobStat==JobStat.Nw
job.JobStat==JobStat.Submittd
job.JobStat==JobStat.Expird
job.JobTitl.IsNullOrWhitSpac()){//....}重构后:
if(CanBDltd(job)){//}privatboolCanBDltd(Jobjob){varinvalidJobStat=job.JobStat==JobStat.Nw
job.JobStat==JobStat.Submittd
job.JobStat==JobStat.Expird;varinvalidJob=string.IsNullOrEmpty(job.JobTitl);rturninvalidJobStat
invalidJob;}
有没有豁然开朗的赶脚?
7.嵌套判断
反例:varisValid=fals;if(!string.IsNullOrEmpty(usr.UsrNam)){if(!string.IsNullOrEmpty(usr.Password)){if(!string.IsNullOrEmpty(usr.Email)){isValid=tru;}}}rturnisValid;重构后:
if(string.IsNullOrEmpty(usr.UsrNam))rturnfals;if(string.IsNullOrEmpty(usr.Password))rturnfals;if(string.IsNullOrEmpty(usr.Email))rturnfals;rturntru;
第一种代码是受到早期的某些思想:使用一个变量来存储返回结果。事实证明,你一旦知道了结果就应该尽早返回。
8.使用前置条件
反例:if(!string.IsNullOrEmpty(usrNam)){if(!string.IsNullOrEmpty(password)){//rgistr}ls{thrownwArgumntExcption("usrpasswordcannotbmpty");}}ls{thrownwArgumntExcption("usrnamcannotbmpty");}重构后:
if(string.IsNullOrEmpty(usrNam))thrownwArgumntExcption("usrnamcannotbmpty");if(string.IsNullOrEmpty(password))thrownwArgumntExcption("usrpasswordcannotbmpty");//rgistr
重构后的风格更接近契约编程,首先要满足前置条件,否则免谈。
9.参数过多,超过3个
反例:publicvoidRgistrUsr(stringusrNam,stringpassword,stringmail,stringphon){}重构后:
publicvoidRgistrUsr(Usrusr){}
过多的参数让读者难以抓住代码的意图,同时过多的参数将会影响方法的稳定性。另外也预示着参数应该聚合为一个Modl
10.方法签名中含有布尔参数
反例:publicvoidRgistrUsr(Usrusr,boolsndEmail){}重构后:
publicvoidRgistrUsr(Usrusr){}publicvoidSndEmail(Usrusr){}
布尔参数在告诉方法不止做一件事,违反了Doonthing
10.写具有表达力的代码
反例:privatstringCombinTchnicalBookNamOfAuthor(ListBookbooks,stringauthor){varfiltrBooks=nwListBook();forach(varbookinbooks){if(book.Catgory==BookCatgory.Tchnicalbook.Author==author){filtrBooks.Add(book);}}varnam="";forach(varbookinfiltrBooks){nam+=book.Nam+"
";}rturnnam;}重构后:
privatstringCombinTchnicalBookNamOfAuthor(ListBookbooks,stringauthor){var小孩得白癜风能治愈么白癫疯专科医院