实验二 结对编程(内容更新)

实验二  结对编程实验(内容更新)

 

一、实验目标:

1)体验敏捷开发中的两人合作。

2)进一步提高个人编程技巧与实践。

 

二 、实验内容:

1)根据以下问题描述,练习结对编程(pair programming)实践;

2)要求学生两人一组,自由组合。每组使用一台计算机,二人共同编码,完成实验要求。

3)要求在结对编程工作期间,两人的角色至少切换 4 次;

4)编程语言不限,版本不限。建议使用 Python 或 JAVA 进行编程。

  

实验内容:

一.查阅相关资料加深对敏捷开发和结对编程的理解

敏捷开发:

百度百科:敏捷软件开发(英语:Agile software development),又称敏捷开发,是一种从1990年代开始逐渐引起广泛关注的新型软件开发方法,是一种能应对快速变化需求的软件开发能力。它们的具体名称、理念、过程、术语都不尽相同,相对于“非敏捷”,更强调程序员团队与业务专家之间的紧密协作、面对面的沟通(认为比书面的文档更有效)、频繁交付新的软件版本、紧凑而自我组织型的团队、能够很好地适应需求变化的代码编写和团队组织方法,也更注重软件开发过程中人的作用。

理解:敏捷开发是一种基于更紧密的团队协作、能够有效应对快速变化需求、快速交付高质量软件的迭代和增量的新型软件开发方法。此方法更关注协作、质量、可工作的产品、全才华的专才,基于实践而非基于理论。

结对编程:

百度百科:结对编程(英语:Pair programming)是一种敏捷软件开发的方法,两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。输入代码的人称作驾驶员,审查代码的人称作观察员(或导航员)。两个程序员经常互换角色。在结对编程中,观察员同时考虑工作的战略性方向,提出改进的意见,或将来可能出现的问题以便处理。这样使得驾驶者可以集中全部注意力在完成当前任务的“战术”方面。观察员当作安全网和指南。结对编程对开发程序有很多好处。比如增加纪律性,写出更好的代码等。结对编程是极端编程的组成部分。

理解:在实际结对编程中不仅只是编程活动,也包括一起分析、设计、测试等全程活动。同时结对编程有助于高质量完成项目 。

 
二.github的学习过程
①github使用自己的仓库
首先运行mkdir -p+文件夹名字/+项目名字 && cd $_创建一个文件夹并添加一个自己需要的项目目录,运行git init转换成git仓库。在目录下添加自己需要的文件,运行git add .git commit 提交commit。
然后在github上创建一个自己的仓库,运行git remote add +远程仓库简写名 (如origin)+自己仓库的url用来创建和管理远程仓库,运行git remote -v验证。
再运行git push +远程仓库简写名( origin) +接纳我们commit的分支(如master),将本地 commits 推送到远程仓库。
!!!当远程仓库上存在一些 commit ,但我们的本地仓库上没有这些 commit时(如合作时):先要运行git pull +远程仓库简写名(如origin) +需要拉取 commit 的分支名称(如master),然后再提交commit和push。

②github使用别人的仓库

fork项目——克隆项目到本地git clone——(设置上游远程仓库git remote add——同步远程仓库git pull——设置本地分支git check out master——合并上游项目和本地项目git merge)——提交本地更改,更新远程仓库git  push——提交pull request

首先选择一个需要的作者的项目点击fork 按钮将其复制到我们的账户,自选一个文件夹的目录下(非git仓库)运行git clone+复制过来的我们账户项目url 克隆仓库到本地。

再进行修改、添加文件并git add .git commit之后,运行git push +远程仓库简写名(如origin) master,将本地修改push到自己远程仓库的master(默认)分支上 。(也可以先运行git checkout -b +特性分支名,再运行git push +远程仓库简写名+特性分支名,将本地修改push到自己 远程仓库的特性分支上 )。

!!!若原项目作者对项目进行更改了,我们的 fork 中不会获得这些更改,所以先要将她的项目添加为额外远程仓库,以便与她保持同步。运行git remote add +新的远程仓库简写名(如upstream)+原作者项目仓库地址。然后运行 git fetch+新的远程仓库简写名  master,获取仓库更新(可运行 git status查看更新情况),再运行git merge +新的远程仓库简写名/master(确保在master分支下)合并原作者的更改,然后运行git push +远程仓库简写名(origin)  master,即可与原作者仓库保持一致,再进行文件修改等commit操作,然后再次push即可。

最后向原作者仓库提交拉取请求。

 

三.组队过程,所选择的课题

♥组队过程:

 

♥所选择的课题:生命游戏——感受数学思想与老子“三生万物”智慧的不谋而合。

规则:游戏开始时, 每个细胞可以随机地(或给定地)被设定为“生”或“死”之一的某个状态, 然后,再根据如下生存定律计算下一代每个细胞的状态: 每个细胞的状态由该细胞及周围 8 个细胞上一次的状态所决定; 如果一个细胞周围有 3 个细胞为生,则该细胞为生,即该细胞若原先为死则转为生,若原先为生则保持不变; 如果一个细胞周围有 2 个细胞为生,则该细胞的生死状态保持不变; 在其它情况下,该细胞为死,即该细胞若原先为生则转为死,若原先为死则保持不变。

 

