个人作业-Week2


一、代码复审Checklist

1.概要部分

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

本次作业的需求可以分成基本的功能实现和大规模数据下程序的健壮性,以及少量的异常处理能力,也就是说我们可以通过一般功能测试压力测试和少量的鲁棒性测试来进行测试。

程序的测试结果首先参考了2017BUAA软工助教 个人项目测试结果

测试-c的结果如下图:

NumberID -c 1 -c 5 -c 100 -c 500 -c 1000 -c 50000 -c 1000000
15061104 0.9 0.117 0.218 0.76 1.326 60.102 -8

测试-s的结果如下图:

NumberID -s 1.txt -s 5.txt -s 100.txt -s 500.txt -s 1000.txt -s 50000.txt -s 1000000.txt
15061104 0.148 0.2 2.637 12.7 25.165 -2 -4

接下来分别说明这些测试的结果。

  • 一般功能测试

    测试结果显示,程序在可以完成少量数据规模下解决问题的需求,这里不再赘述。
  • 压力测试

    测试结果显示,程序在生成1million个数独的时候无法生成足够的数独。我在自己的PC上进行了同样的测试,即输入:
suduku.exe -c 1000000

等待10分钟无果。

  • 异常数据

    我设计了若干测试样例,它们的说明和测试结果见下表:
样例 语句 说明 预期结果 实际结果
case1 sudoku.exe -c asd 参数非法 退出并报错 报错并退出
case2 sudoku.exe -c 0 边界值 退出并报错,或者sudoku.txt为空 报错并退出
case3 sudoku.exe -c -1 参数越界 退出并报错 报错并退出
case4 sudoku.exe -c 10000000 参数越界 退出并报错 报错并退出
case5 sudoku.exe -s nonexist.txt 文件不存在 退出并报错 退出
case6 sudoku.exe -s nosolution.txt 文件中数独不可解 退出并报错 sudoku.txt中生成全0数独
case7 sudoku.exe -s 参数不够 退出并报错 报错并退出
  • 总结

    总的来说,程序能够完成基本的需求,但是程序不能在大规模数据下保持健壮性,同时对于少数异常不能很好的处理。

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

根据1.1中的测试结果可知,程序在考虑设计上有些欠妥当。

1.3 代码可读性如何?

从代码的:层次结构注释的详尽程度注释的易读程度变量的命名清晰度来分析。

  • 层次结构

    优点:作者使用的是DLX算法,代码大部分采用了OO的风格,代码中大致包括DLXNode,DLXGenerator,DLXSolver,SudokuLoader,SudokuSolver,这些类的划分比较清晰易懂,从main函数开始的层次结构也比较清楚。

    缺点:Issue1(1)main.cpp中的几个函数solvePuzzle、createSudoku等很有面向过程的风格,很让人困惑,也许更好的方法是把这些函数封装到相关类的方法中。(2)程序的输出由类SudokuLoader来实现,这个功能明显和这个类的命名有冲突,也许可以新建一个SudokuOutput类来处理。

  • 注释的详尽程度

    优点:程序对大部分方法都有简略的说明,在一些具体的算法步骤上也有说明,有一定的可读性。

    缺点:程序对类的说明较少,也许可以对每个类加一个简要的注释来说明其职责、可变性等。

  • 注释的易读程度

    较好,没有生僻词。虽然方法只有说明没有具体的例子,但因为本次作业比较简单,所以不需要也可以读懂。

  • 变量的命名清晰度

    比较清晰,基本能从名字中了解到变量的功能。

  • 总结

    总体来说,代码可读性较高,但在结构设计和类的功能划分上仍有部分细节有些混乱。

1.4 代码容易维护么?

可维护性主要是指代码是否能适应各种各样的变化,这次作业结构比较简单,所以总体来说问题不大。

不过测试代码中用到了itoa函数,这个函数在linux中不可用,会导致程序的可维护性降低。见Issue5

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

除了一些冗余的代码,基本可以全部覆盖,冗余代码的说明在2.5节。


2.设计规范部分

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

没有特定的设计模式。

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

存在。Issue3

在SudokuLoader::writeToFile函数中使用了硬编码:

char content[19 * 9 + 2];

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

代码本身没有影响,但是测试代码中含有itoa会影响移植到linux之后的测试。

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

基本没有,由于使用了DLX,其中的一些基本操作和数据结构需要重新定义。

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

有:

void solveWithAllAnswers(DLXNode *listHead, vector<int>& tempSolution, vector<vector<int>>& lastSolution, int depth);

这个方法的定义和代码都可以删除。Issue4


3.代码规范部分

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

代码基本有统一的风格,问题已经在之前阐述过。


4.具体代码部分

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

内部的异常处理在1.1中阐述过。

