2025软工K班结对编程任务

https://gitee.com/ldkcode/ketangdianming/tree/master
https://blog.csdn.net/2301_80295708/article/details/155162048?sharetype=blogdetail&sharerId=155162048&sharerefer=PC&sharesource=2301_80295708&spm=1011.2480.3001.8118
https://www.bilibili.com/video/BV1UhUNB7EFu/?share_source=copy_web&vd_source=a158081635caa5791dcda7f052a73018

一、结对探索

1.1 队伍基本信息

结对编号:1a2a3a;队伍名称:码上点到你

学号姓名作业博客链接具体分工
102301446林得恺2025软工K班结对编程任务前端与交互负责人:负责React架构搭建、UI组件开发(评分弹窗、图表)、动画效果实现及前端状态管理(乐观更新策略)。
102301445林潇2025软工K班结对编程任务后端与系统负责人:负责Flask环境搭建、数据库设计(MySQL/SQLite双模)、API接口开发与测试、数据导入导出逻辑及部署文档编写。

1.2 描述结对的过程

本次结对编程我们采取了“前后端分离、核心逻辑共研”的模式。

  1. 初期阶段:我们共同阅读了作业需求,确定了使用 React + Python Flask 的技术栈,并讨论了“本地/云端双模”这一核心架构,以解决网络不稳定时的可用性问题。
  2. 开发阶段:利用QQ和微信进行实时沟通。在编写核心算法(如加权随机点名)时,我们使用了屏幕共享进行结对编程(Driver-Navigator模式),一人负责写代码,另一人负责实时Code Review和逻辑检查。
  3. 联调阶段:针对出现的跨域问题(CORS)和云数据库连接超时问题,我们共同排查,最终通过优化后端连接池参数和前端请求逻辑解决了问题。

1.3 非摆拍的两人在讨论设计或结对编程过程的照片

在这里插入图片描述

二、原型设计

2.1 原型工具的选择

我们选择了 Figma 作为原型设计工具,并在后期结合 墨刀 进行交互演示。

  • 选择理由:Figma 支持多人在线协作,方便我们在异地也能同时编辑同一个设计稿。其强大的组件库功能让我们能快速搭建出符合 Material Design 风格的界面。墨刀则用于快速生成可交互的演示链接,方便验证用户体验。

2.2 遇到的困难与解决办法

  • 困难1:点名过程的紧张感营造
    • 描述:最初设计仅是一个简单的文本跳动,缺乏课堂点名的“刺激感”。
    • 解决:我们参考了类似抽奖系统的设计,引入了“滚动动画”和“减速停止”的视觉效果。通过 CSS 动画配合 JS 定时器,实现了名字从快速滚动到慢慢停下的效果。
  • 困难2:复杂数据的移动端适配
    • 描述:积分排行榜包含多个维度的数据(积分、点名次数),在手机端展示时容易拥挤。
    • 解决:我们在原型中设计了响应式布局,在移动端自动隐藏次要信息,或将图表转换为更适合竖屏的列表形式。

2.3 原型作品链接

本作品需要在双终端下运行。

1. 后端启动 (Python)

确保已安装 Python 3.8+。

# 1. 安装依赖
pip install flask flask-cors pymysql

# 2. 启动服务 (默认端口 5000)
python server.py

注意​: server.py 已配置为动态读取前端传来的数据库配置,并设置了 20s 的连接超时以适应慢速云数据库。

2. 前端启动 (React)

确保已安装 Node.js 16+。

# 1. 安装依赖
npm install

# 2. 启动开发服务器
npm run dev

访问链接 http://localhost:5173 即可使用。

2.4 原型界面图片展示

  • 主界面(待机与点名中):界面简洁,左侧显示当前连接状态(本地/在线),中间为巨大的点名卡片。支持“随机点名”和“顺序点名”两种模式入口。
    在这里插入图片描述

  • 评分反馈弹窗:点名结束后自动弹出。设计了快捷评分按钮(出勤+1,复述准确+0.5等)。
    创新点:支持触发“双倍积分”等随机事件的视觉反馈。
    在这里插入图片描述

  • 数据可视化看板:利用柱状图和折线图展示积分前10名的同学及其被点名次数,直观反映课堂活跃度。
    在这里插入图片描述

  • 数据库配置与管理:支持一键切换本地/云端模式,并提供 Excel 批量导入功能。
    云端模式在这里插入图片描述
    本地离线模式本地离线模式

三、编程实现

3.1 开发工具库(如文件读取包等)的使用

