软工结对编程作业
项目 | 内容 |
---|---|
这次作业属于哪个课程 | 软件工程 |
这次作业的要求在哪 | 结对编程作业 |
本次项目的github地址
PSP表格(开发前)
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
.Estimate | 估计这个任务需要多少时间 20001970 | ||
Development | 开发 | ||
.Analysis | 需求分析 (包括学习新技术) | 240 | |
.Design Spec | 生成设计文档 | 180 | |
.Design Review | 设计复审 (和同事审核设计文档) | 120 | |
.Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | |
.Design | 具体设计 | 200 | |
.Coding | 具体编码 | 450 | |
.Code Review | 代码复审 | 240 | |
. Test | 测试(自我测试,修改代码,提交修改) | 240 | |
Reporting | 报告 | ||
.Test Report | 测试报告 | 180 | |
.Size Measurement | 计算工作量 | 30 | |
·Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 |
Sum |合计 |1970|
接口设计
Information Hiding, Interface Design, Loose Coupling,指的就是信息隐藏,接口设计,松散耦合这几个方面。
Information Hiding的概念最初由David Parnas在Parnas(1972)中描述,在此之前,Richard Gauthier和Stephen Pont在其1970年出版的“ 设计系统程序”一书中对模块化进行了讨论。Information Hiding, Interface Design作为将任何设备,软件或硬件划分为功能模块的有效标准。例如,汽车是一种复杂的设备。为了使汽车的设计,制造和维护合理,将复杂的设备分成具有隐藏设计决策的特定接口的模块。通过以这种方式设计汽车,汽车制造商还可以提供各种选择,同时仍然具有制造经济的车辆。Information Hiding, Interface Design提供了灵活性。这种灵活性允许程序员在正常演进期间修改计算机程序的功能,因为计算机程序被改变以更好地适应用户的需要。当计算机程序设计得很好时,使用信息隐藏原理将源代码解决方案分解为模块,进化变化更容易,因为变化通常是局部变化而不是全局变化。
所以我们的设计方案主要就是对类的变量进行私有封装,不让其暴露出来,其次为调用私有变量和修改提供特殊的接口。其次就是对每一个命令行参数的处理封装成函数,便于调用,提供标准化的接口。
计算模块接口的设计与实现过程
st=>start: main函数入口
e=>end
op=>operation: 处理命令行参数状态机
cond=>condition: 是否有环?
op2=>operation: 拓扑排序及动态规划(类)
op3=>operation: dfs暴力搜索(类)
st->op->cond
cond(yes)->op3
cond(no)->op2
整体思路
我们没有写这个正则表达式来匹配所有的命令行参数,因为参数个数较少,组合情况不多,所以我们采取了有限状态机的方式来识别所有的命令选项。然后根据这个图是否有环调用相应的类去处理。对单词文本的处理是将输入的一个个单词当作图上的一个个点进行处理,采用邻接矩阵来储存边与边之间的距离,距离为被指向单词的长度
无环类:主要是一个类,运用了拓扑排序和动态规划的思想,寻找最长路径。
有环类:这个也是一个类,这部分是我写的,我主要就是DFS遍历图,暴力搜索寻找最长路径。
UML类图
VS自动生成的类图如下:
由图我们可以看出,我们主要是实现了一个公共接口类,分别在有环和无环类中实现了这个处理-w和-r的函数实现。
计算模块接口部分的性能改进
我们小组开始没有对搜索进行优化,所以说有时候进行了大量的无用搜索。我们主要对这个拓扑排序进行了优化,减少了很多不必要的搜索。其次就是在处理-r参数时,我们先判断了图,如果没有环,仍然调用拓扑排序来做。这样就减少了很多时间开销。我们这个改进大概总共花费了6个小时吧
Design by Contract感想
Design by Contract, Code Contract就是指合同化编程,契约式设计。契约式设计就是按照某种规定对一些数据等做出约定,如果超出约定,程序将不再运行,例如要求输入的参数必须满足某种条件。契约式设计的核心概念就是前置条件,后置条件和不变式,这种方式的好处是可以避免很多bug,减少调试的时间,这个我们大二下OO的JSF要求差不多了。但是这种方式设计起来过于繁琐,每一个函数设计起来费时费力。
所以说,我们并没有采取这种方式,而是采取了函数内检查的形式。
单元测试
没有封装成core接口,所以测试不好做。
TEST_METHOD(TestMethod1)
{
string xx = "test.txt";
ProcessNoRing p = ProcessNoRing(xx);
p.init();
p.getWord(xx);
Assert::AreEqual(2, p.wordNum);
}
异常处理说明
-输入文件不存在
例如输入111.txt,但是在这个目录下没有这个文件,会报错:open file failed!!!
-输入的单词数量过多
例如输入五百个以上不同的单词的文件,会报错:too many words!!!
-输入了有环的指令但图中没有环
报错:topologicalSort successed! 表示可以拓扑排序,图中无环
-输入了无环的指令但图中有环
报错:topologicalSort failed! 表示不可以拓扑排序,图中有环
-输入的首字母有除了字母之外的字符出现
报错:illegimate input as first char X(表示错误的字符)
-输入的尾字母有除了字母之外的字符出现
报错:illegimate input as last char X(表示错误的字符)
-输入的某个单词自身首尾相同
不会报错,不会自身成环
-输入单个字母的单词
不会报错,视为正常单词
界面模块的详细设计过程
这个主要就是运用状态机的知识来处理这个命令行参数。
主要函数有下面三个
void FirstState(char *argv[]);
void SecondState(char *argv[]);
void ThirdState(char *argv[]);
这个主要就是识别到-r进入第一个状态,然后识别到-h或者-t进入第二个状态,最后-w,-c进入第三个状态。
在这个过程中,我们会把一些参数转为bool型变量。
void FirstState(char *argv[]) {
if (strcmp(argv[ArgvCnt], "-w") == 0 || strcmp(argv[ArgvCnt], "-c") == 0) {
process = strcmp(argv[ArgvCnt], "-w") == 0 ? 0 : 1;
ArgvCnt++;
ThirdState(argv);
}
else if (strcmp(argv[ArgvCnt], "-h") == 0 || strcmp(argv[ArgvCnt], "-t") == 0) {
ProStart = strcmp(argv[ArgvCnt], "-h") == 0;
ProEnd = strcmp(argv[ArgvCnt], "-t") == 0;
ArgvCnt++;
if (strlen(argv[ArgvCnt]) == 1 && isalpha(argv[ArgvCnt][0])) {
StartWord = argv[ArgvCnt][0];
EndWord = argv[ArgvCnt][0];
ArgvCnt++;
SecondState(argv);
}
else {
ErrorPrint(argv);
}
}
else {
ErrorPrint(argv);
}
}
部分函数如上所示。
界面模块与计算模块的对接。
int EnalbleLoop; //是否允许单词环 (0不允许,1允许)
int process; //处理单词的方式 (0为单词数量,1为单词字母数)
int ProStart; //是否指定首字母(0不指定,1指定)
char StartWord; //首字母
int ProEnd; //是否指定尾字母(0不指定,1指定)
char EndWord; //尾字母
string fileName; //文件路径
如上所示,这个界面模块和计算模块主要就是通过这几个全局变量进行对接,命令行的参数已经完全转化为我们所需的参数,直接调用即可。
描述结对的过程
我们整个结对的过程,开始也和大多数人一样。彼此也有一些不太一致的地方。但是既然选择了在一起,就只能慢慢去沟通、交流、配合。经过几次线上线下的讨论之后,我们的观点也趋于一致,然后就开始了愉快的编程了。我们主要是我开始编写命令行参数的识别部分并提供部分接口,然后文政尧就开始写无环部分单词链的处理,然后我在开始有环单词链的处理,文政尧再进行单元测试,我负责把整个程序封装好。
评价反思
结对编程的优点:
1.能够发现一些人为bug,而且能够及时修复。
2.对一些复杂算法能够及时讨论,找出合理的解决方案。
3.程序版本更新比较及时,没有滞后感
结对编程的缺点:
1.对两个人要求比较高,不一定适合自己。
2.比较耗时耗力,而且容易滞后进度,容易处在等的环节。
因为这次没有做的很好,我们打算继续改进。
成员 | 优点 | 缺点 |
---|---|---|
15005012 左顺 | 性格开朗,执行力好,善于思考 | 有时候比较执拗,对算法领悟不够深 |
16061100 文政尧 | 性格开朗,对算法理解比较好,有一些创新想法 | 执行力不是很够 |
PSP回溯
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
.Estimate | 估计这个任务需要多少时间 | 2000 | |
Development | 开发 | ||
.Analysis | 需求分析 (包括学习新技术) | 240 | 250 |
.Design Spec | 生成设计文档 | 180 | 120 |
.Design Review | 设计复审 (和同事审核设计文档) | 120 | 120 |
.Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
.Design | 具体设计 | 200 | 300 |
.Coding | 具体编码 | 450 | 500 |
.Code Review | 代码复审 | 240 | 200 |
. Test | 测试(自我测试,修改代码,提交修改) | 240 | 260 |
Reporting | 报告 | ||
.Test Report | 测试报告 | 180 | 100 |
.Size Measurement | 计算工作量 | 30 | 20 |
·Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 30 |
Sum |合计 |1970|1930