四.开发平台和技术工具、协同工具的选择

我和队友在经过讨论后最终还是选择了以最为熟悉的C语言作为此次编程的语言,开发平台我使用的是Dev-C++,队友使用的是Visual C++,协同工具采用了QQ的远程分享屏幕和通话。

 

五.结对编程的过程

☀分析生命游戏的游戏规则,我们采用了QQ远程分享,进行探讨:

我们将游戏规则黏贴在ppt上,然后通过屏幕分享进行讨论,将重点内容做出标记,如随机地定义细胞“生”和“死”我们就决定用rand( )函数来做,然后分析细胞状态,可能由于一开始我分析的时候就定性思维地先把细胞分别成活的和死的来看,导致后面由我编写此部分代码的时候就写的比较冗长。(后面有贴出来对比)

 

☀讨论怎样去计算一个细胞周围的生命数,然后设计了整个游戏的函数模块:

我们一开始讨论细胞周围的生命数时,就以最普通的情况来进行讨论的,没有考虑到边界的情况,后来我们想到了一种解决方法,就是在初始化细胞地图的时候i=0开始,而细胞变化的地图从i=1开始,即将最外的那一层细胞作为边界,就可以保证里面的细胞都能够满足普通情况的游戏设定。

函数模块的设计时,我们并未考虑分成多个模块,3个简单的模块更容易我们去理解和编写后续代码。

 

☀一起开始写程序:

在写程序的过程中,我们进行了编写和检查的角色互换。但可能是我们的算法比较简单,考虑实现的也比较朴素,所以我们的代码量比较少,然后我们的角色互换也就不需要很频繁。

 

☀一起完成github上的一系列操作:

编完自己部分的的代码之后,我们一起将自己的代码Push到仓库中,共同牢固我们所学的github的一系列命令和操作,我们一开始提交commit的命名也是没有想太多,以名字加次数命名,后来觉得不妥,又回归到正规的以具体修改,添加了什么内容来进行命名。

 

 

☀一起完成程序测试和debug :

虽然是一起的结对编程,但是也有出错的地方,譬如字母的拼写错误,头文件的问题,界面以及刷新时间问题以及后来修改代码的问题等等,说明在编程过程中不放错误真的很难,但是通过检查不断修改正确也未尝不是一件好事。所以在经历不断地出错和修改下最终我们共同完成了编译,成功运行了此次程序。

 

六.具体的程序设计与实现

●编码规范

1.命名规范

函数命名和变量命名我们均采用帕斯卡命名规范,即大驼峰式。尽量做到了容易理解和记忆;

宏定义命名均为大写。

2.代码编辑排列规范

变量、数组的定义尽量放在最开始处;

函数间使用空行分开,每个函数定义时写注释;

核心代码写上注释,说明具体完成什么功能;

注释不应太多,注意简明扼要;

循环、判断语句的代码采用缩进风格;

程序块的分界符"{"和"}"各占一行。

●程序总体设计

 

●功能实现情况

基于生命游戏最基本的游戏规则,我们设计的十分简单,总共由三个部分组成,一个主函数main( )模块,一个游戏数据初始化RawDate( )模块(用来初始化地图内的细胞生命状态),一个游戏RunLifeGame( )模块(地图的输出和细胞周围生命的数量计算以及细胞下一代状态的判断都包括在其中)。用CellsMap表示当代细胞状态地图,NewCellsMap表示下一代的细胞状态地图。具体可看如下代码,代码量不多,写的也很基本,所以直接放在下面:

 1 #include "stdio.h"
 2 #include "string.h"
 3 #include "windows.h"
 4 #include <iostream>
 5 #include <time.h>
 6 #define HIGH 20  //游戏尺寸
 7 #define WIDTH 40
 8 
 9 int CellsMap[HIGH][WIDTH]; //初始状态细胞地图 
