结对编程
Part One: 结对编程的感触和认识
eXtreme Programming 极限编程中对结对编程的描述:
结对编程(Pair Programming)是一种敏捷软件开发实践,指两个程序员并排坐在一台电脑前,面对同一个显示器,使用同一个键盘和鼠标一起工作。一个人输入代码,而另一个人审查他输入的每一行代码。输入代码的人称作驾驶员,审查代码的人称作观察员(或导航员), 两个程序员定期互换角色。他们在一起完成需求分析、系统设计、编码、单元测试、整合测试(Integration Test)、写文档等工作。基本上所有的开发环节都一起肩并肩地、平等地、互补地进行工作。
“理想状态”下结对编程有以下的一些优点:
- 有利于提升项目质量,减少Bug;
- 有利于知识传递,降低学习成本;
- 多人熟悉同一段代码,减少项目风险;
- 与别人一起工作会增加责任和纪律性;
- 使得可以在讨论中更加愉快高效的解决问题等
可是现实情况却不是如此,我们的结对编程过程并没有感受到那些优点。。。下面是我的一些思考和反思。
初期憧憬的结对编程过程:
我个人来说还是很希望能够和搭档一起来进行项目开发,就像标准的结对编程那种模式,每个环节都在一起讨论协作完成。因为一个人在写程序的时候总会有思维的局限性,导致很多细节的地方容易忽视,从而容易产生错误,在实现方案的考虑上也会因为缺少讨论争执而不能有很好的改进。所以当时对结对项目感觉是一片美好~~~
实际的结对项目开发过程中的情况:
a. 我的搭档是我大学前两年从未接触过的隔壁班的同学,有比较强烈的陌生感
b. 两人的互相了解不深,各种学校活动和生活安排很不相同导致没能进行很好的交流(有一次)
c. 由于缺乏沟通和了解,我们最终选择分工,我来完成核心模块和测试模块,队友完成界面模块
d. 最终导致效率并没有提高,结对编程的那些优点完全没有体会到。。。
反思以及对未来结对编程的看法:
1、假设队友是随机产生的,甚至可能是初次谋面的
以后我一定要先请队友去吃顿饭。。。互相了解、打破隔阂是后期项目开发效率产生的第一步,要互相留下好的印象。
然后能够根据两个人的特点来对后期项目的开发进行规划和安排。
只有两人能够特别自然随意得进行交流,在问题上面能够有自己的独立想法,这样在开发过程中才能对队友放心。
(当队友是个熟悉的人,上面这条基本不用在意)
2、制定代码规范
不同人的编码习惯实在是不同,不知道队友对我的习惯是否满意,不过队友的代码风格确实让我感觉很难受。这个环节在沟通交流中一定要在一开始就做好。
3、关于如何提高结对编程的效率
一定要事先有很好的进度规划,然后安排好一起合作的时间。
在一起工作的时候,要求都能够保持专注 ,尽管是有两个人,但是只有都专注于思考才能发挥结对的作用。
有不同的意见一定要及时的提出来,一起讨论一起思考,这样才能够使项目得到完善。
最后想问一个问题:
结对编程的话,寻找合适的搭档不应该也是很重要的事情吗?是不是能考虑在下次结对编程中允许自己选择比较熟悉的搭档呢?
-------------------
(队友 @Myskety)
队友应该是个比较乐于助人,比较实在的一个人;
也是个随和的同学,好像什么都愿意听我的。。。
由于了解还不够深,我也不好再往下说。但是我的一个看法是希望他以后能够更加自信,更加有想法。
最后祝愿我们都能快乐学习,天天向上~
@Me: 能想、能看、能写。缺点就是时间把握上老是出问题,有那么点强迫症,但是说白了就是有点爱磨蹭。
Information Hiding [技术介绍]
Definition:
Information hiding for programmers is executed to prevent system design change. If design decisions are hidden, certain program code cannot be modified or changed. Information hiding is usually done for internally changeable code, which is sometimes especially designed not to be exposed. Such stored and derived data is not expounded upon, most generally. Change resilience of classes and ease of use by client objects are two byproducts of hidden data.
Encapsulation Is Not Information Hiding [相关阅读]
InformationHiding is the idea that a design decision should be hidden from the rest of the system to prevent unintended coupling.
Encapsulation is a programming language feature.InformationHiding is a design principle.
InformationHiding should inform the way you encapsulate things, but of course it doesn't have to. They aren't the same thing.
Interface Design
- 使用接口是为了提高提高系统的 灵活性、可扩展性、可插入性 、 可复用性、可维护性 、可测试性。
-
一个好的接口能够提供给后面的程序设计一个良好的框架。这对于团队项目来说是非常有用的一种设计。团队合作中,有明确的分工,每个人负责不同的模块,
这种情况下我们定义一套公用的接口用于模块间的通讯,为我们提供了一种面向接口的编程思想,同时可以在某一模块未完成时供另外的编程人员使用,大大提高
了团队编程的效率。
- 接口设计的六大原则有:Single Responsibility Principle,Liskov Substitution Principle,Interface Segregation Principle,Dependence Inversion Principle,Least Knowledge Principle,The Open Closed Principle
Loose Coupling [技术介绍]
通过设计使得类与类之间的依赖性变低,类与类好像是隔开了一样,它们之间仅仅通过消息来联系。所以我们在进行代码设计时,不用担心会破环其他地方的代码当代码有改动时,不用大规模的改动代码。
Design by Contract
[参考文献]
The benefits of Design by Contract include the following:
- A better understanding of the object-oriented method and, more generally, of software construction.
- A systematic approach to building bug-free object-oriented systems.
- An effective framework for debugging, testing and, more generally, quality assurance.
- A method for documenting software components.
- Better understanding and control of the inheritance mechanism.
- A technique for dealing with abnormal cases, leading to a safe and effective language construct for exception handling.
契约编程建立起使用者与编程人员之间的某些规范。比如说契约设计中会约束某一方法在调用时对传入参数的要求,以及方法对返回值的约定。契约编程对于程序设计者来说无疑是相当方便的。上学期的面向对象中,一直被要求使用防御式编程,编程人员要时刻考虑恶意输入的情况,单是处理这一方面就要花费大量的气力。本次程序中,由于是命令行程序,就要求用户在输入指令时的参数形式等等遵循一定的规范,还有对于给定算式结果的正误判定模块,也要求给定的算式不允许出现其他无关的特殊字符的情况。这对于我们程序的编写来说提供了很大的便利。
Unit Test
在单元测试中主要对一些基础类的运行进行测试,具体在这个项目中有BaseCalc,NumItem,Expression.
其中BaseCalc中是一些自定义的计算,比如辗转相除法求最大公约数等,这里是为了验证这些方法的正确性。
NumItem中是自定义的存放计算中的数的类,以分数的形式来存所有的数,在这里做了单元测试验证计算的正确性,以及基本的toString等转换方法的正确性。
Expression主要是表达式,由于表达式涉及到的方法是生成,这个过程中涉及到了随机数,所以无法保证结果的唯一性,在测试过程中于是主要集中对生成表达式的一些属性范围进行验证。
单元测试覆盖率
关于做单元测试的一些感受:
1、使得整个开发过程中感觉一步一个脚印,能够非常得踏实,很有步步为营得感觉。
2、有利于时刻保证项目开发的有序性,从而使得能够更好地把握整体的框架。
3、测试一定要严格全面!!!
在开发过程中,由于给基础类都做了覆盖率较高的单元测试,但是这里一定要注意“覆盖率高不等于正确性好”,开发到后面发现了一个bug,在寻找的过程中由于过度相信单元测试导致对先前的基础方法的正确性没有进行怀疑和检查,由于找bug时的目标错了,导致白白浪费了好几个小时,确实心酸。。。
总的来说,单元测试还是给了我们很大的帮助。
但是以后再进行单元测试时,一定要根据条件语句的走向设置更加全面的单元测试~
UML
架构分析:
BaseCalc这个类中封装一些后面其他类中需要广泛用到的方法。
NumItem这个类是自己构建的一个专门记录四则运算过程中出现的所有可能的数,里面都用分数形式表示,并且对正负进行了记录,并且定义了toString()、toDecimalForm()、randomToString()方法,分别用于分数形式表示数字、小数形式表示数字、随机形式表示数字(满足生产表达式的随机性)。并且在这个类上重写了加减乘除运算符,从而能够方面后面的使用。
Expression这个类基于NumItem基础,表达式的生成采用从在子表达式基础往上添加一个运算符一个操作数的形式,getAdd等四个函数表示的是添加的运算符的类型,这样做的好处是为了能够将用户对表达式中的各种限制要求使用上去。然后构造函数中就采用了随机生成表达式的,这个类有一个缺点就是随机性导致无法很好得进行单元测试。
NumItemException这个类是自己定义得一个异常。
Arithmetic是模块的顶层:
- 在这层的generateArith是用于生成指定数目和限制要求的表达式及答案的;
- checkArith是用于检验一个四则运算式子字符串的运算值是否与给的答案字符串表示的值一致,为了方便单元测试做的;
- checkFile是将checkArith直接运用到文件上面,从而分析文件中的所有问题的答案是否正确。
通过调用Arithmetic中的函数,在UI中可以直接使用ArithCore核心模块中的东西,同时Console的Runningtest也可以通过这个很好得运行起来。