结对编程总结
关于这次结对编程的总结
——163 李雁楠 (173 张孝祖)
缘由:
这一次pair project,我和7班的张孝祖同学分在一个团队。结对情况刚一分布,张孝祖同学便非常积极地找到了我,并交换了电话以便联系。不过,此时我还对作业的情况不太清楚。于是,我们相约分别先将作业题目看一遍,并各自先思考以后再一起讨论。
作业要求:
这次的作业是设计一栋21层高的楼里的4个电梯的运行算法,每个乘客重量m kg(m的平均值为70,且45<=m<=120),楼层分布为0~20,0层为停车场,故0,1楼的流量最大。以下是老师给的:
1) A set of API
2) A naive solution (BUS program)
3) A set of test cases to run
磨合历程:
由于开始并不知道老师已给出部分代码,我们还为整体构架而纠结了好久。不过,我们知道后就立刻从组长手中拿到了老师给出的源程序,而我们只需将程序框架看懂,并将电梯的运行程序的算法改进,优化即可。于是,我们再次联系,决定分别回寝室研究透原代码,之前对于框架的构思便毫无用武之地了,不过,这些对于我们从一个编程者的角度理解老师的程序也大有帮助。
这是讨论时的情景——才怪…
这是专门摆好,请他舍友帮忙拍摄的合照,仅为纪念
算法分析:
之前我们也询问了其它小组的一些想法,经过讨论以后决定的算法是:就像日常所用的电梯一样,对于每一个电梯外的人来说,他们提出一个请求后,电梯内部会根据方向来判断让哪一个电梯去载,判定标准为是否有电梯的行进方向上有这一楼层,且行进方向与该乘客的方向一致,若无,则让未行进的电梯去完成这一任务。然而,在编程时,由于这一算法实现起来过于复杂,且还有许多的判定优先级需要去考虑,最终难产了。于是,下面的这个算法诞生了……
最后实现的算法:
为每个电梯都设置一个等待队列,对于每个电梯,进行如下操作:
(1)在其静止时,若其等待队列有请求时,分4种情况讨论:1电梯在提出请求的楼层上方,请求方向向下,则去提出该方向请求的楼层中最近的一层;2 电梯在提出请求的楼层上方,请求方向向上,则去提出该方向请求的楼层中最低的一层;3 电梯在提出请求的楼层下方,请求方向向上,则去提出该方向请求的楼层中最近的一层;4 电梯在提出请求的楼层下方,请求方向向下,则去提出该方向请求的楼层中最高的一层。
(2)在其运行时,若是上行,若是中途经过的层中有请求,且方向一致(即上行),并仍有一人的余量(此处出于人道主义,取的是45KG,即最轻的重量,因为外面的人如果仅有45KG,取别的数字将会使得此人眼睁睁的看着电梯经过),则该层的上行请求将被接受,电梯到达该层将会停留;同理,在其下行时,若是中途经过的层中有请求,且方向一致,并仍有一人的余量,则该层的下行请求将被接受,电梯到达该层将会停留。
UML图:
完成感想:
其实最后选择这个算法也是很无奈的,主要是自身的经验不足外加能力有限,在deadline之前无法将脑海中早已拟好的算法实现。这给了我一个深刻的教训,在开发前,一定要正确判断自身能力,预估好工期,合理安排计划,这样才能顺利的完成每一个工程。
结对的优缺点:
结对对于我们来说,其实是相当合适的,首先,我们2个对于程序的开发都稍有欠缺,而结对的时候,不懂得地方可以互补;其次,每个人思考一个问题的角度都不一样,对于算法的分析也有局限性,而2个人一起,可以使得思考比较全面,提高代码质量;最重要的,“当局者迷”,有另一个人在一旁,bug将会很快被找到,相信很多人有过这种经验,做错了一道不算很难的数学题,然后不管检查了多少次都找不出错来,而他人在旁边一眼就看出来了,以前编程时有一大部分时间是花在debug上,而现在将大大缩减工期。
不过,结对编程也并并非只有优点,遇到以下情况也挺糟糕的:
1、2人的水平都不高,对于某些问题,2人都无法解决,此时0+0=0,结对毫无益处;
2、2个人思维方式的不同,也会导致一些无法融合的争执,将使进度停滞;
3、对于不太熟悉的2个人来说,磨合可能需要很长一段时间,将会影响工期。
自我评价:
1.写代码次数多,代码风格好;
2.理解力强,能够比较快的理解新东西;
3.思维清晰,对于整体构架有一定的理解;
4.行动的”矮子”,对于自己的新想法总是懒于动手,很少实现。
伙伴评价(张孝祖):
1.积极活跃,接到任务后立刻联系我,遇到重点、难点主动找我一起解决;
2.思维敏捷,对于算法出现的问题总是有着其独到的见解;
3.求知欲强,虚心向学,在构思中遇到的问题,还有编程中遇到的一些我们无法解决的麻烦,他会向同班的经验丰富的同学请教;
4.性格较急,和我的节奏不太相合,作为他的伙伴,压力较大
总的来说,作为他的队友,还是非常开心的,因为性格比较怠懒的我,总是会将不着急的事情搁置一旁,这样的话,经常会因为对工期和工程量的误判导致最终任务的拖延,有了他的提醒和督促,才使得最终任务能够顺利的完成!
关于设计方法:
Information Hiding (信息隐藏):模块之间通过他们的api通信,一个模块不需要知道另外一个模块的内部情况,这就被称为信息隐藏。这样可以有使得模块可以独立开发,测试,优化,修改,理解,促进系统开发的速度,因为这些模块可以并行开发;同时也减轻了维护的负担,因为维护人员可以更快的理解这些模块,并在调用的时候不影响其他模块;提高了软件的可重用性,因为模块之间不紧密相连,最后封装也降低了构建大型系统的风险,即使整个系统不可用,但是这些模块可能是有用的。
interface design (接口设计)把公共的非静态方法和属性组合起来,以封装特定功能。我们可以将模块中一些固定的特定功能封装成接口。一方面我们可以利用这些接口实现固定功能的不同实现方法,使得不同的实现方法可以更加灵活的运用,另一方面在程序的维护和升级阶段,我们可以扩展接口,实现更加完备的功能,方便特定功能模块的管理。
loose coupling (松散耦合),經過細分化后的模組之間的關聯性較小,相互的影響程度不大的一种状态。在“Loose Coupling”架構下的个个模組之間,雖然有相互連結,但是彼此的依存度較小,在变更或者修改模組時的柔軟度較佳。相对的緊密耦合(tight coupling),处理速度上会較快,但是因为彼此之間的關聯性較大,在变更或者修改模組時,必須考慮必須周詳。系統如果是鬆散耦合,沒有使用特定的技術和語言開發,當业务或交易对象發生變更時,也能够迅速对应。
Design by Contract(契约式设计)
Design by Contract的核心是断言(assertion)。所谓“断言”,是指永远为真的布尔型语句,如果不为真,则程序必然存在错误。通常情况下,检查断言的时机,应该局限于调试(debug)阶段,而不是代码的实际执行阶段。实际上,完成的程序永远不应期望断言会被检查。在继承关系中,断言扮演着独特的角色。继承的风险之一在于,开发人员为子类重新定义的行为,可能会违背父类的行为。断言减少了这种风险。对某个类来说,其不变量和后继条件必须能够应用于所有的子类。子类可以加强这两类断言(也就是说,增加更多的限制),而不能削弱它们。而前提条件则只能削弱,而不能增强。
优点:
契约能使文档更出色,它是类特性的公开视图中的固有成分,有着更可靠的文档,运行时要检查断言,以便保证制定的契约与程序的实际运行情况一致;断言定义了测试的预期结果,并且由代码进行维护,使程序有明确的测试指导,既能够获得精确规范得到的益处,同时还使得程序员继续以他们所熟悉的方式工作。
缺点:
断言不能沿着继承层次往下遗传。
Code Contract(程式码合约)
Code Contracts是.NET Framework 4.0的新功能,它是微軟对契约式編程(Design by contract)概念所提出的一种解決方案,主要由前置條件(Preconditions)、后置條件(Postconditions)、與物件非變異(Object Invariants)這三大契约所構成,可以很容易的为程式碼加入驗證程式碼,降低程式的錯誤發生率,提高程式的品質,也可以整合单元測試,減少单元測試的工作量,甚至整合文件產生器,讓產出的程式文檔更为詳細。
优点:
提升自动测试程度,提供静态验证,执行阶段,验证文件产生。