对于外部操作,在用fstream来操作文件的时候,有如下代码:

 if (strcmp(argv[1], "-s") == 0) { //Solve puzzle from file
fstream puzzleFile;
puzzleFile.open(argv[2], ios::in);
solvePuzzle(puzzleFile);
puzzleFile.close();
} else if (strcmp(argv[1], "-c") == 0 && atoi(argv[2]) > 0 && atoi(argv[2]) <= sudokuMaximum) { //Create puzzle file
fstream sudokuFile;
sudokuFile.open("sudoku.txt", ios::out);
createSudoku(sudokuFile, atoi(argv[2]));
sudokuFile.close();
} else {
reportError();
}

这里在打开文件之后没有检查文件是否打开,建议使用is_open()方法来检查是否打开。

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

  • 无错误。
  • 字节的长度,其中只涉及到ascii码,不涉及双字节字符。
  • 从0开始计数。

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

  • 边界条件1.1中测试过,基本没有问题。
  • 没有Switch语句
  • 除了一个while循环,其他函数都是for循环的形式,while循环的判断式中的变量在循环体内自增,所以没有死循环,for循环的限定条件和变量的增减都有明确的定义,所以没有可能出现死循环。

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

没有

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

代码中有3次用new关键字进行的资源的申请,下面是其中一处:

SudokuSolver solver = SudokuSolver();
DLXNode* listHead = new DLXNode();
vector<int> answer;

这三处申请都没有释放。

考虑到申请的不是数组,并且是有限次申请,所以导致资源泄露的可能性比较小。

但还是建议应该在程序结束之后释放相应的资源。

由于是有限的new,所以优化的空间比较小。

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

没有,DLXNode中定义的成员都有明确的使用目的。


5.效能

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

在1.1中我们看到,代码的效能比较不尽人意,生成50000个数独就要60秒,而解50000个数独的时候没有生成相应的文件。

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

没有,程序的热路径都在DLX的递归调用上。

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

会超时,判断应该是算法递归层数加深变得无法处理,应该进一步优化算法。


6.可读性

1.3中已经有过阐述,总体来说比较易读,推荐对每个类进行简单的功能和性质说明。


7.可测试性

作者基于简单的数据规模测试了3个核心的功能函数,即和生成和求解数独有关的3个函数。

但这样测试的粒度过大,会导致发生错误的时候定位难,同时测试中也没有包括一些异常检测和压力测试。

建议添加相应的测试,并将核心方法分解成更细粒度的方法进行测试。


二、设计一个代码规范

1.cpplint提供的代码规范和自己代码规范的不同

(1)是否添加copyright

(2)在include .h头文件的时候应该声明相应的路径

(3)建议使用using-declarations,举例来说就是,把cout替换成std::cout。

(4)用int64而不是long,long是c中的类型

(5)//和注释之间应该有一个空格

(6)建议采用K&R风格的大括号,我的代码中大部分使用这个风格,只有定义函数的时候会把包围函数的左大括号换行,cpplint中也只是使用了'almost'这个词来限定这条规则

(7)用空格来代替tab

(8)’,‘之后应该空格

(9)行结束之前有多余的空格

(10)else放在if的有大括号之后

(11)代码块结束之后有冗余的空行

2.之前没想到的规范以及规范意义的思考

(1)添加copyright

加作者还是比较有必要的,毕竟是自己的劳动成果。

(2)声明.h文件的时候应该声明相应的路径

这条没想到过,不过思考了一下确实有一定的必要性,会避免一些二义性问题。

(3)using-declarations

这个规则在有多个命名空间的时候很重要。

(4)用int64而不是long

C++下应该统一使用C++的类型

(5)//和注释之间应该有一个空格

这个应该影响不大

(6)空格代替tab

这个问题在构建之法中也提到过,会影响程序的可读性,之前没有注意,之后会改进。

(7)’,‘之后应该空格

之前没有想到,但似乎不影响可读性就可以。

(8)行结束之前有多余的空格

这个问题没有想到,但是其中的意义有什么意义呢?

(9)代码块结束之后有冗余的空行

同(8),这个规则是为了让代码块更紧凑吗?

3.自己设计的代码规则

我和partner商量之后定下了下面的规则:

风格规范:

  1. 缩进格式:4个空格

  2. 行宽:80个字符

  3. 左括号位置:K&R风格

  4. 命名风格:小驼峰式命名

  5. 长语句的换行:不影响可读性即可

  6. 指针声明格式:星号紧挨类型

  7. public / protected / private 顺序

  8. return之后的表达式是否加圆括号:必要时才加括号

  9. 命名空间内代码是否缩进:不缩进

  10. 水平留白:运算符前后留白,函数的参数之间不留白

  1. 垂直留白:函数之间留白不超过一行,函数体内留白处加注释

  2. 注释:每个函数加注释

设计规范:

  1. 是否支持goto语句:不支持

  2. 是否支持struct:不支持

  3. 是否支持运算符重载:不支持

  4. 变量定义与初始化是否同时完成:是

