结对项目
1.相关信息
Q | A |
---|---|
这个作业属于哪个课程 | 2020春季计算机学院软件工程(罗杰 任健) |
这个作业的要求在哪里 | 结对项目作业 |
我在这个课程的目标是 | 系统地学习软件工程开发知识,掌握相关流程和技术,提升工程化开发的能力 |
这个作业在哪个具体方面帮助我实现目标 | 了解熟悉结对开发流程,为之后的组队项目做好铺垫 |
教学班级 | 005 |
项目地址 | https://github.com/NoSameRain/BUAA_SE_IntersectPrj_Pair.git |
2.PSP表格:
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
· Estimate | · 估计这个任务需要多少时间 | 20 | 20 |
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 200 | 240 |
· Design Spec | · 生成设计文档 | 60 | 60 |
· Design Review | · 设计复审 (和同事审核设计文档) | 60 | 60 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 40 |
· Design | · 具体设计 | 30 | 40 |
· Coding | · 具体编码 | 300 | 350 |
· Code Review | · 代码复审 | 150 | 200 |
· Test | · 测试(自我测试,修改代码,提交修改) | 300 | 300 |
Reporting | 报告 | ||
· Test Report | · 测试报告 | 120 | 120 |
· Size Measurement | · 计算工作量 | 40 | 40 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 60 | 60 |
合计 | 1370 | 1530 |
3.看教科书和其它资料中关于 Information Hiding,Interface Design,Loose Coupling 的章节,说明你们在结对编程中是如何利用这些方法对接口进行设计的。
Information Hiding:1972年,David Parnas提出了信息隐藏的想法。他认为关键的设计系统应该对客户和前端用户隐藏。他将信息隐藏定义为一种可以保护客户端免受内部程序影响的方法。换句话说,信息隐藏是使用编程语言功能(如私有变量)或显式导出策略来防止类或软件组件的某些方面对其客户端可访问的能力。例如,可以隐藏产生给定结果的计算。它遵循可以描述为一种信息隐藏类型的功能模型。信息隐藏的一个优点是具有灵活性,例如允许程序员更容易地修改程序。也可以通过将源代码放置在模块中以在将来随着程序的发展和发展轻松访问而完成。
在我们的设计中,每个类(Line,Point)并无私有属性,因为它们的相关属性是需要提供给外部函数进行计算的,所以在类里信息隐藏的体现并不明显。但是对整个项目来说,计算和错误处理的功能实现封装在了dll文件里,UI只需要知道结果而不必关心计算过程,在这一点上体现了了信息隐藏。感觉在这个过程中,信息隐藏是原理,封装是技术,通过将实现过程封装到提供接口的方式来实现隐藏信息。通过隐藏信息,封装 ,组合模块可以创建更大的实体。同时确保了隐藏的功能的正确性后,可以专注于UI模块的设计,而不必担心隐藏的细节。
Interface Design:这里的接口应该主要指的是API,即Application Programming Interface(应用程序接口),它是一些预先定义的函数,或指软件系统不同组成部分衔接的约定。 目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问原码,或理解内部工作机制的细节。文章提到了关于优秀的API接口设计原则及方法,在设计原则方面,首先是考虑接口存在的必要性,即这个接口的存在是十分有意义和价值的;第二点是职责明确,一个接口只负责一个业务功能;第三点是高内聚低耦合,一个接口要包含完整的业务功能,而不同接口之间的业务关联要尽可能的小;除此之外还有分析角度明确、入参格式统一、提供状态及反馈等。
在我们的接口设计中,core是为UI和命令行程序提供计算和错误处理功能的,因此core的接口主要是从功能的角度来设计的,比如计算交点并返回,错误审查并返回错误信息,从文件读入数据和写入数据等,保证了信息隐藏。在后文对接口会有详细的介绍。
Loose Coupling:在编程中,耦合是指一个组件具有另一组件的直接知识程度,也就是软件模块之间的相互依赖程度。耦合通常与内聚形成对比,。低耦合通常与高内聚相关,反之亦然。低耦合通常是软件结构良好和设计良好的标志,并且与高内聚性结合使用时,可以达到较高的可读性和可维护性的总体目标。耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。
在我们的设计中,使得模块的功能化分尽可能的单一,避免直接调用其他模块,但是在编程过程中不可避免的会使用public声明方法以及全局变量的定义,导致松耦合体现的效果不是那么理想。在之后和其他小组的松耦合测试中,也因为接口的设计有点差异,所以需要做细微的修改。
4.计算模块接口的设计与实现过程。设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?说明你的算法的关键(不必列出源代码),以及独到之处。
本次作业里有三个类(Point,Line,WFLine),Line是存储计算交点所需的直接信息,WFLine是为处理有无穷多交点即Line重合设计的类,包含3个参数a,b,c,即采用ax+by+c=0的直线表达式;a,b,c是由两个点的坐标计算而来,故WFLine继承自Point。关于Point和Line,WFLine的函数声明都放置在assis.h中。
需要实现的重要函数有以下:1.确定直线参数;2.求直线交点;3.判断交点是否在线段或者射线上;4.错误输入处理;5.判断是否有无穷多交点;6.set用于去重的运算符重载函数;
我们设计的接口如下:
DLL_API void readin(string FileName);//读入数据
DLL_API void clear();//清空所有容器
DLL_API void cnt_coor_num(); //计算交点个数
DLL_API set<Point> getPoints();//返回交点集合
DLL_API vector<line> getLine();//返回直线集合
DLL_API void addLine(line l);//添加直线
DLL_API void delLine(line l);//删除直线
DLL_API void solve();//求解
DLL_API void write(string FileName);//写入文件
DLL_API string inputHandler(string FileName);
//从文件读入数据时进行错误处理 正常应返回 "Everything is ok!"
DLL_API string InfinitePoints();
//判断线之间是否重合 正常应返回"NO InfinitePoints!"
DLL_API int getP_cnt();//获得交点个数
DLL_API int getPointNum();//points size
程序开始时,各函数调用顺序如下:
在addLine之后需要调用InfinitePoints()以判断是否有无穷多交点,再调用交点计算模块进行计算。
5.阅读有关 UML 的内容:UML。画出 UML 图显示计算模块部分各个实体之间的关系(画一个图即可)。
由于此次作业中类与类之间的关系未做过多设计,故在starUML中画出的图比较简略:
6.计算模块接口部分的性能改进。记录在改进计算模块性能上所花费的时间,描述你改进的思路,并展示一张性能分析图(由VS 2015/2017的性能分析工具自动生成),并展示你程序中消耗最大的函数。
性能改进:40min.
主要的性能改进是在存储交点方面,一开始我们采用的是将节点的Xpoint和Ypoint转化为string以达到去重的目的,并存储在map容器中,经过性能分析发现to_string和insert函数开销特别大,所以换成了直接存储结点对象(含有两个double属性)到set容器中,同样可以达到去重的目的。改进前性能分析图如下:
可以看出to_string函数和map容器的insert函数开销极大。改进后:
主要的CPU开销是在set的insert操作。
7.看 Design by Contract,Code Contract 的内容:描述这些做法的优缺点,说明你是如何把它们融入结对作业中的。
Design by Contract未契约式编程,Code Contract是代码契约,都指向一种软件设计的方法,它规定软件设计者应该为软件组件定义正式的,精确的和可验证的接口规范,该规范扩展了抽象数据类型的普通定义,包括前置条件,后置条件和不变量(来自wiki)。博客给出了关于前提条件、后置条件和不变量的举例介绍。简单的说,契约作用于两方,每一方都会完成一些任务,从而促成契约的达成,但同时,每一方也会接受一些义务,作为制定契约的前提,有任意一方无视了必尽的义务,则契约失败。契约式编程要求我们在前提条件、后继条件和不变量条件进行契约的检查。契约所约束的,就是一个为了确保程序正常运行的条件。
Microsoft 在 .NET 4.0 中正式引入契约式编程库。.NET4.0除了之前提到的三个概念之外,还增加 Assert(断言),Assume(假设) 概念。博客对.NET 4.0 中的契约式编程进行了较为详细的分析。在.NET4.0中,对宏和条件编译进行抽象封装。这些成果大多集中在 System.Diagnostics.Contracts.Contract 静态类中。该类中的大多数成员都是条件编译。这样,我们就不用再使用 #ifdef 和定义 CONTRACTS_FULL 之类的标记。更重要的是,这些行为被标准化,可以在多个项目中统一使用,并根据情况是否生成带有契约的程序集。
-
优点:
1.使编译器可以根据从契约中收集的信息生成更好的代码。
2.使开发人员的思维更清晰,有助于养成良好可交互的编程习惯,而且对于提高程序性能很有帮助。它对大多数程序设计都有很大的帮助。
3.契约式编程可以严格区分责任,大家都是平等的享有义务和权力,让每个人都不必为了迁就他人的错误而进行艰难的编码。
4.减少难以解释的错误的机率,基本排除不可预知的参数和组合错误。
-
缺点:
A drawback of using these methods and Ensuring is that you can’t disable these checks in production.
也就是在生产中无法自由地把这些契约disable,真要引入这种风格到你的代码时,得编写一个模块来随时关闭这种功能。
在我们的结对作业中,对接口的约定大概就是一个简单的DbC,双方开发完毕后通过接口实现模块的对接,都需要按照契约完成任务,一定程度上体现了执行契约的义务在我,而核查契约的权力在对方。在单元测试的过程中,采用Assert断言来检测程序内部逻辑的正确性,它的使用也可以当作一种通过契约执行来测试设计的方式。
8.计算模块部分单元测试展示。展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路。并将单元测试得到的测试覆盖率截图,发表在博客中。要求总体覆盖率到 90% 以上,否则单元测试部分视作无效。
单元测试部分,我们主要构造了L-L,L-S,L-R,S-S,S-R,S-L,R-R,R-S,R-L几种情况下线相交、平行的测试,需要特殊处理的情况,比如斜率不存在,交点重合,S-S,S-R,R-R时可能出现交点不在线内部或者交点刚好是端点的情况,需要尤其注意。部分测试代码如下:
//这个方法是对构造函数和直线相关计算功能的测试
TEST_METHOD(TestMethod2) {
line l1;
l1.store_coor("R 0 1 1 0");
Assert::AreEqual(l1.type, (string)"R");
Assert::AreEqual(l1.k, (double)-1);
Assert::AreEqual(l1.ulimited, false);
line l2;
l2.store_coor("S -1 -1 0 1");
Assert::AreEqual(l2.type, (string)"S");
Assert::AreEqual(l2.k, (double)2);
Assert::AreEqual(l2.ulimited, false);
}
//一般情况下的求取交点的测试
TEST_METHOD(TestMethod3) {
line l1;
l1.store_coor("L 0 0 1 1");
line l2;
l2.store_coor("L 1 0 0 1");
coor_4_line.push_back(l1);
coor_4_line.push_back(l2);
calcu_coor(0, 1);
Assert::AreEqual(intersection.size(), (size_t)1);
}
//交点在射线或线段的延长线上
TEST_METHOD(testMethod9) {
clear();
N = 4;
line l1, l2, l3, l4;
l1.store_coor("L -2 0 0 -2");
l2.store_coor("R 1 1 2 2");
l3.store_coor("R 1 0 0 2");
l4.store_coor("S -2 0 1 4");
coor_4_line.push_back(l1);
coor_4_line.push_back(l2);
coor_4_line.push_back(l3);
coor_4_line.push_back(l4);
cnt_coor_num();
Assert::AreEqual(intersection.size(), (size_t)2);
}
//斜率不存在且交点在端点处
TEST_METHOD(testMethod12) {
clear();
N = 3;
line l1, l2, l3;
l1.store_coor("S 3 2 3 1");
l2.store_coor("R 3 2 3 4");
l3.store_coor("S 3 -1 3 -2");
coor_4_line.push_back(l1);
coor_4_line.push_back(l2);
coor_4_line.push_back(l3);
cnt_coor_num();
Assert::AreEqual(intersection.size(), (size_t)1);
}
//重合交点
TEST_METHOD(testMethod14) {
clear();
N = 3;
line l1, l2, l3;
l1.store_coor("L 0 2 2 0");
l2.store_coor("R 0 0 1 1");
l3.store_coor("S 1 0 1 3");
coor_4_line.push_back(l1);
coor_4_line.push_back(l2);
coor_4_line.push_back(l3);
cnt_coor_num();
Assert::AreEqual(intersection.size(), (size_t)1);
}
//临界数据
TEST_METHOD(testMethod15) {
clear();
N = 3;
line l1, l2, l3;
l1.store_coor("L 100000 100000 -3 19999");
l2.store_coor("L 99999 100000 4 8366");
l3.store_coor("L -6542 768 9999 -4");
coor_4_line.push_back(l1);
coor_4_line.push_back(l2);
coor_4_line.push_back(l3);
cnt_coor_num();
Assert::AreEqual(intersection.size(), (size_t)3);
}
//有斜率且斜率相同端点相交的SS
TEST_METHOD(testMethod21) {
clear();
N = 2;
line l1;
line l2;
l1.store_coor("S 0 0 1 1");
l2.store_coor("S 1 1 2 2");
coor_4_line.push_back(l1);
coor_4_line.push_back(l2);
cnt_coor_num();
Assert::AreEqual(intersection.size(), (size_t)1);
}
//其中一个垂直且假交点在垂直延伸线上的ss
TEST_METHOD(testMethod22) {
clear();
N = 2;
line l1;
line l2;
l1.store_coor("S 1 0 0 1");
l2.store_coor("S 1 1 1 2");
coor_4_line.push_back(l1);
coor_4_line.push_back(l2);
cnt_coor_num();
Assert::AreEqual(intersection.size(), (size_t)0);
}
//还有一部分关于图形之间的位置关系:考虑L、R、S两两平行、相交的情况。从斜率角度出发,考虑任意两个图形,一个有斜率另一个斜率不存在,两个斜率都存在(斜率相等、不相等),两个斜率都不存在的情况以及上述情况的组合。
覆盖率和测试情况截图:
9.计算模块部分异常处理说明。在博客中详细介绍每种异常的设计目标。每种异常都要选择一个单元测试样例发布在博客中,并指明错误对应的场景。
错误类型 | 输出 | 测试样例 |
---|---|---|
类型不符合L S R | Please input line type as "L","S","R" at line | 2 K 1 2 4 5 a 0 0 1 1 |
‘-’后未紧跟数字 | Make sure ‘-’ is followed by number.Error at line | 3 L 0 0 1 1 R 3 2 0 5 S 9 - 7 8 |
坐标范围超限 | Make sure that the range of points is(-100000,100000).Error at line | 2 L 1000001 4 5 1 R 3 2 0 5 |
line中两点重合 | Please input two different points.Error at line | 3 L 1 4 5 1 R 3 2 0 3 S 7 8 7 8 |
输入数据不完整 | TOO SHORT!Please input as "LSR int_x1 int_y1 int_x2 int_y2" for each line.at line | 4 L 1 4 5 1 R 3 2 0 3 L 6 4 3 2 S 9 7 5 |
输入过多元素 | TOO LONG!Please input as "LSR int_x1 int_y1 int_x2 int_y2" for each line.Error at line | 3 L 0 0 1 1 R 3 2 0 5 S 9 5 6 7 8 |
输入非整数 | Please input integers.Error at line | 3 L 0 0 1 1 R 3 2 0 5 S 9 5 6 7 R 4.45 6 7 6 |
找不到输入文件 | File is Not Found | input.txt移除 |
第一行不是整数 | Make sure the first line is an Integer that greater than or equal to 1. | a L 0 0 1 1 R 3 2 0 5 |
第一行小于1 | Make sure N is an integer greater than or equal to 1. | 0 L 0 0 1 1 R 3 2 0 5 |
type和数字没有空格 | Make sure there is a SPACE between number and letter at line | 2 L0 0 1 1 3 R 3 2 0 5 |
N和直线数目不匹配 | N does not match the number of lines. | 2 L 0 1 1 3 R 3 2 0 5 R 0 0 1 1 |
出现以0开始的数字 | A number that begins with 0 at line | 4 L 0 1 1 3 R 3 2 0 5 R 0 0 1 1 S 012 3 4 5 |
不止一个交点,即LSR 出现重合情况 | Infinitely intersections between line type-xx | 2 L 1 0 2 1 L 0 -1 -1 -2 这一类的错误情况比较多,涉及到三种线两两组合以及斜率是否存在的问题,更多的测试数据可以在github地址的readme.md中看到。 |
以下是一部分运行截图:
10.界面模块的详细设计过程。在博客中详细介绍界面模块是如何设计的,并写一些必要的代码说明解释实现过程。
本次界面模块的实现用到了Qt插件.UI设计这一部分由于知识点比较繁杂,花费了非常多的时间,首先是阅读官方文档,对基本的类和函数有一个大致的了解.比如信号槽机制以及一些绘图控件.前期准备大概花了一两天,实际写代码并没有花费太久(主要还是负责封装的同学接口写的好,调用起来非常顺畅,整体上功能的实现思路也就比较清晰)后期解决qt的各种报错又花了很多时间,主要还是对lib,dll文件的引用不够了解,导致在属性设置上走了很多弯路.
现在回过头来看代码部分其实思路很简单,功能也就那几个.接下来讲一下我的设计流程以及思路.
设计UI我是从功能的角度出发的,首先明确要实现那些功能:添加几何对象,删除几何对象,从文件导入几何对象的描述,绘制几何对象,绘制几何对象交点,显示交点个数,抛出异常信息,退出界面.
大致明确了要实现这些功能后,我首先利用Qt Designer对窗体进行了大致的可视化设计.
Designer(界面设计器)设计 ui 界面最终转换为 C++ 代码(ui_类名.h),和我们写的 Qt 代码是大同小异的,假如我们对某些部件操作不熟悉,不知道该如何用其相应函数,这时候我们通过 Designer(界面设计器)拖拽此部件,修改其所需属性,接着编译,看其自动转换的 C++ 代码如何实现,这样可学习其相应函数的用法.
以上步骤完成后开始利用代码进行具体的功能设计与实现.首先在源文件中对几个功能按钮进行了信号槽设置,当butoon被按下后就会触发相应的功能,这里我学到了一点就是,按照qt的命名方法对函数进行命名可以省去connect部分的代码,实现button与相应功能的直接连接.以下为几个主要的功能,分别对应5个button(添加对象、删除对象、绘制几何对象、绘制交点、添加文件)
private slots:
void on_AddLine_clicked();
void on_DelLine_clicked();
void on_GenerateGraph_clicked();
void on_GeneratePoint_clicked();
void on_AddFile_clicked();
然后是几个具体要实现的功能.添加几何对象和删除几何对象部分很简单,就是调用了intersect模块的addline和delline接口,并且进行了对输入的信息异常以及输入的几何对象有无穷交点进行了判断,这里展示部分代码,一些细节部分都使用星号略去
void intersect_ui::on_AddLine_clicked()
{
*****
QString text = ui.InputStr->text();
if (text.size() == 0)
{
ui.error_messege->setText("please input text");
}
else
{
*****
addLine(l1);//添加直线
*****
if (message1 != "NO InfinitePoints!")
{
ui.error_messege->setText(qmessage1);
delLine(l1);//删除直线
}
}
ui.InputStr->clear();
}
void intersect_ui::on_DelLine_clicked()
{
*****
QString text = ui.InputStr->text();
if (text.size() == 0)
{
ui.error_messege->setText("please input text");
}
else
{
*****
delLine(l1);//删除直线
}
ui.InputStr->clear();
}
绘制几何对象部分花费了比较长的时间.这里用到了QT-Qcustomplot来实现基础坐标轴功能以及图像的绘制.其中直线,线段,射线的绘制我查阅了QCPAbstractItem官方文档用到了QCPItemStraightLine以及QCPItemLine类来实现.这里以绘制直线为例进行展示,射线和线段部分略去
void intersect_ui::on_GenerateGraph_clicked()
{
*****
vector<line> lines = getLine();//返回直线集合
for (int i = 0;i < lines.size();i++)
{
if (lines[i].type == "L")
{
QCPItemStraightLine* l = new QCPItemStraightLine(ui.widget);//构造直线
ui.widget->addItem(l);//添加到图中
l->setPen(QPen(Qt::blue)); //设置画笔
l->point1->setCoords(lines[i].x1, lines[i].y1);
l->point2->setCoords(lines[i].x2, lines[i].y2);
ui.widget->replot();
}
else if (lines[i].type == "R")
{
*****
}
else if (lines[i].type == "S")
{
*****
}
}
//设置可拖拽 滚轮放大缩小 图像可选择
ui.widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
}
通过查阅资料我在坐标轴中实现了拖拽,滚轮放大缩小功能,便于查看生成的几何对象.
生成交点与这里大同小异,就是调用了intersect模块中的返回交点坐标接口然后根据坐标点信息进行绘制,这里不再详述.
输入文件部分调用核心模块中的读文件接口和异常处理接口,实现也非常简单.
void intersect_ui::on_AddFile_clicked()
{
QString text = ui.InputFileName->toPlainText();
string str = text.toStdString();
string message = inputHandler(str);
QString qmessage = QString::fromStdString(message);
if (message == "Everything is ok!")
{
string message1 = InfinitePoints();
QString qmessage1 = QString::fromStdString(message1);
if (message1 == "NO InfinitePoints!")
{
readin(str);//读入数据
}
else
{
ui.error_messege->setText(qmessage1);
}
}
else
{
ui.error_messege->setText(qmessage);
}
11.界面模块与计算模块的对接。详细地描述 UI 模块的设计与两个模块的对接,并在博客中截图实现的功能。
模块对接其实我在上一点中也已经提到了.我们的思路很简单,实现什么功能的槽函数就对接实现什么功能的计算模块的接口.
举例来讲,就是UI模块的以下函数
private slots:
void on_AddLine_clicked(); //添加几何对象
void on_DelLine_clicked(); //删除几何对象
void on_GenerateGraph_clicked(); //绘制几何对象图形
void on_GeneratePoint_clicked(); //绘制交点
void on_AddFile_clicked(); //读文件
分别对应调用核心模块中以下函数
DLL_API void addLine(line l);//添加几何对象
DLL_API void delLine(line l);//删除几何对象
DLL_API vector<line> getLine();//返回几何对象集合
DLL_API set<Point> getPoints();//返回交点
DLL_API void readin(string FileName);//从文件读入数据
同时考虑到错误处理,还调用了用于检查文件格式,判断是否有无穷交点等的函数.具体怎么调用,在什么时候调用,上面的代码部分都进行了展示.从总体的逻辑上来看就是以下三步:
- 槽函数响应事件
- UI模块中相应函数被执行
- UI模块中函数调用核心模块中函数来实现特定功能并更新核心模块数据
功能展示截图如下:
- 绘制几何对象及交点,显示交点个数,缩放大小
- 显示异常信息(这里展示了输入为空、找不到该文件、某两个几何对象有无穷交点的错误信息)
-
addLine和delLine
导入txt:(有可能部分线没有出现在界面内,在其他象限,拖动一下坐标轴即可)
addLine:
结果:(有可能部分线没有出现在界面内,在其他象限,拖动一下坐标轴即可)
delLine:
结果:
若addLine有误,则会提示error message:
12.描述结对的过程,提供两人在讨论的结对图像资料(比如 Live Share 的截图)。关于如何远程进行结对参见作业最后的注意事项。
远程结对感觉还是挺有挑战的,在作业的第一个星期因为我和队友都有其他任务,所以交流比较少,大家是分头行动,比如增加功能和测试,各司其职;在第二个周开始共享屏幕,视频交流,效率还是提升很多,对接口的设计和使用也更为快捷。屏幕共享截图:
13.看教科书和其它参考书,网站中关于结对编程的章节,例如:博客,说明结对编程的优点和缺点。同时描述结对的每一个人的优点和缺点在哪里(要列出至少三个优点和一个缺点)。
在这次结对项目中,我和队友驾驶员(Driver)和领航员(Navigator)的身份不是固定的,比如在错误处理阶段和IU设计开发阶段,我俩的身份就是互换的,在减小任务压力上还是很有作用的。但是这次作业的不足是我俩对作业进度的掌握不好,前期进度缓慢,后期太敏捷。没有完成附加题也比较遗憾。这是在以后的作业中需要改进的地方。
优点:
1.结对编程能提供更好的设计质量和代码质量,两人合作能有更强的解决问题的能力。
2.对开发人员自身来说,结对工作能带来更多的信心,高质量的产出能带来更高的满足感。
3.在心理上, 当有另一个人在你身边和你紧密配合, 做同样一件事情的时候, 你不好意思开小差, 也不好意思糊弄,提高责任感。
4.让代码不断处于复审中,能及时地发现问题和解决问题,避免把问题拖到后面的阶段。
缺点:
1.在个人项目的基础上增加了沟通成本,很幸运的是我有一个同理心很强也很负责的队友。
2.两个人系统或者软件版本不匹配带来的模块对接问题是真的心累...
优点 | 缺点 | |
---|---|---|
16005046 | 1.沟通能力强,在结对过程中有什么问题都是很及时的解决。 2.学习新东西很快,效率很高(尤其是到后期哈哈哈),在一个晚上通过无数百度、谷歌、必应、csdn还有其他资料解决了计算模块和UI模块对接的问题。 3.心态平和,遇到问题不急躁,值得我学习。 |
有时候可能没有注意到一些小细节。 |
17373532 | 1.还算比较负责,比较主动积极。 2.能够仔细分析代码解决bug。 3.比较细心。 |
遇到问题比较急躁;并且效率比较低。 |