本项目使用了以下关键库:

  • 前端
    • React 18 + Vite:构建高性能前端应用。
    • XLSX (SheetJS):用于在浏览器端解析 Excel 文件,实现名单导入。
    • Dexie.js:封装 IndexedDB,实现浏览器的本地数据库存储。
    • Recharts:基于 D3 的图表库,用于绘制积分排行榜。
    • Tailwind CSS:原子化 CSS 框架,快速构建美观界面。
  • 后端
    • Flask:轻量级 Python Web 框架,提供 RESTful API。
    • PyMySQL:用于连接云端 MySQL 数据库。
    • Flask-CORS:解决前后端分离带来的跨域资源共享问题。

3.2 代码组织与内部实现设计(类图)

系统采用前后端分离架构。

  • 前端 (App.tsx) 作为核心控制器,维护 currentStudent(当前学生)、dbMode(数据库模式)等全局状态。
  • 服务层 (services/) 封装了 api.ts (云端交互) 和 db.ts (本地存储),通过统一的接口(如 addStudent, updateStudent)屏蔽了底层数据的差异,实现了“双模切换”对业务逻辑的透明化。
  • 后端 (server.py) 采用工厂模式管理数据库连接,根据请求头动态连接不同的数据库实例。
调用
HTTP 请求 (Online Mode)
Direct Access (Local Mode)
Frontend_App
+state students
+state dbMode
+handleGradingSubmit()
+startRandomCall()
Service_Layer
+api.getStudents()
+db.students.toArray()
+importFromExcel()
Backend_Server
+get_db_connection()
+route_add_student()
+route_update_student()
Browser_IndexedDB

3.3 说明算法的关键与关键实现部分流程图

核心算法:加权随机点名算法

为了实现“积分越高,被点概率越低”的需求,我们设计了反向加权算法。

  1. 计算每个学生的权重:weight = 1 / (score + 1) (防止分数为0导致除零错误)。
  2. 计算总权重 totalWeight
  3. 生成一个 0totalWeight 之间的随机数 r
  4. 遍历学生列表,累加权重,当累加值大于 r 时,该学生即为中选者。
    在这里插入图片描述

3.4 贴出重要的/有价值的代码片段并解释

片段1:前端乐观更新(Optimistic UI) 实现

为了解决连接云数据库时 2-3 秒 的延迟感,我们在提交评分时采用了“先更新界面,后同步数据”的策略。

// App.tsx
const handleGradingSubmit = async (delta: number) => {
    // 1. 立即关闭弹窗,给用户极速响应
    setShowGrading(false);

    // 2. 【乐观更新】立即在本地修改显示的分数,不需要等数据库返回
    if (dbMode === 'online') {
        setRemoteStudents(prev => prev.map(s => {
            // 匹配当前学生并更新视图
            if (String(s.studentId) === String(currentStudent.studentId)) {
                return { ...s, score: s.score + delta, callCount: s.callCount + 1 };
            }
            return s;
        }));
    }

    // 3. 【后台静默同步】发送真实请求给后端,用户无需等待此处完成
    try {
        await api.updateStudent(currentStudent.studentId, {
             score: currentStudent.score + delta,
             callCount: currentStudent.callCount + 1
        });
    } catch (error) {
        console.error("同步失败:", error); // 仅在控制台报错,不打断用户流程
    }
};

片段2:后端动态数据库连接与超时控制

为了适应免费云数据库性能较差的情况,我们在后端增加了超时控制和重连机制。

# server.py
def get_db_connection():
    # ... 从请求头获取配置 ...
    try:
        connection = pymysql.connect(
            host=host,
            user=user,
            password=password,
            database=database,
            charset='utf8mb4',
            connect_timeout=20,  # 增加连接超时时间防止前端卡死
            read_timeout=20,
            write_timeout=20
        )
        return connection
    except Exception as e:
        print(f"Database connection error: {str(e)}")
        return None

3.5 性能分析与改进

  • 问题​:在测试导入 50 人以上的名单到云数据库时,页面卡顿严重。
  • 分析​:最初的实现是循环发送 50 次 POST 请求,每次请求都需要建立 TCP 连接和数据库握手,耗时极长且容易触发浏览器的并发限制。
  • 改进​:
    1. 后端新增 /api/students/batch 批量插入接口,使用 SQL 的 INSERT INTO ... VALUES (...), (...) 语法。
    2. 前端改造导入逻辑,一次性将解析好的数组发送给后端。
    3. 结果​:导入 50 人名单的时间从 15秒 缩短至 ​0.5秒​。

3.6 单元测试

我们编写了脚本对后端的随机算法API进行了统计学测试。

# test_random.py 部分代码
def test_weighted_random():
    # 构造数据:A(0分), B(100分)
    # 预期:A 的权重是 1/1=1,B 的权重是 1/101≈0.01
    # A 被选中的概率应接近 99%
    counts = {'A': 0, 'B': 0}
    for _ in range(1000):
        result = simulate_random_pick([student_A, student_B])
        counts[result['name']] += 1
    
    print(f"A: {counts['A']}, B: {counts['B']}")
    assert counts['A'] > 900  # 验证概率分布是否符合预期

