结对项目的感受

一、合作编程

合作编程是非常愉快的一件事,我们两个彼此信任,分工明确,一起开发了“小学数学习题助手”这个软件。

这个软件主要有题目生成、检验答案、计算器三部分功能。题目生成部分可以按数量、数值上界、运算符数量、是否包括括号、分数、乘除法、负数来设定要求,存储在默认文件或用户指定文件中。检验答案可以从用户指定的算式以及答卷文件中读取并进行判卷,结果存储在成绩文件中。计算器则可以输入一个算式,计算出答案。

 

这次结对编程中,我主要负责窗体与前端,鲁聃主要负责后端,负责维护计算核心dll。结对编程的方式很明显地增加了每个人的专注度,使每个人得到合理适量的任务压力,并顺利地完成。结对编程的缺点可能就在于增加了沟通成本,我与鲁聃经常需要对dll接口、传参细节、异常处理与各种细节问题沟通,很庆幸我们两个给对方的反馈都很及时,没有造成工作效率的影响,但是可以预想,如果两个人对于分工结合部分不明确,又不能及时沟通,会造成效率的降低。

鲁聃的优点在于,对计算核心模块精益求精,使计算核心DLL功能强大而独立,为前端提供了简单明确的接口,以及强大的字符串读入识别处理与字符串输出功能,对于我在使用DLL中的疑问与发现的bug,可以很快地回应与更新DLL;此外,软件功能基本完成后,对软件功能进行充分地测试,检测了软件的稳定性、正确性,也发现了一些bug并更正。

我的优点在于,有较好的用户体验感觉,清楚界面前端如何设计会让用户感到舒服,交互流程如何设计会自然,那些信息需要传达给用户,比如使用说明等。我的缺点是做事比较急躁,尤其遇到用户界面这样琐碎的处理流程,经常会出些bug。

 

二、关于 Information Hiding, interface design, loose coupling

1. Information Hiding,信息隐藏,信息封装是结构化与面向对象设计的基础。在我们的“小学数学习题助手”软件开发中,时时都在使用 Information Hiding原则。我做前端,不需要看鲁聃的工程文件,不需要看鲁聃的代码,只需要鲁聃给我提供一个DLL还有一份接口说明。鲁聃维护计算核心,只需要将接口维护好,前端的设计、布局、用户交互等不需要考虑。我们通过一份“接口协议”结合为一个高效率的团队,这正是信息隐藏原则的意义。

2.interface design,接口设计,是一个项目可以划分为不同部分的基础。我和鲁聃之所以可以一个负责前端一个负责计算核心将这个软件完成,最重要的一点就是我们有良好的接口设计。我们约定好生成算式参数设置接口、生成算式接口、计算接口、检验答案接口,在编写代码中又加入了异常抛出约定以及极端情况约定。我们设计了良好的接口,大大方便了我们的分工协作,最大程度保证了我们工作的独立,不受搭档代码情况影响。

3.loose coupling,松耦合。松耦合的目标是最小化依赖,实现可伸缩性、灵活性和容错。我们的项目中,前端与后端都有很强的可伸缩性与灵活性与容错。比如,前端可以自由选择从用户获取信息的方式,用户交互方式而无需顾虑后端的实现,后端可以自由选择解决问题的算法,变量的使用,而无需考虑前端的实现方式。前后端只需要遵守同一套“接口协议”就可以保证正常运行。后端提供的DLL文件可以不断更新,而不影响前端开发,这也体现了松耦合的理念。

 

三、Design By Contract

契约式设计,就是把类和他的客户程序之间的关系看做正式的协议,描述双方的权利和义务,被Bertrand Meyer称作构建面向对象软件系统方法的核心。

契约式设计的提出主要基于软件可靠性的考虑,包括正确性与健壮性。正确性指软件按照需求规格执行的能力,健壮性指软件对需求规格中未声明状况的处理能力。健壮性主要与异常处理机制相关。契约即客户按照需求规格使用软件,软件设计者按照需求规格设计软件,需求规格之外的请求造成的软件使用错误责任不由软件设计者承担。契约式设计是一套机制,在客户称需要提供者之间明确地声明双方的责任与权力,即契约,并能够对这些契约进行验证。

我们在“小学数学习题助手”软件开发过程中,对于绝大部分正常请求给予支持,并进行了正确性验证。对于极端情况的数据,比如生成题目数量非常大而生成数值上限与运算符数量非常小的情况,我们进行了响应的异常报错处理机制,并设计良好的用户交互,通知异常原因。我们的软件开发过程其实是在遵循契约式设计的原则。

契约式设计的原则的优点在于,确保了server与client地位的平等,双方有各自的义务与责任,这样就保证了代码的质量,提高了软件工程的效率与质量。

契约式设计也有缺点,那就是契约式设计需要一种机制来验证契约的成立与否,断言就是最好的选择,但并不是所有的程序语言都有断言机制,那么强行使用语言进行模仿就势必造成代码的冗余和不可读性的提高,比如.NET4.0以前就没有assert的概念。

四、单元测试与代码覆盖率

单元测试中,我们首先对各个基础功能进行检测,包括加减、乘除、有括号、有代分数、有负数等各种式子进行测试,保证程序的正确性。

随后,我们对程序面对的各种边界问题、极限问题、输入不合法、操作不合法问题所产生的异常进行测试,保证程序的鲁棒性。

最后,对程序整体使用进行测试,如在生成题目后导入Excel进行计算并检查,在用户界面进行各种操作实验,确定用户交互过程的流畅完整体验。

测试代码覆盖率,因为环境问题VS无法装上测试工具Xunit,无法查看代码覆盖率,所以这一块只好回头再补上。

五、UML图

