这是一次关于结对编程的体验
0.写在前边
结对编程(英语:Pair programming)是一种敏捷软件开发的方法,两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。输入代码的人称作驾驶员,审查代码的人称作观察员(或导航员)。两个程序员经常互换角色。
在结对编程中,观察员同时考虑工作的战略性方向,提出改进的意见,或将来可能出现的问题以便处理。这样使得驾驶者可以集中全部注意力在完成当前任务的“战术”方面。观察员当作安全网和指南。结对编程对开发程序有很多好处。比如增加纪律性,写出更好的代码等。
结对编程是极端编程的组成部分。
其实结对编程做起来很简单也很有趣,找个水平差的不太远的程序员和自己配成一对。只用一台计算机,大家选一个人坐在键盘前面负责输入,另一个人坐在后面口述。两个人要不断的交流,频率不应低于一分钟一次。整个的设计思想由后面只动口不动手的人主导,而由操键盘的人做实现。由于人的思维速度是快于输入代码的速度的。那么观看的人可以有空闲的时间做额外的思考,观察代码写的有没有问题,结构有没有问题。
1. 项目要求
分析问题需求:
- 需要使用程序生成300道数学题
- 需要答案在0~100之间
- 需要中间的过程运算数均在0~100之间
- 需要考虑到运算优先级
- 限制在四则运算
- 需要给出答案的正确与否
- 能够选择答案是否显示
- 能够给出正确率
由于我们两人组都对C++相对更加熟悉,所以我们选择使用C++来实现这个项目
2. 开发环境
机器A:Visual Studio Code + mingw64
机器B:Xcode + clang
首先使用机器A编写了最初的程序原型,经过基本的测试和编译后,将代码发送到机器B中,使用
3. 实验内容和步骤
所谓结对编程,核心就是一个人输入代码,而另一个人审查他输入的每一行代码。
所以由我在一旁看另一位同学编码,我一边给出意见和建议,一边理解对方的代码。
第一版原型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include <iostream> #include <time.h> #include <cmath> #include <map> #include <algorithm> using namespace std;
const int N = 300; bool flag; char op[] = {'+', '-', '*', '/'}; map<char, int> f; int a[N + 5], b[N + 5], c[N + 5], ans[N + 5];
int f2(int a, char op, int b) { if ((a < 0) || (b < 0)) return -1; if ((a > 100) || (b > 100)) return -1; if (op == '+') return(a + b); if (op == '-') return(a - b); if (op == '*') return(a * b); if (op == '/') { if (!b) return(-1); else if (a % b) return(-1); else return(a / b); } }
int main() { f['+'] = f['-'] = 0; f['*'] = f['/'] = 1; srand(time(NULL)); for (int i = 1; i <= N; i++) { flag = false; char ch1, ch2; while (!flag) { a[i] = rand() % 100; b[i] = rand() % 100; c[i] = rand() % 100; ch1 = op[rand() % 4]; ch2 = op[rand() % 4]; if (f[ch1] < f[ch2]) { ans[i] = f2(b[i], ch2, c[i]); ans[i] = f2(a[i], ch1, ans[i]); } else { ans[i] = f2(a[i], ch1, b[i]); ans[i] = f2(ans[i], ch2, c[i]); } if ((ans[i] < 0) || (ans[i] > 100)) flag = false; else flag = true; } cout << '(' << i << ") " << a[i] << ch1 << b[i] << ch2 << c[i] << "=" << ans[i]; if (i % 3) cout << '\t'; else cout << endl; } return 0; }
|
在第一版原型中,我们简单的实现了按照项目要求中的算式需求,生成300道数学题的功能
。我们主要通过 rand()
函数取模运算来限制随机生成的数字。同样,使用 rand()
随机生成不同的运算符号。对于每一个生成的算式,我们对其进行运算,并得到对应的运算结果。
我们再检查运算结果是否在0~100中,如果不在,就再生成一个算式。
这样,我们就很快的实现了最初的原型设计
第二版原型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include <iostream> #include <time.h> #include <cmath> #include <map> #include <algorithm> using namespace std;
int N; const int M = 510; bool flag; char op[] = {'+', '-', '*', '/'}; map<char, int> f; int a[M], b[M], c[M], ans[M], check[M], w[M]; char ch1[M], ch2[M];
int f2(int a, char op, int b) { if ((a < 0) || (b < 0)) return -1; if ((a > 100) || (b > 100)) return -1; if (op == '+') return(a + b); if (op == '-') return(a - b); if (op == '*') return(a * b); if (op == '/') { if (!b) return(-1); else if (a % b) return(-1); else return(a / b); } return 0; }
void write(bool flag) { for (int i = 1; i <= N; i++) { cout << '(' << i << ") " << a[i] << ch1[i] << b[i] << ch2[i] << c[i] << "="; if (flag) cout << ans[i]; if (i % 3) cout << "\t"; else cout << endl; } }
void init() { f['+'] = f['-'] = 0; f['*'] = f['/'] = 1; srand(time(NULL)); for (int i = 1; i <= N; i++) { flag = false; while (!flag) { a[i] = rand() % 100; b[i] = rand() % 100; c[i] = rand() % 100; ch1[i] = op[rand() % 4]; ch2[i] = op[rand() % 4]; if (f[ch1[i]] < f[ch2[i]]) { ans[i] = f2(b[i], ch2[i], c[i]); ans[i] = f2(a[i], ch1[i], ans[i]); } else { ans[i] = f2(a[i], ch1[i], b[i]); ans[i] = f2(ans[i], ch2[i], c[i]); } if ((ans[i] < 0) || (ans[i] > 100)) flag = false; else flag = true; } } }
int main() { cout << "请输入需要生成的习题数量(0-500):"; cin >> N; cout << "正在自动生成习题" << endl; init(); int num = 0; cout << endl << "请按照题号依次输入答案,按回车自动进入下一道题" << endl; for (int i = 1; i <= N; i++) { cout << '(' << i << ')' << a[i] << ch1[i] << b[i] << ch2[i] << c[i] << "="; cin >> check[i]; if (check[i] != ans[i]) w[++num] = i; } cout << "您共回答正确了" << N - num << "道题目,答错" << num << "道" << endl; if (num) { cout << "您做错的题目分别为:" << endl; for (int i = 1; i <= num; i++) { cout << "第" << w[i] << "道,您输入的答案为" << check[w[i]] << "正确答案为" << ans[w[i]] << endl; } } else cout << "都答对了,你真棒!" << endl; return 0; }
|
在第二版中,我们在第一版的基础上添加了几个功能
- 能够选择需要回答的问题数量
- 能够和用户交互,输入答案
- 验证用户输入的答案
- 统计正确数量,给出错误的题号和正确答案
4. 结果和分析
经过很短的时间我们的项目原型就已经完成了,回顾上方的需求分析,我们已经完成了所需的功能
虽然给出了答案的正确与否,但是遗漏了正确率的功能
除此之外,这个程序的交互见面还过于简陋。如果按照需求的分析,项目的涉众是小学老师和小学生,如果还留着简陋的交互界面对于使用者来说必然是不适的,所以我们还可以有更多值得改进的地方
5. 实验体会
组员A:相比起原本自己敲代码的情况下,结对编程能够更高的提升效率,帮助我们在有限的时间内尽可能完成所需要做的工作。而且在有人查看的情况下,也更加容易在编码阶段就更容易发现代码中的错误,也能够关注到一开始没有注意到的问题。
组员B:在别人写代码的时候在一旁观看,能够学习到别人的编码风格和设计思维。每个人都会有自己的编程风格,所以不仅需要学会自己写代码,更重要的是学会看懂别人的代码。使用结对编程的方式迫使我们把注意力集中在工作中,而不容易被不相关的事情打断思路。
一些研究发现程序员结对工作与单独工作相比,会写出更短的程序,更好的设计,以及更少的缺陷。研究发现缺陷率降低15%到50%,会由于程序员的经验以及任务的复杂度而不同。结对编程比单独编程相比,通常会考虑更多的设计选项,达成更简单,更易维护的设计;程序员们也会更早地捕捉到设计的缺陷。结对编程与一个程序员承担同一个任务相比工作会完成的更快。结对的程序员经常发现当他们一同工作时表面上“不可能”的问题变得容易,或更加快速,或至少有可能解决。