软件工程结对作业
软件工程结对作业
非不认真,非不努力,奈何时间所剩无几,未能提交最完美的作业
一)项目GitHub地址。
https://github.com/awfsgdf/coyg
虽然我们GitHub项目的tag提交时间很晚,但实际上我们很早就开始写代码了,只是没有注意到作业要求
二)PSP表格。
Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|
计划 | 60 | 60 |
· 估计这个任务需要多少时间 | 60 | 60 |
开发 | 1400 | 1810 |
· 需求分析 (包括学习新技术) | 120 | 60 |
· 生成设计文档 | 120 | 30 |
· 设计复审 (和同事审核设计文档) | 60 | 30 |
· 代码规范 (为目前的开发制定合适的规范) | 20 | 10 |
· 具体设计 | 120 | 240 |
· 具体编码 | 720 | 1080 |
· 代码复审 | 120 | 60 |
· 测试(自我测试,修改代码,提交修改) | 120 | 300 |
报告 | 180 | 180 |
· 测试报告 | 60 | 60 |
· 计算工作量 | 60 | 60 |
· 事后总结, 并提出过程改进计划 | 60 | 60 |
合计 | 1640 | 2050 |
三)看教科书和其它资料中关于Information Hiding, Interface Design, Loose Coupling的章节,说明你们在结对编程中是如何利用这些方法对接口进行设计的。
我们应用了信息隐藏:设置类的private参数;接口设计:尽量满足可以在任何环境调用;松耦合:由于GUI没有做出来所以没有实现。
四)计算模块接口的实现过程。
先把以a-z开头的单词分别存在26个向量中,把以a-z结尾的单词分别存在26个向量中,以这52个向量来保存图的信息,然后根据图的信息和输入的参数计算出可以作为遍历开始的点的集合,然后依次以这个集合里的点作为DFS的起点,进行深度优先搜索,找出最长单词链。其中有些细节这里不再详述,代码注释写的比较清楚。
五)UML图。
六)计算模块接口部分的性能改进。
在没有环的图中,由于图的结构比较简单,我认为爆搜全部路径是一种奢侈,于是采用了类似剪枝的方法,省去了大量肯定得不到最长路径的遍历,运行时间比较短。在有环的途中,无奈本人学艺不精,找不到更高效的方法,只能DFS爆搜,但是我发现我的爆搜过程严重超时,经过查找资料和分析代码,我发现我的DFS的问题在于它传入的无用的参数太多了,于是我把一些变量设置为类变量,不再作为参数传入,只是在调用寻找最长链的函数中声明一个类对象,这样修改之后跑同一份代码的时间竟然缩短为原来的十分之一(从十分钟缩短到到一分钟)。由此我了解到,函数传入的参数过多确实会严重影响运行效率。下图为改进之后的DFS函数爆搜100个点带环图最长单词链的性能分析图。
七)看Design by Contract, Code Contract的内容,描述这些做法的优缺点, 说明你是如何把它们融入结对作业中的。
优点是在编译的时候就可以检查程序的正确性,而且通过这种方法保证了程序的正确性;缺点是没法自由地控制契约是否生效,而且对于存在大量输入输出的函数会拖慢运行速度。
我们应用的方法是对每个模块都做正确性测试,以提升整个工程的正确性。
八)计算模块部分单元测试展示。
单元测试得到的测试覆盖率截图如下所示
(注:此部分覆盖截图和测试样例代码由我的队友提供)
char* input[4] = { (char*)"END", (char*)"OF", (char*)"THE", (char*)"WORLD" };
char* result[4] = { 0 };
gen_chain_word(input, 4, result, 0, 0, false);
char* input1[11] = { (char*)"Algebra", (char*)"Apple", (char*)"Zoo", (char*)"Elephant", (char*)"Under", (char*)"Fox",(char*) "Dog", (char*)"Moon", (char*)"Leaf",(char*)"Trick",(char*) "Pseudopseudohypoparathyroidism" };
char* result1[11] = { 0 };
gen_chain_word(input1, 11, result1, 0, 0, false);
char* input2[11] = { (char*)"Algebra", (char*)"Apple", (char*)"Zoo", (char*)"Elephant", (char*)"Under", (char*)"Fox", (char*)"Dog",(char*) "Moon",(char*) "Leaf",(char*)"Trick", (char*)"Pseudopseudohypoparathyroidism" };
char* result2[11] = { 0 };
gen_chain_char(input2, 11, result2, 0, 0, false);
char* input3[5] = { (char*)"Element", (char*)"heaven", (char*)"Table",(char*) "Teach", (char*)"Talk" };
char* result3[5] = { 0 };
gen_chain_word(input3, 5, result3, 0, 0, true);
char* input4[5] = { (char*)"Element", (char*)"heaven", (char*)"Table",(char*) "Teach", (char*)"Talk" };
char* result4[5] = { 0 };
gen_chain_char(input4, 5, result4, 0, 0, true);
char* input5[11] = { (char*)"Algebra", (char*)"Apple", (char*)"Zoo", (char*)"Elephant", (char*)"Under", (char*)"Fox", (char*)"Dog",(char*) "Moon",(char*) "Leaf",(char*)"Trick", (char*)"Pseudopseudohypoparathyroidism" };
char* result5[11] = { 0 };
gen_chain_word(input5, 11, result5, 'a', 0, false);
char* input6[11] = { (char*)"Algebra", (char*)"Apple", (char*)"Zoo", (char*)"Elephant", (char*)"Under", (char*)"Fox", (char*)"Dog",(char*) "Moon",(char*) "Leaf",(char*)"Trick", (char*)"Pseudopseudohypoparathyroidism" };
char* result6[11] = { 0 };
int len = gen_chain_char(input6, 11, result6, 'a', 0, false);
char* input7[11] = { (char*)"Algebra", (char*)"Apple", (char*)"Zoo", (char*)"Elephant", (char*)"Under", (char*)"Fox", (char*)"Dog",(char*) "Moon",(char*) "Leaf",(char*)"Trick", (char*)"Pseudopseudohypoparathyroidism" };
char* result7[11] = { 0 };
gen_chain_word(input7, 11, result7, 0, 'n', false);
char* input8[11] = { (char*)"Algebra", (char*)"Apple", (char*)"Zoo", (char*)"Elephant", (char*)"Under", (char*)"Fox", (char*)"Dog",(char*) "Moon",(char*) "Leaf",(char*)"Trick", (char*)"Pseudopseudohypoparathyroidism" };
char* result8[11] = { 0 };
gen_chain_char(input8, 11, result8, 0, 'n', false);
char* input9[5] = { (char*)"Element", (char*)"heaven", (char*)"Table",(char*) "Teach", (char*)"Talk" };
char* result9[5] = { 0 };
gen_chain_word(input9, 5, result9, 't', 0, true);
char* input10[5] = { (char*)"Element", (char*)"heaven", (char*)"Table",(char*) "Teach", (char*)"Talk" };
char* result10[5] = { 0 };
gen_chain_char(input10, 5, result10, 't', 0, true);
char* input11[5] = { (char*)"Element", (char*)"heaven", (char*)"Table",(char*) "Teach", (char*)"Talk" };
char* result11[5] = { 0 };
gen_chain_word(input11, 5, result11, 0, 'n', true);
char* input12[5] = { (char*)"Element", (char*)"heaven", (char*)"Table",(char*) "Teach", (char*)"Talk" };
char* result12[5] = { 0 };
gen_chain_word(input12, 5, result12, 0, 'n', true);
char* input13[5] = { (char*)"aa", (char*)"aaa", (char*)"aaaa", (char*)"aaaaa", (char*)"a" };
char* result13[5] = { 0 };
gen_chain_word(input13, 5, result13, 0, 0, true);*/
char* input14[11] = { (char*)"Algebra", (char*)"Apple", (char*)"Zoo", (char*)"Elephant", (char*)"Under", (char*)"Fox", (char*)"Dog",(char*) "Moon",(char*) "Leaf",(char*)"Trick", (char*)"Pseudopseudohypoparathyroidism" };
char* result14[11] = { 0 };
gen_chain_word(input14, 11, result14, 'a', 'k', false);
char* input15[11] = { (char*)"Algebra", (char*)"Apple", (char*)"Zoo", (char*)"Elephant", (char*)"Under", (char*)"Fox", (char*)"Dog",(char*) "Moon",(char*) "Leaf",(char*)"Trick", (char*)"Pseudopseudohypoparathyroidism" };
char* result15[11] = { 0 };
gen_chain_word(input15, 11, result15, 's', 's', false);
九)计算模块部分异常处理说明。
异常处理函数 | 功能 | 异常样例 |
---|---|---|
void check_h_and_t(char head, char tail, bool have_head, bool have_tail); | 检查是否存在head开头和tail结尾的单词 | 输入的单词列表为{"hello", "world" , "yes"},而命令行窗口输入的参数包含-h a -t b |
void check_file(); | 检查输入单词文件的路径是否正确 | 输入的文件路径错误或者没有路径指定文件 |
void check_loop(bool enable_loop, int size); | 检查输入的单词列表有无环是否和-r参数匹配 | 输入的单词列表为{"hello", "olleh", "yes"},而命令行窗口输入的参数不包含-r |
void check_null(char *word); | 检查传入的char *word[]里是否有空指针 | 输入的单词列表char *[]在下标0到下标len-1这些元素之间有空指针 |
void check_char(int i); | 检查传入的单词列表里是否都是英文单词 | 输入的单词列表为 |
void check_void(int len); | 输入的单词列表的单词数量是否小于2 | 输入的单词列表为 |
void check_2(); | 检查搜索到的单词链的单词数量是否小于2 | 搜索到的单词链为 |
void check_same(); | 检查输入的单词列表中是否有重复的单词 | 输入的单词列表为 |
int find_arg(int argc, char *argv[], arg &w, arg &c, arg &h, arg &t, arg &r, char &head, char &tail); | 检查传入的参数组合是否出错,如果出错,以int形式返回错误的类型以便分情况报错 | 输入的参数不包含-w且不包含-c,返回int类型数据4 |
十)界面模块(如果没有实现GUI,则可以描述命令行模块)的详细设计过程。
参数的定义和作业要求一致,当参数输入不符合逻辑时会报相应错误,例如-w和-c同时出现,-w和-c同时未出现,-h参数错误,-t参数错误,源文件不存在等等。
十一)界面模块(GUI或命令行模块)与计算模块的对接。
以下是命令行运行.exe文件的截图。
十二)描述结对的过程,提供非摆拍的两人在讨论的结对照片。
结对不是一个容易的过程,由于种种原因,我和队友没有很长的时间可以结对编程,因此程序的代码部分是我一人编写,只是在最后两天编写测试用例、对接GUI的时候我们一起结对编程了一段时间,但是由于除了编写代码之外的后续工作开展的太晚导致我们最终提交的项目并不完美,但是我已经对自己满意。在写这次作业的过程中,我既体会到了单人爆肝的辛苦,也体会到了结对编程的乐趣,可以说做这次作业的过程是一种历练。
十三)看教科书和其它参考书,网站中关于结对编程的章节,说明结对编程的优点和缺点。结对的每一个人的优点和缺点在哪里 (要列出至少三个优点和一个缺点)。
结对编程的优点:
1)可以互相督促,不会纵容某一方拖延
2)一边写代码一边有人监督不易出错
3)两个人可以经常交流,分享知识。
结对编程的缺点:
1)可能还是会让人不太适应吧。
我的优点:
1)比较认真
2)比较刻苦
3)比较爱学习
我的缺点:
1)没有给予队友足够帮助
我的结对对象优点:
1)比较刻苦
2)做事比较有条例
3)求知欲比较强
我的结对对象缺点:
比较不守时,没有按时完成任务。
十四)在你实现完程序之后,在附录提供的PSP表格记录下你在程序的各个模块上实际花费的时间。
表格见上文。