个人作业Week2-代码复审

一、代码复审Check List

1. 概要部分

代码能符合需求和规格说明么?

代码不符合需求和规格说明。测试“-c”时,生成的数独有些不合法;测试“-s”时,解题总少解一道,且文件路径有问题(Comment)。对错误参数可以处理。但N<=1000000并没有限制

代码设计是否有周全的考虑?

每个子功能都用函数实现,并定义了一系列结构体来维护数独。

代码可读性如何?

代码可读性一般。缺少必要注释和命名规范。

代码容易维护么?

不容易维护。所有600行代码都放在一个main.cpp文件中,缺少必要注释。只有3个commit,而且代码相关都在第二个commit中。

代码的每一行都执行并检查过了吗?Comment

代码中有很多注释了的代码;我猜测是作者调试是加的,发布时又注释掉了。发布时应该删去。而且调试时临时使用的代码应该用

#ifdef DEBUG

#endif // DEBUG

包括起来。这样可以防止发布是忘记删除或分不清哪部分应该删除,而且调试时更方便。

代码覆盖测试:

-c测试

-c

-s测试

-s

2. 设计规范部分

设计是否遵从已知的设计模式或项目中常用的模式?

没有用到设计模式。

有没有硬编码或字符串/数字等存在?Comment

在对数独结构体格子的遍历过程中,使用了大量的硬解码数字,还有产生随机数的种子数组,也使用了硬编码。

代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到Win64)?

使用C++编程,并且没有使用特定平台的API或库,所以没有依赖某一平台,不影响移植。

开发者新写的代码能否用已有的Library/SDK/Framework中的功能实现?在本项目中是否存在类似的功能可以调用而不用全部重新实现?

作者自己写了统计运行时间的代码,用到了time.h库中的实现;对字符串的操作也用了相当多的string的功能实现。

此项目中不存在可以调用而不用全部重新实现的功能(或许存在而我不知道,我对各种库了解的比较少)。

有没有无用的代码可以清除?(很多人想保留尽可能多的代码,因为以后可能会用上,这样导致程序文件中有很多注释掉的代码,这些代码都可以删除,因为源代码控制已经保存了原来的老代码。)

作者注释了调试过程中使用的代码,这些在发布的时候都可以清除掉。

3. 代码规范部分

修改的部分符合代码标准和风格么(详细条文略)?

代码风格遵循统一的标准和风格;不过命名规范比较欠缺,都是由小写字母组成的单词。

4. 具体代码部分

有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常?

对错误进行了处理,可以允许处理错误的参数。对外部函数的返回值进行了检查。

参数传递有无错误,字符串的长度是字节的长度还是字符(可能是单/双字节)的长度,是以0开始计数还是以1开始计数?

参数传递无错误。字符串的长度是字节的长度,因为读写处理过程中只涉及到数字的读写,是单字节字符,所以也是字符的长度。以0开始计数。

边界条件是如何处理的?Switch语句的Default是如何处理的?循环有没有可能出现死循环?

作者对参数的大小进行了判断,保证了下界>0,但并未处理上界。而且由于算法性能比较差,上界1000000的数独生成恐怕也是做不到的。

项目中并未出现switch语句。

不可能出现死循环。作者对循环条件和循环条件的变化处理的很好。

有没有使用断言(Assert)来保证我们认为不变的条件真的满足?

没有使用。但作者确实在头文件中include了<cassert>,却并未使用。

对资源的利用,是在哪里申请,在哪里释放的?有没有可能导致资源泄露(内存、文件、各种GUI资源、数据库访问的连接,等等)?有没有可能优化?

存在一定的内存泄漏。在处理“-s”参数时,对象table1``new后并未deleteComment),不过考虑到之后程序的进程马上会终止,程序申请的内存会被全部释放,所以影响不大。但是使用完table1将其所申请释放,仍是一个好习惯。

数据结构中是否有无用的元素?

