Week2 结对编程总结

黄金点游戏 - 结对编程总结

这篇随笔是关于上周的黄金点游戏的一个总结。文中会根据作业要求介绍我们结对编程小组的工作内容、结果以及过程中的一些观察和思考。

在开始实现之前,用PSP表格记录下你预估完成项目需要的时间。

PSP表格:Personal Software Process,这里我们使用这种模型来回顾我们完成这次作业的流程和时间安排,但由于我们这次作业要做的是个很简单的 bot, 所以有些 PSP 中提到的环节并不存在于我们的工作内容中,所以用-表示省略。由于我们是非常紧密的结对编程,几乎所有时间都是在一起讨论和写代码的,所以不存在代码规范和设计复审等流程。(唯一的代码复审时间出现在第一天晚上我自己把基本框架写完,等到第二天我们再一起往里面加东西)

PSP各个阶段 预估时间(hrs) 实际时间(hrs)
计划 1 2
开发 9 7.5
· 需求分析 2 1
· 生成设计文档 - -
· 设计复审 - -
· 代码规范 - -
· 具体设计 1 0.5
· 具体编码 4 3
· 代码复审 0 0.5
· 测试 2 3
报告 2.5 2.5
· 测试报告 - -
· 计算工作量 0.5 0.5
· 事后总结 2 2
总共花费的时间 12.5 12

看教科书和其他资料中关于Information Hiding, Interface Design, Loose Coupling的章节,说明你们在结对编程中是如何利用这些方法对接口进行设计的。

这个问题可能不适用于这次我们的结对编程作业。在了解了上面几个名词的概念之后,发现他们更加适用于大型项目的设计。而我们的项目仅仅只用到了几个函数。不过一些思想是可以体现在函数设计上的。在之后的大型项目中,我们可能会用到这些设计思想帮助提高程序质量。

描述重要模块接口的设计与实现过程。设计包括代码如何组织,比如会有几个类、几个函数,他们之间的关系是如何的,关键函数是否需要画出流程图?说明你的算法的关键(不必列出源代码),以及独到之处。

首先简单介绍一些我们的 bot 的设计思路:
我们参考 Q-learning 的思想,但是实际并没有严格遵循它的模式,而是基于 state-action 这种组合模式,实现了一个简单的可在线学习的决策模型。
我们希望我们的 bot 能做什么事?
当开始新的一局游戏,我们希望我们的 bot 能利用此局之前的所有玩家输入和黄金点值的信息,计算出这一轮应该输出的两个 candidate 数。
具体到我们的决策模型下,我们希望在新的一句开始时,我们的 bot 能根据历史信息为当前局判断出一个状态,然后在一个动态可学习的状态-动作概率矩阵中找出当前状态下成功概率最高的一个动作,这个动作就是某一种我们设计的计算 candidate 的方法。
于是我们的最主要的工作就成了如何人工设计一组状态和动作,剩下的就只需要利用 Input 判断状态,然后查表选择动作就行了。
关于动作的设计,我们将一个动作(计算 candidate)划分为三个步骤,每个步骤存在三种可选择的操作,这样下来就一共可以得到 9 种动作。
这种动作的设计指导我们一一对应写出了状态的划分,但最终我们是通过一个概率矩阵来刻画两者之间的对应关系,并且这个矩阵中的概率会随着游戏结果而更新(这个过程可以认为是在学习一组策略)
理论上当我们用训练数据跑完400轮游戏后,更新的到的概率矩阵就是一组”学好的策略“。然而我们知道这种东西对训练数据的依赖性很大,所以我们最终决定选择在线学习的方式,即正式比赛初始时用的概率矩阵是均匀分布的,从头更新。

几个重要的函数:

