软件工程结对作业博客
博客项目地址
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | 70 | 30 |
· Analysis | · 需求分析 (包括学习新技术) | 240 | 160 |
· Design Spec | · 生成设计文档 | 70 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 20 | 10 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 10 |
· Design | · 具体设计 | 120 | 70 |
· Coding | · 具体编码 | 360 | 480 |
· Code Review | · 代码复审 | 120 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 120 | 160 |
· Test Report | · 测试报告 | 120 | 360(生成测试覆盖率找了好久) |
· Size Measurement | · 计算工作量 | 40 | 25 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 40 | 20 |
合计 | 1340 | 1415 |
Information Hiding, Interface Design, Loose Coupling
- information hiding
信息隐藏,有利于程序编写过程中,设计决策相应的改变。通过信息隐藏,防止类或者其余的软件组件被客户端所访问到,提供稳定的接口进行交互。
- 在结对编程的过程中,信息隐藏主要通过C++的类的特性来对实现过程中用到的数据结构等来进行封装。将相应的数据和方法设置为private,防止调用的类能够访问到或者直接应用其中的数据结构。这样在对相应的算法等内容进行修改的时候,不用进行大范围的修改。
- interface design
用户界面设计,通过用户界面设计,使得用户在完成自己的任务时与被设计对象之间的交流尽可能地简单高效,通过图形设计可以提高界面的可用性。
- 我们的界面设计并没有设计图形界面,仅仅只是按照基本要求提供了相应的命令行调用,在调用过程中,若是出现相应的错误,则输出相应的错误信息进行提醒。
- loose coupling
松耦合,在计算机运算和系统设计中,一个松耦合的系统中的每一个组件对其他独立组件的定义所知甚少或一无所知。子范围包括类、接口、数据和服务之间的耦合。[1] 松耦合是紧耦合的对立面。
- 松耦合这块主要是通过提供必要的接口进行交互来降低系统的耦合性。其中主程序主要通过调用preprocess类和相应的core类所提供的接口来组合成完整的程序,preprocess类和core类不会相互影响。
计算模块接口的设计和实现过程
- 计算模块的接口主要就是提供两个要求的接口,其中分别为
gen_chain_word(char* words[], int len, char* result[], char head, char tail, bool enable_loop)
gen_chain_char(char* words[], int len, char* result[], char head, char tail, bool enable_loop)
- 主要实现过程
- 算法关键:将26个字母作为节点,将每个单词作为边,进行图的构建,然后在查找相应的最长路径过程中,通过对图进行相应的dfs遍历来查找。
- 类:主要的类就是图相关的类,该类为WordGraph,其中基本属性有路径和节点等相关的结构体
- 方法:
Path *LongestPathFrom(char start, bool isWeighted); (用于计算已知起点的最长路径) Path *LongestPathBetween(char start, char end, bool isWeighted);(用于计算已知起点和终点的最长路径) Path *LongestPathTo(char end, bool isWeighted);(用于计算已知终点的最长路径) Path *LongestPath(bool isWeighted); (用于计算图中最长路径) bool IsCyclic(); (判断是否含有相应的环)
UML图
计算接口方面的性能改进
- dfs是该算法过程中消耗时间最长的部分,其中刚开始我们的程序中有部分多余的搜索,经过改进了之后,能够减少多余的搜索
-
契约式设计
契约式设计(英语:Design by Contract,缩写为 DbC),一种设计计算机软件的方法。这种方法要求软件设计者为软件组件定义正式的,精确的并且可验证的接口,这样,为传统的抽象数据类型又增加了先验条件、后验条件和不变式。这种方法的名字里用到的“契约”或者说“契约”是一种比喻,因为它和商业契约的情况有点类似。
- 契约式设计能够使得软件整体的设计更加优秀,同时能够在软件编写过程中帮助调试,生成更加可靠的软件。
- 但是契约式编程在设计方面所需要投入的时间更多,同时对于编程人员的水平以及对于软件组件等有清晰的认识。
- 结对编程过程中,我们小组主要通过统一对异常的控制来处理相应的先验条件,比如在处理命令的时候,若是判断该条命令并不合法,则会抛出相应的异常,增加了命令合法的先验条件之后,这样之后的程序就无须处理该种异常的情况。
计算模块单元测试展示
TEST_METHOD(TestMethod1)
{
TEST_INIT(11, "Algebra", "Apple", "Zoo", "Elephant", "Under", "Fox",
"Dog", "Moon", "Leaf", "Trick", "Pseudopseudohypoparathyroidism");
GEN_CHAIN_WORD(0, 0, false);
ASSERT_RESULT_LEN(4);
ASSERT_RESULT("algebra", 0);
ASSERT_RESULT("apple", 1);
ASSERT_RESULT("elephant", 2);
ASSERT_RESULT("trick", 3);
GEN_CHAIN_CHAR(0, 0, false);
ASSERT_RESULT_LEN(2);
ASSERT_RESULT("pseudopseudohypoparathyroidism", 0);
ASSERT_RESULT("moon", 1);
GEN_CHAIN_WORD('e', 0, false);
ASSERT_RESULT_LEN(2);
ASSERT_RESULT("elephant", 0);
ASSERT_RESULT("trick", 1);
GEN_CHAIN_WORD(0, 't', false);
ASSERT_RESULT_LEN(3);
ASSERT_RESULT("algebra", 0);
ASSERT_RESULT("apple", 1);
ASSERT_RESULT("elephant", 2);
}
-
计算模块的单元测试展示如上图所示,其中主要用到的方法为TEST_INIT , ASSERT_RESULT_LEN , ASSERT_RESULT , 其中TEST_INIT主要是通过对输入的单词进行初始化,存入相应的数据结构之中。ASSERT_RESULT_LEN为对结果的长度的检验。ASSERT_RESULT则是对最后结果的检测,检测结果是否为响应的正确内容。
-
测试覆盖率图片
一张为核心计算模块的覆盖率测试报告,一张为命令行程序的覆盖率测试报告
计算模块异常处理说明
- 计算模块中的异常主要可以分为对输入不合法的异常以及输入单词中包含单词环的异常
- 其中针对输入不合法的异常单元测试如下
// pre.command 异常测试
TEST_METHOD(TestMethod6) {
try {
Preprocess pre;
int argc = 1;
char ** argv = new char *[argc];
argv[0] = new char[10];
strcpy(argv[0], "Wordlist.exe");
pre.command(argc, argv);
Assert::Fail();
}
catch (std::exception e) {
}
}
- 其中针对输入单词中包含单词环的异常测试如下
// 有环但enable_loop是false,应该抛出异常
TEST_METHOD(TestMethod1)
{
TEST_INIT(7, "gag", "fag", "glitz", "zaf", "jof", "fij", "lkkj");
Assert::ExpectException<std::exception>([&]
{
GEN_CHAIN_WORD(0, 0, false);
});
}
界面模块
界面模块是我们组后来推进的内容,主要由我的搭档编码。
gui部分主体为两个单词框,其中一个用于输入,另一个用于输出,对于单词链首字母与单词链尾字母等相关内容,在右侧通过复选框等内容进行选择。同时要从文件读取的话,可以通过下拉选单实现相应功能。
部分代码示例如下:
leftLayout = new QVBoxLayout;
rightLayout = new QVBoxLayout;
topRightLayout = new QHBoxLayout;
bottomRightLayout = new QHBoxLayout;
mainLayout = new QHBoxLayout;
// 左边的输入输出框
leftLayout->addWidget(inputLabel);
leftLayout->addWidget(inputTextEdit);
leftLayout->addWidget(outputLabel);
leftLayout->addWidget(outputTextEdit);
// 右上角的单词数最多和字母数最多单选框
topRightLayout->addWidget(maxLabel);
topRightLayout->addWidget(wordRadioButton);
topRightLayout->addWidget(charRadioButton);
// 右下角查找和导出按钮
bottomRightLayout->addWidget(findButton);
bottomRightLayout->addWidget(exportButton);
// 右边布局
rightLayout->addLayout(topRightLayout);
rightLayout->addLayout(headLayout);
rightLayout->addLayout(tailLayout);
rightLayout->addWidget(loopCheckBox);
rightLayout->addWidget(extractButton);
rightLayout->addLayout(bottomRightLayout);
mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
界面模块与计算模块的对接
合作小组的学号:16061011,16061152
我们两个小组对于dll的使用方式有所不同,导致一开始,双方都不能跑对方的程序,最后我们各自作出了相应的调整,解决了相应问题。
我们将对方组的core模块添加了相应的def文件之后,最后成功运行出了相应的结果。
对方组用我们组的core模块之时,程序无法正确运行,最后我们将源码合在一起后找出相应问题并修正,同时在core模块中添加了相应的去重处理。
结对过程
- 结对过程中,为了提高进度,我们小组首先各自单独设计相应的模块,同时完成部分demo编码,以免一起结对编程的时候,浪费过多的时间,最后约定了相应的时间,合作开展结对编程,主要是一起推进程序的完成,讨论算法的实现,最后一起编写相应的测试样例。
- 下图为我们两人在新主楼结对编程之时所拍下的照片
结对编程的优缺点
-
结对编程的优点为两个人同时编程,能够提高程序编写的效率,同时,因为两个人在一起写代码,沟通效率高,能够避免以为沟通过程中,信息传达错误而造成的问题。最后软件写好就是一个整体,避免了分工整合之后的调整等问题。
-
缺点就是这样的编码方式可能很多同学不是很习惯,同时两个人都有自己的想法,需要花费较多的时间达成共识才可以进行相应的编码
-
队友的优点
- 能力强,推进了程序的核心算法部分,对我帮助很大
- 工作积极,总是提前完成相应内容
- 时间安排合理,使得任务顺利完成
-
队友的缺点
- 说话声音稍微有点轻,但不影响交流ε=ε=ε=( ̄▽ ̄)
-
队友对我的评价
- 优点:
- 积极热情,有责任心
- 具有批判性思维
- 注重细节
- 缺点:
- 编码风格不太一致
- 优点:
该格式内容的文字表示引用网上相关内容,