1. 是否需要有代码规范
对于是否需要有代码规范,请考虑下列论点并反驳/支持:
Statement1 : 这些规范都是官僚制度下产生的浪费大家的编程时间、影响人们开发效率, 浪费时间的东西。
这样的观点未免太过于肤浅且自我主义。
首先,之所以产生这样的结论,一方面是因为仅看到团队成员适应团队规范的不便性所带来的损失。
把目光放长远一点,每个人的compromise都会大大提高整体代码的规范性、整洁性与清晰度。
这样的代码无论对于复审、二次开发、调试测试、后期维护等来说都是十分有利的。
大家在同一个规则下编写代码,虽然增加了编写过程中适应规则的时间,但更值得一提的是,这种前期的coding adaption大大降低了后期的composing/reviewing adaption所需时间。
而后期对代码的审核调试,代码与模块之间的拼凑,这两个步骤如果没有前期的规范为基础,那磨合所需的时间会远远超出前期所浪费的时间。
而且前期的浪费是不过分需要人力脑力的,相反后期的浪费将要调用所有团体人员对代码进行解释、修改、审核等。
其次,产生这种想法往往是过于egoism的典型表现,仅仅考虑到自身的不便却忽视了软件工程是一个团体性的任务。
各个分量的局部最优拼凑出来的往往不是全局最优。在最优化过程中,而每个局部都reconcile其它因素才能达到团体利益的最大化,在软件工程中也是如此。
Statement2 : 我是个艺术家,手艺人,我有自己的规范和原则。
编程是一门艺术,这点不可否认。对于个人的编程而言,coding的规范和原则确实构成了展现代码特性的重要一环。
但正如上述1中所说,这是一个团队性的任务,而在这种环境下,编程的艺术更讲究和谐与一致。
如何让各个模块相互协调,让零散不一的零件组合成最终流畅运行的整体,以及让团队中的每一个大脑都能参与并以最舒服的方式进行brainstorm,这些才是团队编程中的艺术。
它与个人的狂想不同,在团队的编程艺术中,你需要作出一定的牺牲,舍弃原本保持的风格(当然这种舍弃也不是绝对的,团队间的协商可以最大程度减少它)。
更关键的一点,我们所舍弃的仅仅是外在的习惯,而编程艺术强调的不仅仅是外在表现形式,更多的是我们的逻辑思维、组织方式和奇思妙想。
从这一角度出发,我们实际上并没有舍弃自己的艺术。与其说是舍弃了自己的规范和原则,不如说是将自己编程艺术的本质用团队的语言做了一次不一般的演讲。
Statement3 : 规范不能强求一律,应该允许很多例外。
这一想法需要进一步的限制与说明,所谓的“例外”是什么样的例外?是在设计创新上的例外,还是在命名规则、模块设计等方面的例外?
若是前者,那团队自然不应进行限制,除非客户有具体明确的需求,不然任何能达到要求甚至超过要求的代码都是值得考虑的。
若是后者,那团队在初期必须要有明确的规范,否则会给后期的相互调用模块、复审代码、调试测试以及二次开发带来诸多不便,降低整体效率。
也许会有部分相反的观点,认为像代码的一些细节,比如括号位置、操作符两端的空格、是否要对长语句进行断行等,可以按照各人的习惯来,认为这些细节并不会对团队工作有较大的影响,用专门的团队规范来限制显得多余。
然而实际上不然,举个例子,括号的位置看似在行尾和行首怎么样都行,但各有各的好处。
在行尾可以压缩代码篇幅,让代码看起来更简洁紧凑,同样大小的屏幕能够容纳下更多代码(相信很多人编程时都恨不得将电脑竖过来看代码,由此可推断若能容纳更多代码能一定程度上提高开发效率);
而在行首则能让代码结构更清晰明了,各个代码模块的层次嵌套关系一目了然。
团队需要根据自身需求来规范这些细节,否则即使是细节的不同,也会导致整个工程看起来杂乱无章,在各种pattern中切换必然会降低开发效率。
但后者也并不是否认了所有人的规范,前期的商榷过程是十分关键的,如何确定一个所有人都满意,最大程度减小每人规范舍弃的原则,这个问题值得前期认真考虑。
经过这种商榷后,诸多人的“例外”已经被包含进了团队规范中。在这一层面,团队规范并没有强求一致。
Statement4 : 我擅长制定编码规范,你们听我的就好了。
软工需要一个leader但不是专制主义者,正如前面所一直强调的那样,一个团队规范要能够最小化所有人的损失,而这样的专制明显无法达到要求。
首先明显的一点,专制必然无法满足大部分团队成员的需求。不考虑多重因素直接得到的规范很难让团队效率最大化。
其次,一味地将个人的偏见强加至所有人身上难免会造成团队内部的不和谐,降低团队效率不说,更可能导致整个团队的分裂。
最后,这种行为将会扼杀团队的创新进取精神。一旦形成了这种专制风气,很有可能使团队成员因不满而拒绝贡献自己创新性的想法。
整个团队变得死气沉沉,甚者可能会变成仅由专制者一人的思维领导的群体,失去了一个团队的意义。
2. 代码复审
Code Review Checklist |
|
General |
|
· Does the code work? Does it perform its intended function, the logic is correct etc. |
· 代码可以正常运行。实现了用户需求中的所有功能(至少测试过程中未发现异常) |
· Is all the code easily understood? |
· 代码结构划分较为清晰。实现了主要三个类分别用于表示表达式、分数以及IO处理。代码中有一处相对而言较晦涩难懂,即在生成表达式过程中如何确定这个项是否是Notation类型(详情请见http://www.cnblogs.com/kanelim/p/4830963.html)。需要建立两个List用于记录可用的Notation以及先前用过的Notation,以便于直接获取Notation以及返回先前状态。 |
· Does it conform to your agreed coding conventions? These will usually cover location of braces, variable and function names, line length, indentations, formatting, and comments. |
· 因为复审的是自己的代码,所以完全一致 |
· Is there any redundant or duplicate code? |
· 大部分子功能代码都已经模块化,暂未发现多余代码。 |
· Is the code as modular as possible? |
· 代码已经将输入输出、表达式、分数等不同功能做了划分。但复审过程中觉得Main函数为了处理输入情况导致条件判断比较臃肿,可以进一步模块化。 |
· Can any global variables be replaced? |
· 用C#编写,无全局变量一说,仅由一些类中的静态成员用于辅助功能实现,不可替代。 |
· Is there any commented out code? |
· 有,部分前期开发时的过时算法,以及用于调试的代码。 |
· Do loops have a set length and correct termination conditions? |
· 有。且测试过程中未发现无限循环的情况。 |
· Can any of the code be replaced with library functions? |
· 所有能用库函数实现的均已使用库函数。 |
· Can any logging or debugging code be removed? |
· 调试用代码已经注释。 |
Security |
|
· Are all data inputs checked (for the correct type, length, format, and range) and encoded? |
· 对第一个功能生成表达式而言,对输入格式做了较强的判断,但没有对内容做过多的语义判断,如可能输入“-n -100 -r 3”这样非法的内容。在这一方面还需要改进。在字符串长度也未限制。在判断指令后有对输入内容重新编码为程序需求的数据结构。 · 对第二个功能判分而言,仅默认每个表达式都是符合规范的(详见第一次作业需求的前提条件),未进行安全性检查。 |
· Where third-party utilities are used, are returning errors being caught? |
· 未使用第三方工具;程序中的诸多函数虽然有返回异常值,但是未对异常情况进行处理,如:calcPriority(),因为用户需求默认输入是合法的,因此无需做处理。 |
· Are output values checked and encoded? |
· 输出的表达式进行了除数是否为0和减法是否为负数的审查,并且用ToString()函数对存储于Expression中的表达式编码后输出。 |
· Are invalid parameter values handled? |
· 未处理。同上,大部分函数默认用户输入是合法的。并且用户输入在main函数中已经判断了合法性,在传参时也认为是合法的。 |
Documentation |
|
· Do comments exist and describe the intent of the code? | · 每一个函数前都有overall review。但在函数内部的comment较少,这点需要进一步改进。 |
· Are all functions commented? | · 每一个函数前都已注释。 |
· Is any unusual behavior or edge-case handling described? |
· 未对边缘情况进行注释说明,程序注释量较少。 |
· Is the use and function of third-party libraries documented? | · 使用的第三方接口都是C#系统命名空间中常用的,因此未进行说明。 |
· Are data structures and units of measurement explained? | · 在Expression中对数据结构和存储模式进行了解释,但未对测量单元进行解释。 |
· Is there any incomplete code? If so, should it be removed or flagged with a suitable marker like ‘TODO’? | · 无未完成的代码。 |
Testing | |
· Is the code testable? i.e. don’t add too many or hide dependencies, unable to initialize objects, test frameworks can use methods etc. | · 单独子模块和整个程序都是可以测试的,构造测试所需的context并不是很麻烦。 |
· Do tests exist and are they comprehensive? i.e. has at least your agreed on code coverage. | · 项目中无测试代码。 |
· Do unit tests actually test that the code is performing the intended functionality? | · 项目中无测试代码。 |
· Are arrays checked for ‘out- of-bound’ errors? | · 由于大部分数组都是定长且都被赋值使用,所以大部分未进行越界检测。除了部分字符串分割后的结果做了处理。 |
· Could any test code be replaced with the use of an existing API? | · 所有功能都已经用现存的子模块进行代替。 |