结对编程作业
项目 | 内容 |
---|---|
课程 | 软件工程(罗杰) |
作业要求 | 结对项目-单词最长链 |
本次作业的目的 | 体验结对编程 |
本次作业对我的锻炼 | 熟悉结对编程,了解结对编程的优点和缺点 |
项目github地址 | 项目地址 |
项目地址
https://github.com/wlof-2/LongestWordChain/tree/wf_try
预估耗时PSP
PSP1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 180(3h) | |
Estimate | 估计这个任务需要多少时间 | 180(3h) | |
Development | 开发 | 1440(24h) | |
Analysis | 需求分析 (包括学习新技术) | 120(2h) | |
Design Spec | 生成设计文档 | 120(2h) | |
Design Review | 设计复审 (和同事审核设计文档) | 60(1h) | |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 60(1h) | |
Design | 具体设计 | 60(1h) | |
Coding | 具体编码 | 480(8h) | |
Code Review | · 代码复审 | 300(5h) | |
Test | 测试(自我测试,修改代码,提交修改) | 240(4h) | |
Reporting | 报告 | 300(5h) | |
Test Report | 测试报告 | 120(2h) | |
Size Measurement | 计算工作量 | 60(1h) | |
Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 120(2h) | |
合计 | 1920(32h) |
接口设计方法
-
Information Hiding(信息隐藏)
信息隐藏指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。信息隐藏在设计的所有层次上都有很大作用:从用具名常量代替字面常量,到创建数据类型,再到类的设计、子程序的设计以及子系统的设计等等。在我们的设计中,我们将程序主要分成三部分,处理输入部分,核心计算部分,输出部分,这三部分除了接口之外,没有变量上的其它关系。也就是三部分的变量是相互分开的,不会出现一个模块改变另一个模块的变量的情况。
-
Interface Design(接口设计)
接口设计的六大原则是,单一职责原则, 里氏替换原则, 依赖倒置原则,接口隔离原则,迪米特法则,开闭原则。因为我们没有出现类的继承关系,所以没有体现里氏替换原则,其它的原则都可以保证,例如接口隔离原则,接口的设计高内聚,能少就少,然后是严格按照为了连接而使用接口的原则。不会出现多余的接口。
-
Loose Coupling(松散耦合)
软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分摸块的一个准则就是高内聚低耦合。 耦合度(Coupling)是对模块间关联程度的度量。我们设计的模块之间的接口与功能上体现出模块的独立性,所以耦合性较低。
计算模块接口的设计与实现过程
void Get_num(char* word[], int len, bool Weight);
// 构造图的模块
void topologicalSort();
// 拓扑排序模块
void longestPath(int start, char* word[], bool begin_end, bool Weight);
// 从点start找出最长链的模块
void Every_Path(int chose, char* word[], char end_letter, char start_letter, bool Weight);
// 根据处理输入的结果,以及接口实现找word list中的最长链
int getWord(char *words[], string path);
// 根据路径path,从文件中读出 *word[]
void paraAnalysis(int argc, char * argv[], char opt[][5], int & flag_wc, char & head, char & tail, bool & para_loop, string &filePath);
// 根据argc,agrv[], 处理参数,得出输入参数的类型,
int gen_chain_word(char* words[], int lens, char* result[], char head, char tail, bool enable_loop);
// 处理单词个数最长的单词链
int gen_chain_char(char* words[], int lens, char* result[], char head, char tail, bool enable_loop);
// 处理字母个数最多的单词链的长度
- 我们接口主要体现在gen_chain_char 函数与 Every_Path 函数,gen_chain_char 函数将输入处理完毕,然后传入参数,表示计算的步骤需要进行哪些计算。这里主要体现的接口参数是 word(表示单词链),head(单词链的头),tail(单词链的尾),chose(从 gen_chain 到 Every_Path的选择参数)。这是最主要的接口设计与实现过程。
- 在计算模块的内部,我们也使用了接口。在函数Every_Path 与 函数longestPath 之间,我们为了实现函数功能的单调性。所以我进一步在 Every_Path 中,将函数的功能细分。在 Every_Path 中主要是将函数细分,而longest_Path 只实现了从某一个起点开始找出最长链。这个设计使模块内的函数功能更加单一,也提高了函数的复用性。
计算模块UML建模
计算模块接口部分的性能改进
算法的考虑:计算的核心部分我们采用的是拓扑排序加动态规划的算法。比暴力搜索比起来降低了计算的复杂性。在拓扑排序阶段,算法的采用的是类DFS的算法。在动态规划阶段,时间复杂度是O(n)。我们没进入下一个点就会存储到这一点的最长路径。在考虑有环的算法的时候,我们想的是对于环,可以将环切出来,也就是将环的入口链与出口链分出来,这样的话在环内计算环的最长链,在环外面加上入口最长链与出口最长链即可。不幸的是,我们并没有实现,还不如直接和其它同学一样使用暴力搜索。花了一些时间实现,但是没有成功。
性能分析
Design by Contract, Code Contract
契约式设计
契约式设计的主要目的是希望程序员能够在设计程序时明确地规定一个模块单元(具体到面向对象,就是一个类的实例)在调用某个操作前后应当属于何种状态。在我看来Design by contract不是一种编程范型,它是一种设计风格,一种语法规范,甚至是个商标(是的,Bertrand Meyer注册了这么个商标)。
-
优点:
契约式设计每一方都期待从契约中获得利益,同时也要接受一些义务。通常,一方视为义务的对另一方来说是权利。契约文档要清楚地写明双方的权利与义务。所以契约式设计在结对编程中发挥重要的作用。负责两个模块的人同时为另一个人负责,完成自己的任务的时候同时相当于行使自己的权力,能够借助外力的方式使双方的程序连接的更加紧密。使程序的耦合度更低。 -
缺点:
不是所有的编程语言都支持契约式设计。
计算模块部分单元测试展示
由于用VS的单元测试出现了一些问题,一直都无法运行测试程序。所以我们就采用了运行测试的方法,构造好测试样例后,不断重复运行程序,与预期效果比对,从而达到测试效果,下面是部分测试的截图和样例:
命令行测试实例
- 例子一:
- 例子二:
计算模块部分异常处理说明
- 我所做的是判断是否有环,在不该出现环的情况下不应该有环,这里上面是无环的情况,改成有环的时候就会报错。判断是否有环,我采用的是在拓扑排序的时候,如果已经访问的点不在栈中,并且又一次被访问到,说明有环。
- 文本文件为空,传进去的单词数组为空,会报告异常错误,并结束程序。
命令行模块设计过程
命令行模块采用argc, char *argv[]两个参数作为命令行输入的接受单元,其中argc表明输入参数的个数(包括程序名),argv是一个字符型的指针数组,存储具体输入的参数。由于这两个本就是main函数的参数,所以我们可以在调试的时候,构造控制台输入。在我们处理输入的时候,这两个参数十分独立,所以调试完之后,在命令行直接分开就可以执行了。
命令行模块与计算模块的对接
开始调试的时候,我们先通过控制台输入argc 与 argv。也就是模拟了命令行执行的参数哦,所以直接在命令行运行时,运行的参数会直接传到输入处理模块,然后传到计算模块。与计算模块的对接就是通过处理输入模块来创建接口完成的。
结对编程过程
下课后在空教室内进行结对编程,我担任代码写手。完成计算部分与连接接口。吴光辉为领航员。
结对总结
结对编程优点很多,可以大大减少bug。同时结对编程必须保证代码的耦合度较低,这样做测试就会简单,而且可以保证单元模块的bug较少。结对编程还可以互相学习,在编程的过程中可以互相发现问题。对整个项目有更好的理解。结对编程缺点我自己感觉就是十分依赖结对双方之间的沟通与交流。还有就是双方的计划于在实施之前的想法。我们就是在实施之前交流的太少了,导致后面我写的时候,他等着,他写的时候,我等着,没有利用好一起写的时候,相互发现bug,相互提问的优势。导致整个项目一拖再拖。
成员 | 优点 | 缺点 |
---|---|---|
吴光辉 | 认真;执行力强;整体意识好 | 讨论的不够及时 |
吴枫 | 善于思考;有耐心debug;善于沟通 | 不够仔细 |
P表格
PSP2 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 180(3h) | 60(1h) |
Estimate | 估计这个任务需要多少时间 | 180(3h) | 60(1h) |
Development | 开发 | 1440(24h) | 1950 |
Analysis | 需求分析 (包括学习新技术) | 120(2h) | 120(2h) |
Design Spec | 生成设计文档 | 120(2h) | 60(1h) |
Design Review | 设计复审 (和同事审核设计文档) | 60(1h) | 60(1h) |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 60(1h) | 30(0.5h) |
Design | 具体设计 | 60(1h) | 200 |
Coding | 具体编码 | 480(8h) | 1200 |
Code Review | 代码复审 | 300(5h) | 200 |
Test | 测试(自我测试,修改代码,提交修改) | 240(4h) | 80 |
Reporting | 报告 | 300(5h) | 240(4h) |
Test Report | 测试报告 | 120(2h) | 120(2h) |
Size Measurement | 计算工作量 | 60(1h) | 60(1h) |
Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 120(2h) | 60(1h) |
合计 | 1920(32h) | 2250(min) |