如何编写可读性好的代码
1.什么样的代码是可读性好的代码?
“让人阅读你的代码,就像阅读文章一样流畅,就像阅读散文诗一样优美!”——这就是好代码!
把代码当作一篇优美的散文诗来写!用这样的标准来要求自己,一定会写出好代码,一定会成为一个优秀的程序员。
代码不仅是写给机器编译的,更是写给人看的!
代码不仅是代码,更是文档!
2.理清思路再动手——先写注释,再写代码
清晰的思路是编程行动的良好指南。花点时间思考一下,不要一接到任务就动手编代码,从而陷入技术细节不可自拔。
2.1 我的编程步骤
(1)在一个空的函数体内用注释写出自己的思路,如:
//功能说明:XXX
private void MyMainFunction()
{
//第1步,XXX
//第2步,XXX
MySubFunction ();//实现XXX
//第3步,XXX
}
//功能说明:XXX
private void MySubFunction()
{
//先空着
return 0;
}
(2)理清思路后,在空白处填写自己的代码。
如果某个步骤中实现起来感觉有点麻烦,那就先放一个空的子函数,为这个子函数建一个空的函数体——保证编译始终通过,稍后再填充这个空函数体。这种方法不影响你的整体思路,避免陷入编程细节,同时又让“大事化小,小事化了”。
(3)编完主函数后,填充空的子函数体。
其实是对(1)(2)的迭代。通过主函数的运行效果,可以实时检测子函数编写的正确与否。我们编写的子函数都即时被应用场景所调用,也就是即时的被测试,这不也是测试驱动的思想吗?事实证明,这样得到的函数,比预先设计的函数更有用。
这样,只要思路清晰正确,编程就不会走太大弯路。
2.2 注释应先于代码存在
注释应先于代码存在,而不是编写完代码之后去补注释。因为人固有的懒惰,编写完代码之后都不情愿再去主动加注释,这使得代码的可读性变差。
另外,利用空白或空白行合理分隔代码,也是一种良好的注释。就像好的文章印刷,段落间距要大一点是一样的。文章中也要留白!
C#代码中可使用region合理分隔代码,同时在region中加入注释。特别是,一定要把私有函数聚集到region中折叠起来,不要与公有函数(或事件函数)交叉,因为我们阅读代码往往是从公有函数(或事件函数)入手的。这可以隐藏细节,使代码看起来更整洁。
3.给变量起个好名字!
合理的变量命名是代码可读的基础。好的命名,不仅仅是使得代码易读,它代表了你对业务领域的理解,对程序逻辑的认知,对项目框架的把握。所以,好的程序员很多时候纠结的不是技术实现问题,而是如何为变量起一个好名字,使得代码读起来流畅,能让更多的人理解!
遵循一些成熟的命名规范,给变量起个好名字的事会容易一些。接下来,我们探讨一下常见的命名规范问题。
(1)常见的大小写命名法
PascalCasing(大写开头):用于名字空间、类型、成员等的命名,举例:FileStream。
camelCasing(驼峰命名法,小写开头):用于形参、局部变量、私有字段等的命名。举例EncryptFile(string plainFile, string cypherFile)。
匈牙利命名法(小写开头,首单词为数据类型):不推荐使用,因为IDE的智能提示很容易让你知道变量的类型。举例:intCount、iCount。(其实,我们对匈牙利命名法有误解,下篇再谈)
另外,微软建议不要在单词间使用下划线。
(2)名字空间的命名
Company.Product.Subnamespace。举例:
HuazemingTech.RailwayMis.Web
(3)类(结构)及对象的命名
名词或名词短语,因为它们代表系统中的实体。举例:
Student student;
List students;
(4)接口的命名
表示类型层次的根基时:名词或名词短语,如:IList;
表示某种能力时:形容词或形容词短语,如IComparable。
(5)方法的命名
动词或动词短语,DoSomething()。如:String.Split()
返回布尔值时使用表示肯定性的短语,并考虑第三人称。如:collection.Contains(item)
(6)属性的命名
名词短语或形容词。举例:
public class ListView{
public ItemCollection Items {get;}//这里用复数形式
}
用肯定性短语命名布尔属性,考虑前缀“Is/Can/Has”。举例:CanRead、IsPostBack。
(7)命名规范不是一成不变的
命名规范不是一成不变的,在特定场景下可以有自己风格的约定,前提是要使代码保持一致、易读。比如,一般我们强烈反对使用汉语拼音命名变量,可是在有些项目中,特别是涉及国内政府、院校的信息标准时,其数据库字段(量很大)完全是按汉语拼音首字母制定的,如果非要翻译成英文就有点矫枉过正了(工作量本身也很大)。一旦熟悉了这个行业之后,这些汉语拼音简写也就成了业务领域知识的一部分了,也就不那么别扭了,这也算中国特色吧。
4.如何检测你的代码是否规范?
(1)人工检测:让同伴阅读你的代码(结对编程,代码复审),发现问题。自我检测,不懈追求――“让人阅读你的代码,就像阅读文章一样流畅!”。
(2)工具检测:FxCop,微软的一个开发工具,可以对编译过的托管代码进行分析,并告诉用户哪些地方不符合设计规范。(博友【金色海洋(jyk)阳光男孩】推荐:R#--ReSharper: http://www.jetbrains.com/resharper/).
5.重构你的代码,做得更好一点点!
嗅嗅代码的坏味道:如果你发现在单页中写了过多的MySubFunction,如果你检测到不符合设计规范的代码,如果你写了过长的函数,如果你发现你在重复拷贝相同的代码段……是时候重构你的代码了!
何谓重构?重构是对软件内部结构的一种调整,目的是在不改变软件可察行为的前提下,提高其可理解性,降低其修改成本。
为何重构?改进软件设计(消除重复,Don’t Repeat Yourself);使代码更易理解(提高可读性);帮你找到Bug(Keep Your Code Clean);助你提高编程速度(后退是为了大踏步的前进)。
何时重构?三次法则:事不过三,三则重构。重构不是重构的目的,当重构能帮助你把后续的事情做得更好,那么还等什么?重构的时机:添加功能时,修补错误时,复审代码时。
如何重构?小步前进,不断验证。(Done is Better Than Perfect)
常见的重构原因和对策:
(1)代码重复。提取为公共类/函数。
(2)代码形式重复。考虑模板类/泛型。
(3)过多函数的类。考虑使用partial分部类,将类分拆到多个文件中去,每个分部类对应一个文件。如MVC中Controller类往往会成为包含过多Action函数的类,就可将其按功能域拆分为多个分部类。
(4)过长的参数列表。构造一个对象,包含所有要用的参数,然后将这个对象当作参数即可。
编程的过程实际是一个不断重构(改进)的过程。通过不断重构,可以去除代码的坏味道,编写可读性更好的代码。同时也深化了你对设计的理解,提高了你的编程素养。
重构,是一种生活态度,每天做得更好一点点。不要有过多的期望,一点点就好!不断前进,逐步逼近完美。
6.向微软学习,向MSDN学习!
微软作为业界最为成功的软件生产商,在各方面都有值得我们学习的地方。我觉得Windows、Office等是我们做界面和为用户设计操作模式的最好老师,当我没有思路的时候,我都会打开Windows的某个功能看看,就会受到启发。
MSDN是我们学习编程的最好老师。MSDN是众多大师的智慧结晶。经常看MSDN中的类库,不仅可以系统的掌握类库的功能,还可以学到如何给变量命名,如何进行架构设计等。看MSDN中的示例代码,也是快速上手的捷径;特别是一些“快速指南”,能很快让你了解某个方面的开发技术。总之,看MSDN有百利而无一害,呵呵,比看很多烂书强多了。(最近也发现了MSDN中一些代码比较烂)
MSDN是帮助文档,我们在使用很多软件遇到问题时,是否忽略了开发者精心给我们准备的帮助文档呢?
(现在做APP,没思路的时候就看看淘宝、京东、微信、支付宝,看他们的UI布局/设计、看他们的操作流程,能够得到启发)
7.小结
通过注释理清思路,给变量起好名字,重构你的代码,从MSDN中领悟大师真谛,其实都是一些编程习惯,养成好的、适合自己的习惯会受益终身。软件大师Kent Beck说:
“我不是个伟大的程序员,我只是个有着一些优秀习惯的程序员而已。”
——与诸君共勉!希望大家都成为具有优秀习惯的程序员,编写散文诗一样的代码!
参考文献/推荐阅读:
《编写可读代码的艺术》
《代码整洁之道》
《.NET设计规范:约定、惯用法与模式》
《重构——改善既有代码的设计》
备注:本文以C#编程为例,不足之处,敬请批评指正。这是本人以前写的文章,第一次使用“简书”,试发一下,欢迎交流。