[buaa-SE-2017]个人作业-Week2的更多相关文章

  1. BUAA SE 个人项目作业

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人项目作业 我在这个课程的目标是 通过个人项目实践熟悉个人开发流程 一.在文章开头给出教学班级和 ...

  2. 集大软件工程15级个人作业Week2

    集大软件工程15级个人作业Week2 快速通读教材<构建之法>,并参照提问模板,提出5个问题. 在每个问题后面,请说明哪一章节的什么内容引起了你的提问,提供一些上下文 列出一些事例或资料, ...

  3. BUAA软件工程个人项目作业

    BUAA软件工程个人项目作业 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人项目作业 我在这个课程的目标是 学习软件开发的流程 这个作业在哪 ...

  4. BUAA 2020 软件工程 热身作业

    BUAA 2020 软件工程 热身作业 Author: 17373051 郭骏 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 第一次作业-热身! ...

  5. BUAA软件工程结对项目作业

    BUAA软件工程结对项目 小组成员:16005001,17373192 1.教学班级和项目地址 项目 内容 这个作业属于哪个课程 博客园班级连接 这个作业的要求在哪里 结对项目作业 我在这个课程的目标 ...

  6. BUAA SE | 提问回顾与个人总结

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 提问回顾与个人总结 我在这个课程的目标是 深入理解软件工程 这个作业在哪个具体方面帮助我实现目标 ...

  7. 个人作业-week2:关于微软必应词典的案例分析

    第一部分 调研,评测 评测基于微软必应词典Android5.2.2客户端,手机型号为MI NOTE LTE,Android版本为6.0.1. 软件bug:关于这方面,其实有一些疑问.因为相对于市面上其 ...

  8. 个人博客作业week2——代码复审

    1.代码规范 这些规范都是官僚制度下产生的浪费大家的编程时间.影响人们开发效率, 浪费时间的东西. 代码规范并不是从官僚制度下产生,它是为了提高项目团队开发效率而产生的一种工具,能够极大的增强代码可读 ...

  9. 团队作业week2

    软件分析和用户需求调查 (2013) 具体内容参看邹欣老师的博客:http://www.cnblogs.com/xinz/p/3308608.html. 作业提交期限:2013年9月25日上课前.

随机推荐

  1. Ext4文件系统架构分析(二)

    接着上一篇博文,继续分析Ext4磁盘布局中的元数据. 1.7 超级块 超级块记录整个文件系统的大量信息,如数据块个数.inode个数.支持的特性.管理信息,等待. 如果设置sparse_super特性 ...

  2. UITapGestureRecognizer 的用法(轻触手势识别器)

    最近在项目中用到了手势操作,键盘回收时还是挺常用的,现在总结下,多谢网络上大神们的分享. 先分享下我在项目中用的代码: UITapGestureRecognizer * mytap=[[UITapGe ...

  3. block本质探寻八之循环引用

    说明:阅读本文,请参照之前的block文章加以理解: 一.循环引用的本质 //代码——ARC环境 void test1() { Person *per = [[Person alloc] init]; ...

  4. laravel5.5源码笔记(八、Eloquent ORM)

    上一篇写到Eloquent ORM的基类Builder类,这次就来看一下这些方便的ORM方法是如何转换成sql语句运行的. 首先还是进入\vendor\laravel\framework\src\Il ...

  5. uva 1590 - IP Networks(IP地址)

    习题4-5 IP网络(IP Networks, ACM/ICPC NEERC 2005, UVa1590) 可以用一个网络地址和一个子网掩码描述一个子网(即连续的IP地址范围).其中子网 掩码包含32 ...

  6. go语言实战笔记(二)

     码代码之前一定要安装go,哈哈哈哈,反正我只装goland然后写不了代码报错,卡在第一段代码哈哈哈哈哈哈 新建项目goproject 新建src文件夹 新建main文件夹 新建第一个go文件 开始写 ...

  7. 复制文件到IDE等工具出现乱码解决方案

    首要的解决方案是设置文件或者项目或者工作空间的编码,可以采用在文件上.项目上右键->properties进行设置 第二种方式是在editplus等编辑器里打开文件,然后打开文件之后点击菜单Fil ...

  8. 复制web项目时注意修改web项目名

    改web项目的项目名可以右击->properties->搜索web找到settings->修改context name

  9. Android开发——布局性能优化的一些技巧(二)

    , 0, drawable.getMinimumWidth(),dra.getMinimumHeight()); tv.setCompoundDrawables(null, null, drawabl ...

  10. 传统路由和OVS区别

    本文主要描述了一种将三层路由变成二层交换转发(以及二层转发变成三层路由)的实现方式,以应对OVS(OpenFlow)跨网段路由复杂的问题:当然技术本身是客观的,具体应用还要看场景. 随着SDN技术不断 ...