函数名称 输入 输出 功能
create_state_dict() 自定义的状态划分标准 一个多级字典 建立状态字典(实际上是状态-动作概率矩阵
get_s() 所有历史信息 三个子状态的值(对应多级字典的索引) 根据输入信息判断当前状态
get_a() 经过处理的状态信息 计算得到的 candidate 根据状态选择动作计算 candidate
update() 历史信息中相应轮的黄金点值 根据历史信息更新状态-动作概率矩阵

再说一下所谓在线学习的事情,假设现在游戏进行到了 300 轮,那这时候我们会得到前 299 轮的数据。这时候,在计算输出当前局的我们的结果之前,我们先会拿前 299 轮数据做一次训练。即经过 299 轮更新,用这时候的概率矩阵去预测当前状态(round 300)应该如何计算输出值。这样也导致我们的运行时间线性增长,到后面需要一两秒才能输出结果。

阅读有关UML的内容。画出UML图显示计算模块部分各个实体之间的关系(一个图即可)。

在阅读了 UML 有关的内容后,发现在软件工程中提的最多的是 UML 类图。但是我们这次的作业代码很简单,并没有用到类,几个重要的函数在上面有给出简单介绍。所以就没有画出类图。有时间会补充一个简单的流程图。

看Design by Contract的内容,描述这些做法的优缺点,说明你如何把它们融入结对作业中。

Design by Contract:
优点:
规范的描述可以减少编程过程中的错误。
程序的鲁棒性强,质量高,更加可靠,不易发生异常错误。
缺点:
对于简单的程序,可能这样的要求会显得累赘。

程序的代码规范、设计规范。你们俩如何达成共识、采用什么规范?程序中是否有异常处理?你如何处理各种异常?

之前说过我们俩是”紧凑的“结对编程,所有 coding 的时间都是一个人在写另一个人在看的,所以不考虑其他人参与的情况,我们是没必要代码规范的,由于两人相关经验有限,并没有对某种设计规范很熟悉,所以在这次有限的时间内就没有采用什么设计规范。达成共识很简单:我们每写一个函数或变量,就同时告诉队友这是个什么东西,这个命名是如何想到的(例如,我想写一个 get_s函数获取当前局的状态,就一边写一边告诉对方我们这个函数是获取 state 的,所以是 get_s)

描述界面模块的详细设计过程。你的程序有用户界面么?在博客中详细介绍你如何设计你的界面模块。

没有用户界面。我们做只是一个 bot,这个 bot 不会和用户有直接的交互,按照游戏的进行方式,程序只需要通过 stdout 输出两个数字就行。

描述界面模块与其他模块的对接。详细描述UI模块的设计与其他模块的对接,并在博客中截图实现的功能。界面/控制/数据模块体现了MVC的设计模式了么?

根据上一个模块的说明, 这个模块对我们这次的作业并不适用.

描述结对的过程。提供两人在讨论的结对照片。遮挡和美化都是允许的。

我(左)和我队友(右)

(突然发现《构建之法》里面提到的结对编程要求两个人使用同一个键盘,然而我们这种操作只是在代码测试阶段,方便两者都能很快的修改某一处地方)
(而且从那 it 借来的电脑的键盘布局有点反人类233)

结对的过程整体来说是很紧密的,从一开始的讨论,对问题的定义开始,我们就是一起在讨论室讨论。因为两个人都是女生,交流起来都很有耐心,没有什么障碍。并且我们俩是同专业的同学,再加上我觉得我们两个水平差不多(所以不存在一个大佬全程带着飞这种情况),所以讨论过程中有啥不清楚的都会直接问,这个相互反复阐述想法的过程能很好地帮助我们理解问题和发现问题,我觉得这是很好的。我们基本上是比较严格的复现了《构建之法》中的”领航员“和”驾驶员“模式,并且轮流交换角色,且不说效率究竟如何,但是这个过程是比较舒适且能够保持整个下午都是专注的状态。

看教科书和其他参考资料中关于结对编程的章节,说明你们采用了哪种合作方式,以及结对编程的优点和缺点。a) 结对的每个人的优缺点在哪里(需列出至少三个优点和一个缺点)?b) 你如何说服你的伙伴改进他/她的缺点?请考虑一下三明治方法。
就像上一段说的,我们是”紧凑的“结对,比较严格的复现了《构建之法》中的”领航员“和”驾驶员“模式。
我们在第一天晚上做的事情大概就是把问题的定义和要做的事情弄明白,这个阶段由于不涉及coding,所以不存在”领航“和”驾驶“的动作,要我说大概就是”领航员“和”驾驶员“在出发前的某一个晚上,规划这次行程,的模式。
结对编程的优点

  1. 两个人干活不容易摸鱼,有时候一个人干活,如果遇到一时无法解决的问题就容易开小差,干别的事去了。两个人就不会这样,所以主要写代码的那天下午我们都觉得这么长时间下来我们能保持专注,挺难得的。
  2. 两个人写东西会有反复的阐述自己想法和理解别人想法的过程,这个过程可以帮助我们得到更好的解决方案

