结对编程项目分析与心得

  看似漫长实则短暂的结对编程项目就这么结束了。细细回想起来,其中更有着点滴的感悟与体会。

项目需求

带 UI(桌面应用、网站均可)的小初高数学学习软件

用户:小学、初中和高中学生。

功能

  1. 用户注册功能。用户提供手机号码,点击注册将收到一个注册码,用户可使用该注册码完成注册;

  2. 用户完成注册后,界面提示设置密码,用户输入两次密码匹配后设置密码成功。密码6-10位,必须含大小写字母和数字;

  3. 用户在登录状态下可修改密码,输入正确的原密码,再输入两次相同的新密码后修改密码成功;

  4. 密码设置成功后,跳转到选择界面,界面显示小学、初中和高中三个选项,用户点击其中之一后,提示用户输入需要生成的题目数量;

  5. 用户输入题目数量后,生成一张试卷(同一张卷子不能有相同题目,题目全部为选择题),界面显示第一题的题干和四个选项,用户选择四个选项中的一个后提交,界面显示第二题,...,直至最后一题;

  6. 最后一题提交后,界面显示分数,分数根据答对的百分比计算;

  7. 用户在分数界面可选择退出或继续做题;

  8. 小初高数学题目要求见个人项目。

项目介绍

1 复用个人项目

  从个人项目到结对编程项目转换的初始,已经了解了搭档代码的过程,由于我的个人项目结构更清晰且是面向对象编程,所以在结对编程中复用我的代码。

  了解搭档代码的过程,对自己有着很好的提升作用。之于我,在理解的过程中明白了自己的不足,明白了自己对需求理解的不透彻,也明白了不同人对于同一需求的不同理解……在这个过程中,我明白了很多。而这一切,不过是结对编程初起步。我们才刚刚开始。

  在复用的过程中,我们也认识到分模块编写代码及精炼一个函数中包含内容的重要性与必要性。简单来说就是,把一个功能写成一个模块,以便当再次需要相同功能的时候可以直接使用。而代码重用,也是面向对象编程的一个突出部分,亦是面向对象与面向过程两种编程的不同所在。

  我的个人项目代码基本上可以直接用,但那会用户的数据不是保存在文件或者数据库中而是保存在源文件里面,这样程序一关闭之前对账户所进行的操作将不会保留,而是每次都初始化固定的账户数据。这是我们在结对编程中想要改进的地方,就是把用户信息存于数据库中,User 作为 user 表的实体类,让 UserManager 类中的部分语句改成了 sql 的 CURD,去掉了 User 类中的 level 并增加一个 phone 属性。

  因为之前用 Java 做过桌面程序,所以我们结对编程也是做的桌面程序,实现 GUI 用的是 PyQt5,和之前做过的程序有许多相通的地方,不会的边学边做也会了。

2 项目结构
  • main.py

    交互层,包含项目的运行主逻辑,也是编译运行的主文件

  • user.py

    复用了个人项目中封装两个类:

     User 类:用于描述一个用户的信息

     UserManager 类:用于管理所有存在的用户(包括当前登录用户)以及用户文件夹

  • formula.py

    复用了个人项目中的式子类,为核心算法模块,包含用于生成、保存试卷的一系列方法

    试卷保存于 paper 文件夹下,初始状态下该文件夹不存在,系统运行会自动生成该文件夹

  • GUI.py

    继承自 gui 文件夹中类的集合,实现窗口设置的自定义操作

  • qss.py

    编写了程序界面样式的 qss 语句

  • gui 文件夹

    reg_gui.py,phone_gui.py,identify_gui.py,choice_gui.py,changepwd_gui.py,number_gui.py,exam_gui.py,seeu_gui.py

    登录、注册、发送手机验证码、修改密码、获取题目数量、做题与得分等图形化界面的类

  • icon 文件夹

    存放程序中的样式要使用的图片

3 程序界面
  • 用户登录界面
​    
  • 用户注册界面
​​    
    
  • 选择题目
​    
  • 做题界面
​    
  • 结束界面
​    

经验 & 教训

  • 在写代码的过程中,我遇到了一个很奇怪的 bug 是,在SendCode方法里出现无法修改全局变量和调用其他方法的 bug,但是运行不会报错,当时觉得这是什么邪门的 bug,找了好久才发现是我把发送验证码的按钮连接了两个事件,所以写代码还是要走点心呐~
  • 需要注意的是生成的式子可能是无法计算的,比如根号里面是负数,因此本项目计算结果的方法如下,所以算是有点投机取巧 XD...
 1 def CalResult(self):
 2      # 更改^2,注意使用replace替换字符串后仅为临时变量,需重新赋值才能保存
 3      fml = self.m_notcheckfml.replace('^', '**')
 4      # 更改√
 5      fml = fml.replace('', 'sqrt')
 6      res = "NaN"
 7      try:
 8          res = eval(fml)
 9      except ValueError:
10          pass
11      return res
  • 搭档负责做做题的界面,然后他是直接在 QT designer 生成的代码上改动,添加逻辑,这样破坏了接口的统一,导致如果后面想要改界面时又要把原来的逻辑加进去;所以用 QT designer 设计界面时,最好不要在生成的代码上改动,而是新建一个类去继承它再做修改,这样便于后面修改界面后减少代码的改动。
  • 搭档负责的部分功能都实现的很好,就是在类中引用了很多全局变量、方法等,这样有点破坏了类的封装,使得类对外有了一定的依赖。最后他把代码给我合并时,我需要把原始界面的代码保持好,然后新建一个类去继承原始的类,再在子类中添加逻辑,然后还要把用到全局变量、方法的类方法抽取到交互层。
  • 我们分工还算明确,所以效率比较高,不过本项目还存在不足:
    1. 软件的启动有点慢;
    2. 做题时的 4 个选项一旦做了选择,没办法在下一题设置 4 个按钮的选择状态为unchecked,就是选择了一个选项到下一题是还是会默认选中那个选项,百度了一个小时也还没解决,但其实问题也不算太大;
    3. 分辨率的适配问题,比如有的电脑显示配置为缩放 100% 或 125%,会使得不同显示配置的电脑上显示的字体大小不一样,尝试了别人的解决方案,但似乎没有效果。

感想

  国庆节前几天在各处玩时还牵挂着这个项目,老担心要凉,还好最后配合的还ok,也领会到了结对编程的意义:

 没有人的代码生来完美,也没有人的代码一处不错,我们都互有优缺点,都互有需要学习和可以被学习的地方,在学习与探讨中成长。”

posted @ 2020-10-10 00:49  这次一定  阅读(162)  评论(0)    收藏  举报