一段优秀的代码,它通常须要知足如下几个条件:程序员
#统一规范#正则表达式
全部的代码,第一前提必须是统一规范,而常见的统一规范主要包括有如下内容:数据库
1)统一编辑器规范编程
在团队开发中,咱们并不对各个开发人员使用的编辑器作硬性要求,你可使用常见的如Eclipse、WebStrom、Sublime等集成开发环境IDE,也可使用UltraEdit这种,甚至Vim都无所谓。可是咱们仍是会作一些统一规范要求,好比Tab键统一使用空格Space替换(一个Tab为四个Space)、文件编码统一为UTF-八、换行的Line Delimiter统一为Unix的LF而不是Windows的CRLF(PHP代码尤为重视这点)等等。设计模式
2)统一代码风格数组
咱们知道代码的风格有不少种,尤为是在涉及到括号的使用上,好比:缓存
K&R风格是最先为人们所喜好的放个,它是由C语言之父Kernighan和Ritchie在他们的《C程序设计语言》一书中确立的,它也常被认为是最初和最好的风格,它能够在一个小屏幕中尽量显示更多的信息。这个也是我我的最经常使用的风格。安全
int k_and_r() { int a = 0, b = 0; while (a != 10) { a++; b++; } return b; }
悬挂式的风格在空间上显示上更加开阔,因为有着更明显的前括号,也使得代码更加易于浏览;但在竖向空间上占用更多。app
int exdented() { int a = 0, b = 0; while (a != 10) { a++; b++; } return b; }
缩进风格并不太常见,在这种风格下括号随代码一块儿缩进,这种风格也被称为“Whitesmith”风格,由于早期的Whitesmith的C编译器的示例代码使用的就是这种风格,我的并不推荐。编程语言
int indented() { int a = 0, b = 0; while (a != 10) { a++; b++; } return b; }
还有一些其余的括号风格,好比GNU风格是介于悬挂式和缩进式风格之间的一种风格,括号被放置在各个缩进级别的一半的位置
3)统一命名规范
命名包括文件的命名、类的命名、方法的命名、变量的命名等,良好的命名使得代码易于阅读,也更加易于维护。命名的方法有不少,常见的的有:
匈牙利命名法是一种有争议的命名约束,它将关于变量或函数的类型的信息编入它们的名称当中,要求开头字母使用变量类型的缩写,其他部分用变量的英文或中文的缩写,同时要求单词的第一个字母大写。这种命名法最初是在20世纪80年代的Microsoft公司中出现的,并在该公司的Win32 API和MFC库中获得了普遍的使用,也所以致使了必定的流行性。之因此被称为“匈牙利命名法”,是由于它的创始人Charles Simonyi是匈牙利人。此外,变量名看起来像是使用匈牙利语书写的,可是要理解它并不容易,不少非Windows的程序员都会被好比lpszFile、rdParam和hwndItem等的奇怪名字给搞糊涂。
int iMyAge; // "i"是int类型的缩写 char cMyName[0]; // "c"是char类型的缩写
有的时候又称为“小驼峰命名法”,它在Java语言库以及不少C++代码库中获得了普遍使用,这种命名主要源于其大写字母的布局很像骆驼的驼峰,它规定第一个单词字母小写,后面其余的单词首字母大写。
int myAge; char myName[0];
这种命名法跟上面的驼峰命名法很相像,惟一区别就是其第一个字母也大写,因此有时又称为“大驼峰式命名法”。
int MyAge; char MyName[0];
这种风格在C++标准库和GNU Foundation中比较常见,也即用下划线来隔开不一样的单词。
int my_age; int my_name[0];
事实上,采用什么样的命名方式都是能够的(虽然我我的更偏向于驼峰命名法),更重要的是命名必须清晰,好比函数名能够采用动名词+静名词的组合来命名,而不是用foo和bar这种古怪的名称。另外,建议在清晰的基础上保持简洁,不然也极可能出现相似someTypeWithMeaningfulNaming这种很是冗余的命名,好比在for循环中使用i而不是使用index就是一种推荐作法。
#简洁清晰#
什么叫作简洁?可以一句代码解决的事情,就不要写成两句代码。
什么叫作清晰?虽然一句代码可以解决事情,但咱们有的时候却将其拆成了多句代码,使得其变得可能有点冗余。
优先程度上,清晰>简洁。
每一个人写的代码,它的后续维护者多是一个初级程序员,若是他不能理解你的代码逻辑,或者说你的代码逻辑很难理解,那么他就有可能会犯一些错误。复杂的结构和不经常使用的语言技巧虽然能够证实你在运算符优先级方面有着熟练经验,可是这些实际上会扼杀代码的可维护性。好比下面两段代码:
int a = b = c = 10; int result = a * b + b * c - a + b / c; // 下面的代码虽然不如上面代码简洁,可是更加的简单 int a = 10, b = 10, c = 10; int result = (a * b) + (b * c) - a + (b / c);
清晰的代码,也每每意味着简单的代码。若是对于某段代码不是基于性能上的须要而写得复杂,那么,请保持代码的简单清晰。
#必要注释#
做为一个负责任的程序员,咱们有义务给咱们的代码写注释,即便在编码任务再繁重的状况下。
但咱们也须要注意的是,注释不是越多越好,咱们更加剧视注释的质量,而不是数量。不少时候,一个好的命名已经能够可以帮咱们省下不少注释。好比下面的代码:
for (int i = 0; i < wlst.size(); i++) k(wlst[i]); // 上面代码改为下面代码 for (int i = 0; i < widgets.size(); i++) { printWidget(widgets[i]); }
注释中应该包含的内容包括有:
注释不该该描述代码是怎样运行的,这彻底能够经过阅读代码来了解,你更加应该注意的是描述为何有些东西要这么写,好比下面的代码的注释就不是必须的,彻底能够去掉:
// 循环遍历全部的widget for (int i = 0; i < widgets.size(); i++) { // 打印这些widget printWidget(widgets[i]); }
不要试着去描述代码,好比下面的代码的注释彻底是无效的:
// index自增 ++index;
不要试图在注释中去说明某个代码的限制条件,更应该地使用代码自己的机制去实现。还有,当有的时候你发现可能要花大量的注释来描述某段代码的功能的时候,更好的作法是用代码去描述,好比把一大段的代码拆分红多个子函数,给每一个子函数赋予更合适的命名等。好比:
// 下面这个方法不容许被类之外访问 public void getMyAge() { } // 彻底能够不要上面的注释,而使用以下的代码实现 private void getMyAge() { }
注释不该该给自己的代码形成分心,好比有些程序员喜欢在if的结束加上// end if (a < 1) 这样的注释,而这种注释则是彻底不必的,只会给本来阅读代码形成分心,更合适的作法是经过正确合适的缩进方式等来保证代码可读性。
#健壮安全#
咱们在编写代码的时候,须要考虑各类方方面面的因素,提升代码的健壮性。好比,在编写最多见的登陆代码时,就须要考虑到用户输入的用户名和密码的多种状况,好比:
public void checkLogin(String username, String password) { if (username == null || password == null) { // Error } if (username.trim().equals('') || password.trim().equals('')) { // Error } // do something }
不能只是简单地检查用户名和密码是否匹配,还必需要考虑到当用户名或密码为空时候的处理逻辑,若是用户名是手机号,还必须使用正则表达式来检查所输入的用户名是否符合手机号码样式等等。
不只于此,对于安全性上的要求,还必需要对用户输入的字符进行处理,防止用户输入相似<script>alert()</script>的XSS攻击代码和相似'or'1'='1的SQL注入攻击代码等。
总之,要编写健壮安全的代码,必须时刻考虑到:
“防护性编程”中心原则是“不作设想”,也即永远不要设想用户会按照咱们写代码的预期或要求来使用代码。一些简单的防护性规则,好比“检查全部的输入”和“验证全部的运算”,能够帮咱们把代码中许多的安全隐患给消除掉。
初级开发人员的代码在早期必须经由高级开发人员进行代码审核,有经验的高级开发人员可以经过阅读代码就能发现不少问题,好比边界值的判断上,数组是否会形成溢出和字段长度是否超出数据库限制等这些都是能够经过代码审核来发现。
一些敏捷开发的TDD测试驱动开发就是这么作的,它要求代码必须是能够被测试的,而且这些能够被测试的代码时刻可以经过测试样例。
#高效性能#
随着如今处理器的愈来愈强大,不少时候应用的瓶颈并不在代码而在其余地方(主要是I/O操做,好比读写文件和数据库等),我的更不推荐为了所谓的性能而牺牲了代码的可读性和可维护性,除非这块代码确实是必须优化的。
但咱们也不能仗着处理器的强大就能够彻底不顾代码的性能,有些简单的优化原则在咱们写代码的时候就须要时刻遵循。
若是不是立刻就要使用某个文件,那么就不要打开它;若是暂时不须要某个值,那就不要去计算它;若是没有某个函数程序也能够运行,那就不要去调用它。
若是一个可能会致使函数计算无效的条件,那么对这个条件的判断最好放在顶部,防止作了过多无用工做,好比:
public int calculate(int number) { if (number == 0) { return 0; } // do something }
因为循环中是每次都要作的,那么每次循环中若是某个值都保持不变,则将该值移到循环外面,好比:
for (int i = 0; i < tree.appleCount(); i++) { } // 上面代码能够改为以下 int appleCount = tree.appleCount(); for (int i = 0; i < appleCount; i++) { // do something }
确保将可能失败的测试放在最前面以节省时间,好比if (condition_one && condition_two),确保condition_one不为真的可能性比condition_two更大。
好比将公共的代码提取到共享函数中以免重复计算,或者将某个常常被用到的须要被计算出来的值放到缓存中以备使用。
最后,各类不一样的编程语言都有其不一样的优化之处,好比Java中使用加强式foreach循环就比传统的for循环更加高效,具体到各类语言再具体分析。
#易于扩展#
首先,咱们对于程序的扩展性判断,并非须要其能支持将来需求的变动的可能性。相反,咱们不提倡对代码作“过分设计”,代码的可扩展性更主要的是体如今将来可以对需求变化快速响应上,可以跟随需求的变化而快速变化,而不是一味不变地支持需求的变化。
可是这也确定也不能成为咱们偷懒的借口,咱们仍是可使用一些常规的原则来加强代码的可扩展性,尤为是时刻保证代码的“低耦合”很是重要。
不一样的功能拆分出来,而不是在一个函数里完成,好比:
public void init() { // load database // init environment // init ui // do something } // 上面的方法把全部的事情都放在一块儿,扩展性不好,咱们须要把不一样的功能拆分红不一样的函数 public void loadDatabase() {} public void initEnvironment() {} public void initUi() {} public void init() { loadDatabase(); initEnvironment(); initUi(); }
对于配置文件也是同样,咱们须要在程序的入口处可以根据当前环境不一样而加载不一样的配置文件,好比Web应用中常见的作法是将本地环境、测试环境、正式环境分红三个配置文件,而后根据当前请求域名的不一样而加载不一样的文件,而不是把全部的配置写到一个文件里。
对于一些功能相似的,彻底能够抽象出一个抽象类,在这个抽象类中定义功能接口,而后再在不一样的子类中实现该接口的不一样功能,好比Web应用中一种常见的作法是在抽象控制类中定义GET/POST/PUT/DELETE请求协议的接口方法,而后再在不一样子类中分别实现不一样的功能细节。
public abstract class BaseController { public void get(); public void post(); public void put(); public void delete(); }
#写在最后#
上面写了这么多,其实说白了提升写代码能力惟一的途径就是多写代码,多思考。对于初级程序员来讲,把代码写得具备可维护性(规范/简洁/注释)是最基本的要求,而对于有经验的程序员来讲,还必须考虑代码的健壮性、安全性、高效性和可扩展性等。写代码的时候多考虑下这些东西,常常重构本身的代码,就离写出优秀的代码不远了。
最后,给你们推荐几本我的以为不错的书籍,这几本书对个人代码生涯有着极大的影响。
一、《编程匠艺 编写卓越的代码》,电子工业出版社,Pete Goodliffe(著),韩江, 陈玉(译);
二、《重构 改善既有代码的设计》,人民邮电出版社,Martin Fowler(著),熊节(译);
三、《大话设计模式》,清华大学出版社,程杰(著);
四、《Java优化编程(第2版)》,电子工业出版社,林胜利, 王坤茹(编著);