结对编程的缺点

  1. 效率问题,之前说到我们在工作过程中有”反复的阐述自己想法和理解别人想法的过程“。首先,这种过程本身就是比较耽误时间的花费耐心的(虽然我们这次并没有严重到这种程度),另外我们很难说这样反复商榷的出来的结论究竟是不是大概率比一个人做出来的要好。
  2. 时间安排问题。因为要遵循书上说的结对编程模式,我们必须找到两个人都有时间的时候来干活,这样在时间安排上会有些不方便,而且有时候都有空闲的时间并不一定能同时满足两个人的工作习惯。

个人的优缺点
优点:

  1. 尊重对方,说话有耐心有条理,沟通无障碍无冲突。
  2. 合作意识强,愿意花时间两人坐在一起讨论问题和写代码。
  3. 具备一些我不是很熟练的能力(例如 debug)
    缺点:
    这是我们俩都有的缺点,就是写出来的代码不太好看,函数功能设计得比较杂。
    如何说服队友改进缺点
    这次过程中,合作很顺利,我觉得我队友挺好说话的,所以没有遇到这种情况。不过书中的三明治方法看起来的确不错,之后有机会会考虑用到。

在你实现完程序后,请在PSP表格中记录下你在开发各个步骤上实际花费的时间。说明差异的原因。

这一列得内容也写在上面的表格中了,其中计划的时间比预估要长。因为第一次讨论过程中,发现我和队友对于问题的定义有些出入,所以我们花了一些时间讨论统一意见。
然后具体编码的时间并没有那么长,因为发现经过讨论后得到的方案挺简单的,写起来并不麻烦。

收获、心得体会

写这篇随笔的过程中又从头把这次的作业梳理了一遍,发现代码中存在很多不足的地方,整个设计思路也没有很清晰。
当时可能是由于时间比较紧张,对自己后面能否实现代码也没有信心,所以在简单讨论之后就开始写代码了,并没有做充分的前期记录和设计复审工作。
讲道理,在动手写代码之前把要做的事情写下来梳理一遍,后面的问题会少很多,出了问题也好找原因。但这次就是迷迷糊糊地想出一点头绪之后就开始写代码了吗,幸好期间和队友一直保持沟通,最后写出来地东西还算有点条理。可能这也是结对编程地优点之一吧。说到工作内容,老实说我们组的策略考虑并不周全,其他队伍大多考虑了”捣乱策略“,这个我们是没用的,我们两个人都比较保守,这也导致我们对整个局势的预估出现了偏差,在第二盘激烈震荡的黄金点走势中表现得很不理想。不过看到第一盘的结果,我想我们的 adaptive 的策略算是有点用的。
总的来说,以后写东西会更加注意前期的文档工作,至少要先理清楚整个流程,写下来,然后在开始写代码,并且写代码时明确自己在做什么。

posted @ 2018-10-21 22:28  azshue  阅读(152)  评论(2编辑  收藏  举报