没有。所有定义的数据结构都被利用。

5. 效能

代码的效能(Performance)如何?最坏的情况是怎样的?

作者的解法是模拟人类求解数独的过程:先把可以确定唯一答案的空格填好,找不到这样的空格的时候,就找一个只有两个候选数的空格进行尝试。不断重复这两个过程,最终就可以把数独解出来(当然也可能无解)。生成数独时则先往固定的几个格子里随机填写数字,形成一个数独残局,再用解数独的方法进行求解,生成数独终局。效能分析图如下所示:

其中getcount函数更新每个单元(行、列、子宫格)每个数字(1~9)被占用的情况,是比较耗时的一个工作,使用3层循环实现。

由于程序本身的正确性存在问题。按照助教强调的优化顺序

make it work
make it right
make it fast
make it extensible
make it maintainable

程序无法right,fast也就无从谈起。

代码中,特别是循环中是否有明显可优化的部分(C++中反复创建类,C#中string的操作是否能用StringBuilder 来优化)?

作者虽然使用C++写的程序,但完全使用面向过程的设计方式,类都当结构体使用。一些函数可以改写成某个类的方法,可以增加可读性,而且写起来更容易。

对于系统和网络调用是否会超时?如何处理?

我们的这次个人项目并不需要网络调用。系统调用也只是文件的打开、读写、关闭操作,作者对其检查了返回值,做了正确的处理。

6. 可读性

代码可读性如何?有没有足够的注释?

代码可读性比较糟糕.主要体现在两点:

  • 缺少命名规范
  • 几乎没有注释; 还有有一些调试过程中加的注释, 作者并未删除

7. 可测试性

代码是否需要更新或创建新的单元测试?

作者并没有任何单元测试。需要添加对各个函数的单元测试。

还可以有针对特定领域开发(如数据库、网页、多线程等)的核查表。

我们此次个人项目不涉及任何网页、数据库、多线程(当然不排除一些大佬使用数据库和多线程),不需要任何核查表。

二、设计一个代码规范

由于我此次项目使用C#完成,所以我选择尝试StyleCop这个代码规范工具。事实上,Visual Studio本身对C#的代码规范就比较好用。可以强制你写成MSDN风格的代码,极大地提高可读性。

Visual Studio 2017自带的格式化工具

MarketPlace下载好StyleCop后,我在自己的项目上Run StyleCop,竟然报了246个Warnings。其中绝大多数是关于给文件、类、方法添加Documents和无效空格问题的。

工具提供的代码规范和你个人的代码风格有什么不同?

我个人基本上遵循MSDN风格。一是Visual Studio本身支持的比较好;二是我经常从MSDN上借鉴代码,看的多,复制粘贴起来也方便。

工具提供的代码规范更加严格,尤其是对文档和注释的要求极高。比如,每个文件、每个类、类的每个域、每个方法都要有文档注释说明。而且对于代码风格规范更加严格。比如一个被大括号包裹的语句块后再跟语句需要加个空行;using头文件必须在namespace里面,这个和MSDN默认的有所不同。

工具提供的代码规范里有哪些部分是你之前没有想到的?

  • using头文件必须在namespace里面,这个和MSDN默认的有所不同。
  • 类的每个域都要有文档头,和access modifier。

为什么要这样规范?这样的规范有意义吗?

《构建之法》第4章中讲的很清楚。现代软件工程是一个群体项目,代码要写给人看,所以一个团队要有统一的代码规范。一致的代码规范有利于团队开发和维护。

我们使用的代码规范

  • 使用驼峰命名
  • 常量以k开头
  • 用4个空格缩进
  • 需要加空格的符号后面加空格
  • 函数之间空一行
  • 每个函数和代码块前加上详细的注释
  • 有必要时在变量声明的后面加上注释
  • 所有地方都不省略大括号
posted on 2017-10-02 22:17  YoungForest  阅读(238)  评论(0编辑  收藏  举报