3.7 贴出代码commit记录

在这里插入图片描述

四、总结反思

4.1 本次任务的PSP表格

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划6045
Estimate估计这个任务需要多少时间3030
Development开发12001450
Analysis需求分析 (包括学习新技术)120200
Design Spec生成设计文档6060
Design Review设计复审3045
Coding Standard代码规范 (为目前的开发制定合适的规范)3020
Design具体设计120150
Coding具体编码600850
Code Review代码复审6090
Test测试(自我测试,修改代码,提交修改)180300
Reporting报告6090
Test Report测试报告3030
Size Measurement计算工作量2020
Postmortem & Process Improvement Plan事后总结, 并提出过程改进计划6040
合计26603420

4.2 学习进度条(每周追加)

第N周新增代码(行)累计代码(行)本周学习耗时(小时)累计学习耗时(小时)重要成长
130030088搭建React+Flask基础框架,打通前后端连接
280011001523实现核心点名逻辑、IndexedDB本地存储及云端同步
350016001033完成图表可视化、UI美化、解决CORS和死锁Bug

4.3 最初想象中的产品形态、原型设计作品、软件开发成果三者的差距如何?​

  • 差距分析​:最初想象中,我们希望系统能像原生 App 一样流畅动画。但在实际开发中,受限于 Web 浏览器的性能和云数据库的网络延迟,在“在线模式”下的点名动画一度出现卡顿。
  • 原因​​:
    1. 网络延迟​:免费的云数据库服务器在海外,连接耗时较长(400ms+),导致交互产生裂痕。
    2. 技术选型​:最初使用了轮询方式同步数据,效率低下。
  • 弥补​:我们后期引入了“乐观更新”策略,在视觉上欺骗了用户,让交互看起来是即时的,从而极大地缩小了最终成品与设计原型在体验上的差距。

4.4 评价你的队友

评价林得恺 [前端负责人]:

  • 值得学习​​:对 UI 细节的把控非常到位,特别是那个“双倍积分”的弹出动画,极大地增加了系统的趣味性。解决问题非常执着,Recharts 图表对齐那个 Bug 熬夜修好了,令人佩服。
  • 需要改进​:有时候改代码比较急,变量名拼写容易出错(比如 setIsGradingModalOpen),以后可以多用 IDE 的自动补全。

评价林潇 [后端负责人]:

  • 值得学习​​:逻辑思维严密,API 接口设计得很规范,不仅考虑了正常流程,还处理了 405、500 等各种异常情况。编写的数据库修复脚本帮了大忙。
  • 需要改进​:初期对前端 React 的机制不太了解,导致接口返回的数据结构不太符合前端预期,沟通成本稍高,建议以后可以多了解下游技术。

4.5 结对编程作业心得体会

林得恺 [前端负责人]:

本次结对编程最大的收获在于体会到了 “1+1>2” 的效应。

  1. 互补性​:当一方陷入逻辑死胡同(例如处理图表对齐问题)时,另一方能从不同角度提出“加空格”这种跳出框架的解决方案,迅速破局。
  2. 代码质量​:因为有 Code Review 环节,我们在提交代码前会不自觉地写得更规范,因为知道有另一个人在看。
  3. 全栈视野​:虽然分工明确,但为了解决 Bug,我们都深入了解了对方的技术栈。前端学会了 SQL 优化,后端学会了 React 的生命周期,这对我们未来的职业发展大有裨益。

林潇 [后端负责人]:

本次结对编程任务主要收获如下:

  1. 多维视角打破思维定势:在解决“排行榜图表名字靠左”这个顽固 Bug 时,前端负责人陷入了查阅 CSS 和 Recharts 文档的死胡同,而后端负责人从数据处理的角度提出“在后端给名字加空格”的临时方案。虽然最终我们采用了更正规的前端 BarChart 修复方案,但这种“一个问题,两种视角”的碰撞极大地拓宽了我们的调试思路。

  2. 技术约束驱动架构升级:最初我们因免费云数据库的高延迟而苦恼,认为这是不可抗力。但在结对讨论中,我们决定引入 “乐观更新 (Optimistic UI)” 策略。这一经历让我们明白,恶劣的外部条件往往能倒逼出更优秀的架构设计,最终成品的交互体验甚至优于本地模式。

  3. 代码质量与规范意识:引入 Code Review 机制后,我们发现很多低级错误(如 startSequentialCall 中的定时器未清理导致的死锁)在合并代码前就被拦截了。这种写代码时知道有人在看的心理暗示,让我们在变量命名和错误处理(try-catch)上变得更加严谨。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值