每一个人对于什么是“好”的代码规范未必认同,这时咱们颇有必要给出一个基准线—什么是好的代码规范和设计规范java
计算机只关心编译生成的机器码,你的程序采用哪一种缩进风格,变量名有无统一的规范等,与机器码的执行无关。可是,作一个有商业价值的项目,或者在团队里工做,代码规范至关重要。“代码规范”能够分红两个部分:mysql
1. 代码风格规范——主要是文字上的规定,看似表面文章,实际上很是重要程序员
2. 代码设计规范——牵涉到程序设计、模块之间的关系、设计模式等方方面面的通用原则算法
代码风格的原则是:简明,易读,无二义性
提示:这里谈的风格是一家之言,如遇争执,关键是要本着“保持简明,让代码更容易读”的原则,看看争执中的代码规范可否让程序员们更好地理解和维护程序sql
是用Tab键好,仍是二、四、8个空格?
结论:4个空格,在Visual Studio和其余的一些编辑工具中均可以定义Tab键扩展成为几个空格键。不用Tab键的理由是,Tab键在不一样的状况下会显示不一样的长度,严重干扰阅读体验。4个空格的距离从可读性来讲,正好数据库
行宽必须限制,可是之前有些文档规定的80字符行宽过小了(之前的计算机/打字机显示行宽为80字符),如今时代不一样了,能够限定为100字符编程
在复杂的条件表达式中,用括号清楚地表示逻辑优先级设计模式
1. 最精简的格式A:网络
if (condition) DoSomething(); else DoSomethingElse();
优势:由于能够节省几行
缺点:不一样的语句(Statement)放在一行中,程序调试(Debug)起来很是不方便,若是要一步一步观察condition中各个变量(condition多是包含函数调用的复杂表达式)的变化状况,单步执行就很难了数据结构
2. 有断行的格式B:
if (condition) DoSomething(); else DoSomethingElse();
缺点:因为没有明确的“{”和“}”来判断程序的结构,在有多层控制嵌套时,这样的格式就不容易看清结构和对应关系
3. 改进的格式C
if (condition) { DoSomething(); } else { DoSomethingElse(); }
缺点:不够清晰
4. 每一个“{”和“}”都独占一行,即格式D
if (condition) { DoSomething(); } else { DoSomethingElse(); }
不要把多条语句放在一行上
a =1; b =2; // bogus if (fFoo) Bar(); // bogus
更严格地说,不要把多个变量定义在一行上
Foo foo1, foo2; // bogus
用单个字母给有复杂语义的实体命名并不可取,也是通过了实践检验的方法叫“匈牙利命名法”。例如:
fFileExist // 代表是一个bool值,表示文件是否存在; szPath // 代表是一个以0结束的字符串,表示一个路径
下划线用来分隔变量名字中的做用域标注和变量的语义,如:一个类型的成员变量一般用m来表示,或者简单地用一个下划线“”来作前缀。移山公司规定下划线通常不用在其余方面
由多个单词组成的变量名,若是所有都是小写,很不易读,一个简单的解决方案就是用大小写区分它们。
一个通用的作法是:
须要注释什么?不要注释程序是怎么工做的(How),程序自己就应该能说明这一问题
//this loop starts the i from0 to len, in each step, it // does SomeThing for (i =0; i < len; i++) { DoSomeThing(); }
以上的注释是多余的。注释是为了解释程序作什么(What),为何这样作(Why),以及要特别注意的地方,以下
/go thru the array, note the last element is at [len-1] for (i =0; i < len; i++) { DoSomeThing(); }
复杂的注释应该放在函数头,不少函数头的注释都用来解释参数的类型等,若是程序正文已经可以说明参数的类型in/out,就不要重复!
注释也要随着程序的修改而不断更新,一个误导的(Misleading)注释每每比没有注释更糟糕
另外,注释(包括全部源代码)应该只用ASCII字符,不要用中文或其余特殊字符,不然会极大地影响程序的可移植性。
在现代编程环境中,程序编辑器能够设置各类美观得体的字体,咱们可使用不一样的显示风格来表示程序的不一样部分。
注意:有些程序设计语言的教科书对于基本的语法有详细的注释,那是为了教学的目的,不宜在正式项目中也这么作
代码设计规范不光是程序书写的格式问题,并且牵涉到程序设计、模块之间的关系、设计模式等方方面面,这里又有很多内容与具体程序设计语言息息相关(如C、C++、Java、C#),可是也有通用的原则,这里主要讨论通用的原则。若是你只想为了“爽”而写程序,那么能够忽略下面的原则;若是你写的程序会被不少人使用,而且你得加班调试本身的程序,那最好仍是遵照下面的规定
现代程序设计语言中的绝大部分功能,都在程序的函数(Function、Method)中实现。关于函数,最重要的原则是:只作一件事,而且要作好
函数最好有单一的出口,为了达到这一目的,可使用goto。只要有助于程序逻辑的清晰体现,什么方法均可以使用,包括goto
当程序的主要功能实现后,一些程序员会乐观地估计只须要另外20%的时间,给代码加一些错误处理就大功告成了,可是这20%的工做每每须要所有项目80%的时间
1. 参数处理
在Debug版本中,全部的参数都要验证其正确性。在正式版本中,对从外部(用户或别的模块)传递过来的参数,要验证其正确性
2. 断言
如何验证正确性?那就要用断言(Assert)。断言和错误处理是什么关系?当你以为某事确定如什么时候,就能够用断言。
注意,除了关于异常(Exception)的部分,大部分其余原则对C#也适用
1. 类
2. class vs. struct
3. 公共/保护/私有成员(public、protected和private)
4. 数据成员
5. 虚函数(Virtual Function)
使用虚函数来实现多态(Polymorphism)
仅在颇有必要时,才使用虚函数
若是一个类型要实现多态,在基类(Base Class)中的析构函数应该是虚函数
6. 构造函数(Constructors)
7. 析构函数(Destructor)
8. new和delete
若是可能,实现本身的new/delete,这样能够方便地加上本身的跟踪和管理机制。本身的new/delete能够包装系统提供的new/delete
检查new的返回值。new不必定都成功
释放指针时不用检查NULL
9. 运算符(Operators)
在理想状态下,咱们定义的类不须要自定义操做符。确有必要时,才会自定义操做符
运算符不要作标准语义以外的任何动做。例如,“==”的判断不能改变被比较实体的状态
运算符的实现必须很是有效率,若是有复杂的操做,应定义一个单独的函数
当你拿不定主意的时候,用成员函数,不要用运算符
10. 异常(Exceptions)
异常是在“异乎寻常”的状况下出现的,它的设置和处理都要花费“异乎寻常”的开销,因此不要用异常做为逻辑控制来处理程序的主要流程
了解异常及处理异常的花销,在C++语言中,这是不可忽视的开销
当使用异常时,要注意在什么地方清理数据
异常不能跨过DLL或进程的边界来传递信息,因此异常不是万能的
11. 类型继承(Class Inheritance)
仅在必要时,才使用类型继承
用const标注只读的参数(参数指向的数据是只读的,而不是参数自己)
用const标注不改变数据的函数
代码复审的正肯定义:看代码是否在“代码规范”的框架内正确地解决了问题
名称 | 形式 | 目的 |
---|---|---|
自我复审 | 本身 vs 本身 | 用同伴复审的标准来要求本身。不必定最有效,由于开发者对本身老是过于自信。若是能锲而不舍,则对我的有很大好处 |
同伴复审 | 复审者 vs 开发者 | 简便易行 |
团队复审 | 团队 vs 开发者 | 有比较严格的规定和流程,适用于关键的代码,以及复审后再也不更新的代码覆盖率高——不少双眼睛盯着程序,但效率可能不高(全体人员都要到会) |
软件工程中最基本的复审手段,就是同伴复审
1. 代码复审的目的在于:
找出代码的错误,好比:
编码错误,好比一些碰巧骗过了编译器的错误
不符合团队代码规范的地方
发现逻辑错误,程序能够编译经过,可是代码的逻辑是错的
发现算法错误,好比使用的算法不够优化,边界条件没有处理好等
发现潜在的错误和回归性错误—当前的修改致使之前修复的缺陷又从新出现
发现可能须要改进的地方
教育(互相教育)开发人员,传授经验,让更多的成员熟悉项目各部分的代码,同时熟悉和应用领域相关的实际知识
喜欢在程序中加一些特定的标记,来跟踪各类“要作的事情”,这些标记最好是加上人名,以示负责,
在代码复审过程当中,$review
标记的问题要一一讨论,在代码复审事后,全部的 $review
标记要清除。在一个里程碑或正式版本发布以前,全部的 $todo
和 $bug
标记都要清除
1. 概要部分
代码符合需求和规格说明么?
代码设计是否考虑周全?
代码可读性如何?
代码容易维护么?
代码的每一行都执行并检查过了吗?
2. 设计规范部分
设计是否听从已知的设计模式或项目中经常使用的模式?
有没有硬编码或字符串/数字等存在?
代码有没有依赖于某一平台,是否会影响未来的移植(如Win32到Win64)?
开发者新写的代码可否用已有的Library/SDK/Framework中的功能实现?在本项目中是否存在相似的功能能够调用而不用所有从新实现?
有没有无用的代码能够清除?
(不少人想保留尽量多的代码,由于之后可能会用上,这样致使程序文件中有不少注释掉的代码,这些代码均可以删除,由于源代码控制已经保存了原来的老代码。)
3. 代码规范部分
4. 具体代码部分
有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常?
参数传递有无错误,字符串的长度是字节的长度仍是字符(多是单/双字节)的长度,是以0开始计数仍是以1开始计数?
边界条件是如何处理的?switch语句的default分支是如何处理的?循环有没有可能出现死循环?
有没有使用断言(Assert)来保证咱们认为不变的条件真的获得知足?
对资源的利用,是在哪里申请,在哪里释放的?有无可能存在资源泄漏(内存、文件、各类GUI资源、数据库访问的链接,等等)?有没有优化的空间?
数据结构中有没有用不到的元素?
5. 效能
代码的效能(Performance)如何?最坏的状况是怎样的?
代码中,特别是循环中是否有明显可优化的部分(C++中反复建立类,C#中 string 的操做是否能用StringBuilder来优化)?
对于系统和网络的调用是否会超时?如何处理?
6. 可读性
代码可读性如何?有没有足够的注释?
7. 可测试性
针对特定领域的开发(如数据库、网页、多线程等),能够整理专门的核查表
在开发层次,结对编程能提供更好的设计质量和代码质量,两人合做解决问题的能力更强
对开发人员自身来讲,结对工做能带来更多的信心,高质量的产出能带来更高的知足感
在企业管理层次上,结对能更有效地交流,相互学习和传递经验,分享知识,能更好地应对人员流动
总之,若是运用得当,结对编程能够取得更高的投入产出比(Return of Investment)
驾驶员:写设计文档,进行编码和单元测试等XP开发流程
领航员:审阅驾驶员的文档、驾驶员对编码等开发流程的执行;考虑单元测试的覆盖率;思考是否须要和如何重构;帮助驾驶员解决具体的技术问题
驾驶员和领航员不断轮换角色,不要连续工做超过一小时,每工做一小时休息15分钟。领航员要控制时间
主动参与。任何一个任务都首先是两我的的责任,也是全部人的责任。没有“个人代码”、“你的代码”或“他/她的代码”,只有“咱们的代码”
只有水平上的差距,没有级别上的差别。两人结对,尽管可能你们的级别资历不一样,但无论在分析、设计或编码上,双方都拥有平等的决策权利
设置好结对编程的环境,座位、显示器、桌面等都要能容许两我的温馨地讨论和工做。若是是经过远程结对编程,那么网络、语音通信和屏幕共享程序要设置好