“第二次作业”这四个字看起来平平无奇,但当我在收到题目说明、打开第一次作业的代码时,脑子里冒出来的第一句话是:这次不是做一个新题,而是在自己的旧代码上继续做增量改进。说句实话,这种“第二次”比从零开始难多了——因为你对标准已经心里有数,再写出来的东西不该是“能运行就行”,而是要能看、能维护、能给别人讲清楚。
这篇文章就以我个人做的一份“图书管理系统”第二次作业为例,聊聊我是怎么从需求分析、数据结构重构、GUI界面开发、数据库持久化一直走到提交前的自检,中间踩了哪些坑、绕了哪些路、最后怎么把一份普通课程作业写出点项目迭代的味道。无论你手头是课程作业、实训项目,还是工作中第二次接手同一个模块,这篇的经验和思路都能直接拿来参考。
1. 第二次作业的真实含义:不是重复劳动,而是增量改进
1.1 先别急着写代码,重新读一遍需求原文
很多人拿到第二次作业题目的第一时间,是先打开上一次的代码目录,看看哪些函数能复用。我的习惯相反:先放下代码,把需求原文重新读三遍。原因很简单,第二次作业通常不是简单加两个功能,它往往是一次完整的“版本迭代”——需求里可能藏着第一次没暴露出来的约束条件,而这些约束会直接影响数据结构和界面设计。
以图书管理系统为例,第一次作业要求写一个控制台程序,支持图书的增删改查。第二次作业则在需求里加了一句:“在已有功能基础上,完善可视化管理界面,并确保数据在程序重启后不丢失。”这句话看起来轻描淡写,但拆开看,至少包含三层意思:第一,你要有图形界面;第二,你已经默认有了“已有功能”,也就是第一次的增删改查得保留而不是推翻;第三,数据不能只是在内存里跑一遍,必须做持久化存储。
我见过不少人在这一步就吃亏了,他们直接开写GUI,结果写着写着发现原来的数据结构和逻辑完全嵌死在print和input里,根本没法接按钮事件。于是我特意给自己列了一个“需求解读清单”:原有功能有哪些?这次新增的硬性要求是什么?哪些地方存在隐含约束?哪些表述模糊、需要在设计时自己定规则?这份清单比代码先动笔,省下的返工时间远超过半小时。
1.2 给自己定一个验收标准,别让“做完”变成“没底”
很多作业项目“完成”和“没底”是划等号的,原因在于没有把模糊的需求转成可验证的验收标准。第二次作业里,我在动工前就把需求拆成了若干条可以逐条打勾的验收项,比如:
- 新增一本图书后,界面表格应立刻出现该记录,并且SQLite数据库文件中能查到对应行。
- 删除图书时,如果该图书当前库存不为零,必须弹出二次确认窗口,防止误删。
- 按书名关键词查询后,列表只显示匹配项,清空搜索框后恢复全部图书。
- 程序关闭再重启,之前添加的所有图书都在,不是只有最后一次运行时添加的那几本。
这些验收标准不需要写在正式文档里,但一定要写在你自己能随时看到的地方。因为第二版程序一旦进入代码编写阶段,非常容易被某个弹窗、某个布局问题带偏思路,最后把核心业务逻辑都忘了。验收标准像是一个锚点,每次写完一个功能,跑一遍手动测试,打了勾再往下走,心里就有底。
1.3 增量改进,而不是推翻重写:哪些代码能留,哪些必须换
第二次作业最有意思的地方,在于它逼着你学会“判断代码去留”。这是一个在真实开发中极其重要的能力,学校里却很少专门练。我用一个比喻来思考:第一次作业像搭了一套毛坯房,水电管线都裸露在外面,能住人但很粗糙。第二次作业不是把房子推倒重盖,而是做一次装修——哪些墙能拆、哪些管线保留、哪些管线位置要重新布置,你得心中有数。
回到代码层面,我会把第一次作业里的函数逐个过一遍,按“保留、改造、废弃”三个标签分类。比如,第一次写了一个校验ISBN编号的函数,逻辑没问题,可以直接保留;而原来负责打印输出图书列表的函数,里面全是print和format调用,这次直接被标记为废弃——因为GUI表格不需要print,它需要的是返回数据列表给Treeview控件。分类完成之后,心里就清楚这次的工作量分别在哪,也不会心疼“删掉自己写的代码”这种情绪了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 第一次作业留下的坑:这些代码和思路必须重构
2.1 “能跑就行”的代价:所有逻辑都堆在main函数里
我翻出第一次作业的代码时,脸上是有点发热的。一个文件里写了几百行,所有增删改查的交互逻辑全塞在main函数里,用户输个“1”就执行新增,输个“2”就执行删除,每个分支里还嵌套着input和if判断。当时觉得写得好顺畅,现在再看,完全是一锅粥。
这个结构的致命问题在接GUI时彻底暴露出来。按钮“新增”对应的回调函数,和原来input接收用户输入的逻辑根本没法对接,因为一个按钮点击事件是自动触发的,它不能像命令行一样先打印提示、然后卡在那里等你输入。也就是说,原来所有依赖input的交互代码全部作废。与其在废弃代码上打补丁,不如重新梳理业务逻辑,把“用户输入数据”和“程序处理数据”这两个环节彻底解耦。
2.2 数据结构选型:从“列表套字典”到真正的类
第一次作业写数据结构,大多数同学和我当初一样,直接用“列表套字典”:
python复制books = [
{"book_id": "B001", "title": "某本书", "author": "某人", "stock": 5},
{"book_id": "B002", "title": "另一本", "author":