计算核心DLL程序的UML图:

用户界面UML图:

六、实现算法的方法

Overview

This module can provide some function for calculating, answer check and expression generating, support bracket, negative, int range, multiplication & division, fraction such options

Tips

a. Perfect no repeated expression

b. Expressions generated can be solved by math software when you invoke stdExpr()

       auto-replace ( 1'2/5 ÷ ( 3 × 5 ) ) as ( (7/5) / (3 * 5) ) when MIXED = true

c. About Operation:

       0'3/5 or 3/5 as fraction 3/5

       3 / 5 or 3 ÷ 5 as 3 divs 5

       (3/5)*(2/6) or (3/5)×(2/6) = 1/5

       can not solve (3/5)/(2/6), you should write (3/5) / (2/6) or (3/5) ÷ (2/6)   

d. When use calc(), replace '\t' '\0' ' ' as "";

       auto-replace (-1' 3 2/5) as (-7'2/5)

 

e. IF you need expression with bracket, each subexpression will be surrounded with bracket

       auto-replace (3+2) - 5 × 5 as ( ( 3 + 2 ) - ( 5 × 5 ) ) when IF_BRACKET = true

f. Negative number must surround with BRACKET if there is an operation in front!

       such as 5+(-3)

g. Dividend & Divisor can never be zero, but 0/1 as fraction is allowed

    When IF_FRAC = true, all division can not generate integers such as ((5/3) ÷ (1/3))

h. About Exception —— throw runtime exception:

       Bracket Unmached : ((3+2)                                as InvalidOperationException

       Parameter out of range : intselect(0,1,0)           as InvalidDataException

       Fraction dominator as Zero : 3/0 + 2                as DividedByZeroException

       Divs zero: (5/2) ÷ 0                                             as DividedByZeroException

       Format Error : (asdsad) ; (3++2) ; (3/a2 + 5)     as FormatException

       File not exist : ./ex.sadasf                                   as FileNotFoundException

       Directory not exist : D:\\a~!~~@!\\e.txt           as FileNotFoundException

How To Use

>>>>>Create an "core" object to use these functions by ".":

1. public void init()

       //设定core各属性初值

       //set core parameter as initial value, by this function we can show definition of these parameters

       MAX_OPNUM = 3;                 

//max operations exist in generated expression; larger than 0

       RANGE = 10;                    

//absolute value of numbers(or fractions) in generated expression; larger than 1

       NUM = 20000;                 

//how many expressions could be generated; larger than 0;

       IF_BRACKET = true;                

//set as true if bracket is allowed to exist in generated expression

    IF_NEG = true;                  

//set as true if negative number is allowed to exist in generated expression

IF_FRAC = true;                

//set as true if fraction number is allowed to exist in generated expression

ADVANCE_CAL = true;           

//set as true if multiplication & division is allowed to exist in generated expression

MIXED = false;                

//set as true if you want generate expressions that could be understand by mathematic software, such as excel, matlab, or mathematica,  when MIXED open:

//all fraction express as improper fraction instead of mixed number

//all numbers surround with brackets

//replace all operation as "+""-""*"/"

SHOW_INFO = false;              

//set as true if you want to print repeated expression when generated to console or print calculated expression when check to console

exerciseAdd = "./Exercise.txt";       //set exercise file path

    answerAdd = "./Answer.txt";         //set answer file path

gradeAdd = "./Grade.txt";              //set grade file path

 

2. public void stdExpr()

       //生成标准数学表达式,以假分数表达所有运算数并括起,规范乘除号为*/         

       //set MIXED as true

 

3.public void showInfo()

       //开启控制台输出,生成表达式时输出生成的重复表达式,批改时输出批改过的式子

       //set SHOW_INFO as true

 

4.public void intSelect(int MAX_OPNUM, int RANGE, int NUM)

       //仅设定数字参数值(操作符数,范围,数量)

       //set int parameters, throw InvalidDataException when MAX_OPNUM<1 | RANGE<2 | NUM < 1

 

5.public void boolSelect(bool IF_BRACKET, bool IF_NEG, bool IF_FRAC, bool ADVANCE_CAL)

       //仅设定布尔参数值(有无括号,有无负数,有无分数,有无乘除)

       //set bool parameters

 

6.public void select(int MAX_OPNUM, int RANGE, int NUM, bool IF_BRACKET, bool IF_NEG, bool IF_FRAC, bool ADVANCE_CAL)

       // 4&5

 

7. public void addInit(String exerciseAdd, String answerAdd, String gradeAdd = "./Grade.txt")  

       //初始化地址信息

    //set address parameters with out check validity

 

8. public String calc(String expr)                                             

       //给定表达式,进行计算并返回答案

       //calculate expr and return answer, if expr invalid throw exception (FormatException, DividedByZeroException, InvalidOperationException)

 

9. public void generate()                     

       //按照自身参数生成相应的四则运算表达式和答案并逐行写到文件中

       //generate expressions & its answer to file, throw exception if necessary(FileNotFoundException, FormatException, DividedByZeroException, InvalidOperationException, InvalidDataException)

       //if totalnum of expressions is too large, can not find new expression which is unrepeated in 5 minute, this function will exit and throw InvalidDataException

       //and store all expressions it generated to file

 

10.  public void check()            

       //根据给定的题目和答案文件进行批改

       //check answers in answer.txt that whether match expressions in exercise.txt or not, throw exception if necessary(FileNotFoundException, FormatException, DividedByZeroException, InvalidOperationException)

       //check each line, total min(expressionNum,answerNum) times

       //when find illegal expression throw exception which include the lines this expression @       

 

posted @ 2015-10-05 22:56  rrrsss0  阅读(256)  评论(1)    收藏  举报