10 int NewCellsMap[HIGH][WIDTH]; //下一代细胞地图
11  
12 void RawDate()   //游戏数据初始化
13 {
14     srand((unsigned)time(NULL)); //srand()就是给rand()提供种子seed 
15     int i,j;
16     for(i=0;i<HIGH+1;i++)
17         for(j=0;j<WIDTH+1;j++)
18            CellsMap[i][j]=rand()%2;   //细胞初始状态随机
19 } 
20 
21 void RunLifeGame()    //进行游戏
22 {
23     int i,j,s=0;
24     while(1)
25     {   system("cls"); 
26         for(i=1;i<HIGH;i++)  //打印初始状态细胞地图 
27         {
28             for(j=1;j<WIDTH;j++)
29                 if(CellsMap[i][j]==1)
30                     printf("");
31                 else if(CellsMap[i][j]==0)
32                     printf("");
33             printf("\n");
34         }
35         for(i=1;i<HIGH;i++)
36             for(j=1;j<WIDTH;j++)
37             {     /*计算一个细胞周围8个格子内的活细胞总量*/ 
38                 s=CellsMap[i-1][j-1]+CellsMap[i-1][j]+CellsMap[i-1][j+1]+CellsMap[i][j-1]+CellsMap[i][j+1]+CellsMap[i+1][j-1]+CellsMap[i+1][j]+CellsMap[i+1][j+1];
39                   if(s==3)            //周围有3个活细胞时,该细胞下一代转为生细胞 
40                      NewCellsMap[i][j]=1;
41                  else if(s==2)       //周围有2个活细胞时,该细胞下一代状态不变
42                      NewCellsMap[i][j]=CellsMap[i][j];
43                  else
44                      NewCellsMap[i][j]=0;  //其它情况时,该细胞下一代转为死细胞
45             }
46         for(i=1;i<HIGH;i++)  //打印新一轮细胞地图 
47             for(j=1;j<WIDTH;j++)
48                 CellsMap[i][j]=NewCellsMap[i][j];    
49        Sleep(1000);  
50     } 
51 }
52 
53 int main()
54 {
55     system("color f0");
56     RawDate();
57     RunLifeGame();
58 }

 

//上面细胞下一代状态判断的部分因为我一开始的定性思维分析写的是下面比较啰嗦的一种,后来由队友分析过后简化改成了如上的代码

 1 if(CellsMap[i][j]==1)   //如果细胞为生 
 2 {
 3    if(s<2)
 4        NewCellsMap[i][j]=0; //如果周围活细胞少于2个,该细胞下一代转为死细胞
 5    else if(s>3)
 6        NewCellsMap[i][j]=0; //如果周围活细胞超过3个,该细胞下一代转为死细胞
 7    else if(s==2||s==3)
 8        NewCellsMap[i][j]=1; //如果周围活细胞为2个或3个,该细胞下一代状态不变 
 9 }     
10 else if(CellsMap[i][j]==0)  //如果细胞为死 
11 {
12    if(s==3)
13        NewCellsMap[i][j]=1;  //如果周围活细胞为3个,该细胞下一代转为活细胞,其它情况状态不变 
14    else
15        NewCellsMap[i][j]=0;
16 }     

 

最后的运行结果如下( 有点卡顿的地方是gif转换的问题):

 

七.项目github地址

( https://github.com/hfh123/Life-Game

 

 

 

 

八.结对编程过程中遇到的问题

此次结对编程过程中,在有关游戏代码方面并未出现较大问题,可能是因为我们的追求比较低,目标只是简单地实现了游戏,代码方面未多的考虑到规范性和性能优化等方面。github的结对操作作为此次的重点掌握内容,我们在实验一般的操作过程中并未出现问题,但是后期在我的仓库上又添加了一个JPG分支时,队友更新到自己仓库时出现了问题,只有一个master分支:

 

 

原因是队友fork过来的仓库中只有一个master分支,而我的JPG分支是后来添加的,队友fork过去的时候并未有这个分支,后来pull和push的时候我们都定性思维的到了master分支,实际上应该先在本地创建对应的特性分支,再push到自己远程仓库的特性分支上:

 

然后再进行拉取请求(注意拉取的是源仓库的对应分支,我们这里又双叒叕拉取到了我的master分支去了o(╥﹏╥)o):

我的仓库:

队友的仓库:

 

 

九.实验小结

一起结对编程当然不仅仅是一起敲代码,还有一起对问题的讨论和分析,这样的讨论比一个人的思考更有利于问题的快速解决,在互换角色编写代码过程中,领航员的角色实际上也是特别重要的,时刻关注写代码人的代码是否出错,以及给出一些实际上的建议。并不是原先以为的很清闲的身份。从这次我的感受出发,我觉得相对于一个人的编程,两个人的结对确实要更有意思的多。学习既是一个独立钻研的过程,又是一个需要小组互助、需要彼此激励的过程。与同伴合作学习带给学习者的结果往往是1+1>2。要利用学习同伴的个性力量和潜能,最好的方法就是共同学习,合作完成任务。每个人对问题的理解常常不同,各种差异便构成了一种宝贵的学习资源。所以在这里也要感谢队友的积极参与,使我在此次试验中一定程度上认识到了什么是结对编程,同时感受到了结对编程的魅力。对于github的操作方面,我和队友在经过一次次相互的pull和push的过程中也能基本渐渐熟悉。所以总的来说,此次结对编程基本完成了实验目标,但我们的代码实现相对于很多其他语言写出来的要显得单薄许多,所以对其他语言的学习和掌握还有待提高,希望后面能够用所建议的python和java语言来更好的实现我们的课题。

 

 

 

 

 

 

 

 

posted @ 2020-03-22 20:13  hfh吖  阅读(239)  评论(1编辑  收藏  举报