1. 第四次作业:为什么它总是一道分水岭
如果你正在为“第四次作业”发愁,先别急着怀疑自己。我常年接触各类课程作业和项目评审,见过太多人前三次作业轻松拿高分,第四次却连续熬夜还交不出一份满意的结果。原因并不一定是题目变难了,而是一次典型的“从练习到项目”的跳跃。前三次作业往往只需要你掌握一个函数、一个语法点或者一个小工具,第四次作业却会要求你把前面学的东西全部揉到一起,做成一个完整可运行、有数据存储、有交互逻辑的小系统。
就拿最常见的“待办事项管理工具”作为例子:这个题目看起来简单,无非是新增、删除、标记完成,可真要写好,你得同时处理界面、逻辑、数据存储、异常处理和用户体验。很多同学把前几次作业“能跑就行”的习惯带到这里,结果做到一半发现数据存不住,或者页面一刷新就回到原点,最后只能在硬编码里填数据来“表演”功能。这种作业交上去,明眼人一眼就能看出问题。
我写这篇文章的目的很简单:把“第四次作业”当作你第一个真正的“小项目”来做,而不是当成一道大号练习题。接下来我会从需求拆解、技术选型、实现步骤、常见问题和时间管理五个方面,把我自己辅导同学时反复强调的要点完整过一遍。无论你是刚学编程不久的新手,还是有一定基础但时间紧张的老同学,这篇文章都能给你一条可以直接照着走的路线,而不是一堆零散技巧。
1.1 从单点练习到综合项目的跨越
为什么是第四次,而不是第二次或第八次?这其实对应了大部分教学大纲里“基础语法—控制结构—函数与模块—小型项目”的递进节奏。到了第四次作业,老师默认你已经具备最基本的能力,所以题目不再告诉你“用哪个库、调用哪个函数”,而是只给一个目标,具体方案要你自己定。这个变化对新手来说往往很难适应,因为前几次作业的答案基本都在课件里,第四次开始课件里只有需求,没有答案。
打个比方,前三次作业像是学炒菜时单独练切丝、练火候、练调味,第四次作业则是要求你独立做出一桌菜。切丝的时候你只需要一把刀,做一桌菜却要统筹食材、刀具、锅具、时间顺序和摆盘。程序也一样:写一个排序函数,你只需要关心算法本身;写一个待办事项工具,你要关心用户怎么输入、数据存在哪、程序崩溃了会不会丢数据、别人能不能在你的代码基础上继续改。任何一环掉链子,整体就垮了。
我见过很多同学把大量时间花在某个自以为很难的“亮点功能”上,比如做一个炫酷的动画切换,结果核心的增删改查反而没做好。这其实是对“综合项目”的误解。第四次作业考察的核心不是某一个单独牛X的点,而是所有基础知识能不能稳定地组织在一起。与其把某一根木头削得又尖又细,不如先把整张桌子四条腿都站稳。
1.2 需求没拆清,后面全是返工
拿到题目就打开编辑器开写,是第四次作业翻车率最高的操作,没有之一。哪怕题目只有一句话,也建议先花半小时把需求拆成清单。以“待办事项管理工具”为例,表面上的需求通常包括:添加待办、标记完成、删除待办、展示列表。但你要是只做这些,交上去很可能被指出“刷新后数据没了”“空内容也能添加”“完成状态的筛选在哪”。这些隐藏需求才是真正拉开分差的地方。
拆需求的时候,不用画复杂的图,一个表格就够。我把最常见的功能点拆成了核心项和加分项:
| 功能点 | 优先级 | 隐含要求 |
|---|---|---|
| 添加待办 | 核心 | 空字符串不能提交,内容要有长度限制 |
| 展示待办列表 | 核心 | 按添加时间或完成状态排序 |
| 标记完成/未完成 | 核心 | 状态改变后要能持久化 |
| 删除待办 | 核心 | 删除前最好有确认,避免误操作 |
| 数据持久化 | 核心 | 关闭程序或刷新浏览器后数据仍存在 |
| 筛选显示(全部/未完成/已完成) | 加分 | 让列表更符合真实使用场景 |
| 编辑已有待办 | 加分 | 双击或按钮进入编辑状态 |
| 搜索 | 加分 | 内容实时过滤 |
这个表格看着简单,但真正全部做到的作业并不多。你完全可以把优先级为“加分”的先放一放,先把“核心”全部落实,再去考虑额外功能。这样才能避免做到最后才发现,自己精心做的搜索功能没问题,可是连“刷新后数据还在”这个最基础的要求都没满足。
1.3 别急着写代码,先把边界画出来
拆完需求之后,还要做一件事:给定边界。所谓边界,就是明确“这个作业到底要做什么、不做什么”。同样是待办事项应用,做成“本地单机版”和“多用户联网同步版”完全是两个量级。课程作业通常没有特殊说明,默认本地单机即可,联网同步、多端登录这些东西都属于自己给自己挖坑。
有个很典型的例子:我见过一位同学觉得普通待办应用太简单,非要加上云同步功能,于是引入了认证、服务器、数据库同步,结果折腾两周后光用户登录就做崩了,第四次作业的截止时间也到了。这不是能力问题,而是边界感问题。作业题目给的目标是什么,就先把那个目标做到位,额外价值可以在提交后作为“展望”写进报告里,而不是塞进第一版实现里。
定边界还要考虑技术边界:你当前会哪些技术,就优先用哪些。作业不是产品发布会,不会因为你用了某个冷门框架而加分,反而会因为你花在环境配置上的时间太多,挤占了真正的功能实现时间。选技术的核心原则只有四个字:稳、熟、快、能解释。下面这个章节,我就专门聊聊技术选型这件事。
2. 方案选型:把第四次作业当成一次小项目来做
2.1 技术栈怎么选才不给自己挖坑
技术选型是很多同学最容易犯选择困难症的地方。明明手头的课程只教了某个语言的基础,看到别人用了新框架心里痒,就非要跟着学。我的建议很直接:除非你已经有足够的时间余量,否则作业里一定要选你最近用过、最能驾驭的技术栈。所谓“能解释”,是指老师随机问一句“为什么用这个方案”时,你能清楚地讲出理由,而不是回答“因为网上说这个火”。
以“待办事项管理工具”为例,常见的课程作业形态有三种。第一种是纯前端版本,用HTML、CSS、JavaScript加上浏览器的本地存储,这个方案的优点是无需搭建服务端,打开网页就能用,缺点是逻辑全暴露在浏览器里,数据无法跨设备。第二种是桌面版本,用某种图形界面框架打包成独立程序,适合装在本机演示。第三种是带后端的小型Web应用,比如用轻量级框架加轻量数据库,浏览器访问,数据和逻辑分离,这也最接近真实项目的结构。
我把三种方案的优劣对照列在下面,方便你判断:
| 方案 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| 纯前端 + 本地存储 | 环境简单,无需后端 | 数据只在当前浏览器本地,换浏览器就丢 | 只要求页面交互,不考核后端能力的作业 |
| 桌面GUI程序 | 演示效果好,像真实软件 | 打包分发麻烦,不同系统可能有兼容问题 | 课程指定桌面应用类型的作业 |
| 后端框架 + 轻量数据库 | 结构完整,贴近企业项目 | 需要管理服务进程,稍微多一点环境成本 | 要求了数据持久化,或希望体现系统架构的作业 |
如果你正在学的课程以某编程语言为主,那“轻量Web框架 + 文件型数据库 + 简单HTML”是我最推荐的组合。原因不是它多高级,而是它环境搭建快、文档多、出错好排查。记住:第四次作业的目标是完整体验一遍“从零到一”的流程,不是让你顺便学会一个新框架。稳,比炫重要。
2.2 数据存储方案:本地文件还是数据库
数据持久化是第四次作业绕不开的关键点,也是很多同学第一次意识到“内存变量不能当仓库用”。如果你把待办列表只放在一个编程语言的普通数组里,程序一关,数据就全丢了。所以必须选择一种持久化方案。可选的有三种:纯文本文件、JSON文件、轻量数据库。对于课程作业,我更推荐直接使用轻量数据库,因为它既保留了“单文件、零配置”的简单性,又提供了结构化查询能力。
为什么不推荐纯文本文件?因为你需要自己处理格式、分隔、异常,还得在每次启动时解析文件;数据稍微复杂一点,比如要保存“完成状态”和“创建时间”,文件方案就很容易出现格式错乱。为什么不推荐JSON文件?JSON比纯文本好一些,但并发写入和重复读写仍然需要自己管理。轻量数据库则不一样,它本质上虽然也是一个文件,但内部帮你处理好了结构化存储、事务和SQL查询,你只需要几条语句就能安全操作,而且它零服务器、零配置,非常适合这个规模的作业。
用生活类比来说,文本文件像是把杂货全部堆在一个纸箱里,每次取东西都得翻半天;JSON文件像是有简单分层的收纳盒,比纸箱好找;轻量数据库则像带隔断的抽屉柜,你可以按规则存取,还能随时问它“有哪些东西是未完成的”。如果你的作业只需要保存一组简单的键值对,也可以用浏览器本地存储,但一旦涉及多条记录的增删改查,直接上轻量数据库是更稳妥的选择。后面我会给出具体的建表代码和参数化查询写法。
2.3 界面和交互:能跑通不等于能用
很多同学交上来的作业“功能都有”,但老师点几下就发现不顺手。比如输入框里敲了回车不添加,必须先拿鼠标去点按钮;比如列表为空的时候,页面中间一大片空白,没有任何提示;比如删除按钮没有确认,手滑点错一条就没了。这些问题都不是功能缺失,而是交互缺失。在作业评分里,交互细节往往是最容易拉分也最容易补分的地方。
我总结过三个低成本、高回报的交互细节,做作业时可以直接抄。第一个,输入框支持回车提交,这只需要绑定一个键盘事件,但会让使用体验上一个台阶。第二个,为删除操作增加确认提示,至少可以用一个简单的弹窗确认,避免误删。第三个,列表为空时显示“暂无待办,添加一条试试”,别让页面看起来像没加载出来。这三个细节加起来不过几十行代码,但给人的感觉是“这是个用过心的作品”。
交互设计还有一个容易被忽视的原则:别让用户点多余的操作。比如标记完成,很多人做成必须点进详情页再改状态,这就绕远了。待办事项最常见的操作就是打开应用、看一眼、勾选完成、退出,所以“勾选”这个动作应该直接在列表项上完成,最多单击一下。你不需要学专业的交互设计,只要把自己当成用户,把每个功能从点下第一下到看到结果走一遍,哪里觉得别扭,哪里就是需要改的地方。
3. 实操过程:从空目录到跑起来的关键步骤
3.1 环境初始化与依赖锁定
确定了方案之后,就可以进入实操环节。很多人习惯直接在全局环境里装包,装完就开始写代码,等到提交的时候才发现,别人机器上跑不了。正确做法是第一步就创建虚拟环境,把依赖锁进文件。以某轻量Web框架的后端方案为例,我通常建议这样初始化:
mkdir todo-app cd todo-app python -m venv venv source venv/bin/activate # Windows 下是 venv\Scripts\activate pip install flask pip freeze > requirements.txt这里最关键的不是创建虚拟环境,而是最后一行pip freeze > requirements.txt。它会把当前环境里所有依赖包及其精确版本写入文件,别人拿到你代码之后,执行一条pip install -r requirements.txt就能还原环境。我见过太多同学栽在这个环节:本地能跑,换一台电脑就报错,最后发现是依赖版本冲突,但因为没有锁定版本,根本说不清自己环境里装的是什么。
除了依赖锁定,还要顺手建一个.gitignore文件,把虚拟环境目录、缓存目录和临时文件排除掉。如果课程要求提交压缩包,这个文件至少能保证你不会不小心把几十兆的虚拟环境整个打包进去。这些习惯看起来和学习无关,但真正决定了你的作业能不能被别人顺利运行。
3.2 核心功能实现:待办项的增删改查
环境准备好后,我们从最核心的增删改查开始写。一个最小但结构完整的后端大概长这样。注意,这里我刻意让逻辑简单,目的是先把主流程跑通,而不是一次写出一堆高阶封装。
from flask import Flask, render_template, request, redirect, url_for import sqlite3 app = Flask(__name__) DB_PATH = "todos.db" def get_db(): conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row return conn @app.route("/") def index(): conn = get_db() todos = conn.execute("SELECT * FROM todos ORDER BY created_at DESC").fetchall() conn.close() return render_template("index.html", todos=todos) @app.route("/add", methods=["POST"]) def add(): content = request.form.get("content", "").strip() if content: conn = get_db() conn.execute("INSERT INTO todos (content, done) VALUES (?, ?)", (content, 0)) conn.commit() conn.close() return redirect(url_for("index")) @app.route("/toggle/<int:todo_id>") def toggle(todo_id): conn = get_db() conn.execute("UPDATE todos SET done = 1 - done WHERE id = ?", (todo_id,)) conn.commit() conn.close() return redirect(url_for("index")) @app.route("/delete/<int:todo_id>", methods=["POST"]) def delete(todo_id): conn = get_db() conn.execute("DELETE FROM todos WHERE id = ?", (todo_id,)) conn.commit() conn.close() return redirect(url_for("index")) if __name__ == "__main__": app.run(debug=True)这段代码里有几个细节值得说一下。第一,所有SQL语句都用了问号占位符和参数传入,而不是直接拼接字符串,这是防止SQL注入最基本也是最重要的做法。哪怕你的作业只是本地单机版,也应该养成这个习惯。第二,添加接口在写入前把内容用.strip()去掉首尾空格,并且空内容直接忽略,这就处理了“空字符串待办”的问题。第三,完成状态的切换用了1 - done,一行SQL既能把0变成1,也能把1变回0,避免了在代码里读出来判断再写回去的多余步骤。
第四点比较隐蔽:增删操作处理完之后都用redirect(url_for("index"))跳回列表页,而不是直接在接口里返回页面内容。这么做的好处是,用户刷新列表页时不会再次触发上一次的POST请求,避免了“重复添加”或者“第二次刷新弹出重新提交表单”的尴尬。这个模式叫作PRG(Post/Redirect/Get),是Web开发里非常基础但极其实用的小知识,作业里用上非常加分。
3.3 数据持久化与状态管理
后端代码能跑之后,还需要把数据库表建好。第一次初始化表时,可以在主模块里加一段建表逻辑,也可以用单独的初始化脚本。最稳妥的做法是在应用启动时检查表是否存在,不存在则创建。这样别人拿到代码后不需要手动执行SQL脚本,运行起来就能用。
def init_db(): conn = get_db() conn.execute(""" CREATE TABLE IF NOT EXISTS todos ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL, done INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now','localtime')) ) """) conn.commit() conn.close() init_db()这里的字段设计也有一点讲究。id作为自增主键,保证每条记录有唯一标识;content保存待办内容,用TEXT类型足够;done用整数0和1表示未完成和已完成,简洁明了;created_at存储创建时间,为了方便展示直接用了本地时间的datetime('now','localtime')。如果你的作业需要按时间排序或者显示添加时间,这个字段就能派上用场。别小看这几行建表语句,它是整个数据持久化的地基。
除了数据库里的持久化,还有一个容易被忽略的“状态管理”问题:前端展示时,如何知道一条待办是已完成还是未完成?我的做法很简单,在渲染模板时判断todo['done']的值,给对应的HTML元素加一个CSS类名,比如完成态加上灰色和删除线,未完成保持默认。展示逻辑尽量不要放在后端Python里拼字符串,可以在模板里用条件判断完成,这样职责更清晰。
3.4 提交前的自测清单
功能实现完之后,最重要的一步是自测。我强烈建议你把自测项写成一个清单,一项一项过,而不是凭感觉点两下就算完。以下是我每次提交作业前都会过一遍的测试表,可以直接抄走用:
| 测试项 | 操作方式 | 期望结果 |
|---|---|---|
| 空白输入 | 在输入框只敲空格或回车 | 不会新增内容,页面无报错 |
| 正常新增 | 输入“买牛奶”后提交 | 列表顶部出现该待办 |
| 标记完成 | 点击待办状态切换按钮 | 文字变为完成样式,刷新后状态保留 |
| 删除待办 | 删除一条记录 | 列表中不再出现该记录,刷新后仍然不存在 |
| 刷新持久化 | 新增多条后刷新浏览器 | 数据还在,没有重置 |
| 特殊字符 | 添加<script>alert("x")</script> | 页面不弹窗,内容以纯文本显示 |
| 重复提交 | 连续点击提交按钮 | 不会插入多条相同记录 |
这个清单看似简单,但每一步都可能暴露出一个真实问题。比如特殊字符测试,如果你的模板渲染没有做转义,输入一段HTML代码就可能让页面“破相”,甚至执行脚本。好在现代模板引擎默认会转义输出,但你自己拼字符串就未必了。所以这个测试不只是走流程,它逼着你去检查输出逻辑是否安全。把上面这张表全部跑通,你的第四次作业才算真正达到了“可提交”状态。
4. 现场实录:我在调试中踩过的四个坑
4.1 端口被占用,程序启动失败
第四次作业里最常见、也最容易劝退新手的报错,就是启动服务时提示端口被占用。具体表现是运行启动命令后终端里出现类似Address already in use的信息,然后程序崩溃。这个问题的原因通常是上一个进程没有完全退出,或者你的开发环境里有其他程序占用了同一个端口。如果你用的是Mac或Linux,一条命令就能定位占用端口的进程:
lsof -i:5000看到输出后,记下占用进程的PID,用kill -9 PID强制结束进程,再重新启动服务。Windows环境下可以用netstat -ano | findstr :5000查看占用情况,再配合任务管理器结束对应进程。最省事的办法是换一个不常用的端口,比如把启动端口改成5001,但这只是临时方案,能找到根因还是尽量找一下。
这里还要提醒一点:如果你开启了调试模式,调试模式下代码一改动就会自动重启,有时旧进程还没来得及释放端口,新进程就尝试绑定,也会偶发端口冲突。遇到这种情况,先把调试模式关掉,等确认环境稳定了再开。其实对于最终提交的作品,我更建议关闭调试模式,用一个正式一点的启动方式,比如用生产级的服务器去运行,这会让你的作业看起来更专业。
4.2 列表不刷新,数据“丢了”的假象
另一个特别容易让人崩溃的问题是:明明往数据库里插入了数据,页面却为什么半天不显示?第一反应通常是代码写错了,但我遇到过很多次,数据其实都存在,只是浏览器缓存或服务进程状态没更新。先说浏览器缓存:如果你改了前端代码,但刷新页面时还在用旧的JS和CSS,页面看起来就像“没改过”。解决方法是强制刷新缓存,Mac上用Cmd+Shift+R,Windows上用Ctrl+Shift+R。
再说服务端问题:如果你改了Python代码,但启动服务的终端窗口没有重新触发重启,或者你用的是旧进程,那接口逻辑还是老版本,自然看不到新功能。这里最笨也最有效的方法,是把终端里正在跑的进程停下来,重新启动一次,再刷新页面。不要嫌麻烦,很多“灵异事件”其实就是“进程还是旧的”导致的。
还有一个隐蔽点容易被当成“数据丢失”:如果你用文件型数据库,但打开数据库文件的方式不对,可能会看到空表。比如你在某个路径启动了服务,数据库文件创建在那个路径下;后来你换了目录运行代码,又新建了一个空数据库文件。数据在旧文件里,新的代码读的是新文件,看起来就像是全部丢了。排查时,建议在代码里把数据库路径打印出来,确认到底在读写哪个文件。
4.3 中文乱码与编码问题
中文乱码是课程作业里一个永远存在的话题。表现形式五花八门:页面显示乱码、数据库里变成问号、终端输出乱码。其实大部分乱码问题的根因只有一个:编码不一致。你写的代码文件保存时用的是UTF-8,但数据库连接或页面渲染时换了另一种编码,数据就串味了。在Web应用里,最简单的预防是确保三个地方都是UTF-8。
第一,HTML模板的<head>里明确写<meta charset="utf-8">。第二,Python代码文件开头尽量声明# -*- coding: utf-8 -*-,虽然Python3默认就是UTF-8源文件编码,但这个声明能让看代码的人一眼明白你在用UTF-8。第三,文件型数据库本身以UTF-8存储文本,一般不需要额外设置。如果你使用其他数据库,需要在连接字符串上写上字符集参数。做完这三步,90%的乱码问题都能解决。
剩下10%出现在终端输出上,比如你直接打印数据库里的中文,终端显示乱码。这种情况通常是终端本身的编码设置问题,不是程序问题。Mac终端默认UTF-8,Windows老版本命令行可能默认GBK。如果在Windows上遇到中文乱码,可以在终端执行chcp 65001切换到UTF-8代码页,再重新运行程序。这个操作不改代码,但能帮你判断究竟是程序问题还是显示问题。
4.4 不同设备上字体和布局错乱
作业写在自己电脑上,老师可能在另一台设备上打开验收。这时你会发现一个很常见的问题:同样的HTML页面,在自己屏幕上正常,换台电脑就错位。原因通常有两个,一是浏览器默认样式不同,二是没有声明视口。第一点以浏览器默认margin为例,不同浏览器对body和标题的默认间距处理不同。解决方式是在CSS最前面加一段简单的重置样式:
* { margin: 0; padding: 0; box-sizing: border-box; }这段代码把所有元素的默认间距清零,并且让padding不再撑大元素的实际宽度。虽然全球互联网对“是否该用通配符重置”一直有争论,但在课程作业里它是最省事、最不容易出错的方案。第二点是响应式设置,如果你的页面需要被不同屏幕宽度的设备访问,HTML的<head>里需要加上<meta name="viewport" content="width=device-width, initial-scale=1.0">,否则手机访问时页面会被强制缩放,看起来全是乱的。
还有一个经常被忽略的坑是字体。你本机装了某个中文字体,页面里写死了字体名,但老师电脑上没有这个字体,就会回退到系统默认字体,布局可能错位。处理办法是不要只写一个字体,而是在字体列表里放多个备选项,最后加上通用中文字体作为兜底。这些细节听起来有些琐碎,但恰恰是它们决定了你的作业在别人眼中是“成品”还是“半成品”。
5. 时间不够?给后面同学的优先级建议
5.1 48小时冲刺法
第四次作业赶上deadline才动手,几乎是每个拖延症患者的固定剧本。如果你只剩48小时,也不要慌,按下面的节奏走,依然能交出一份及格往上的作业。前6小时,不要写代码,只做两件事:把需求拆成清单,定好技术栈,初始化好项目和虚拟环境。很多人觉得这是浪费时间,但这一步恰恰能帮你避免后面十几个小时的无效返工。
接下来的24小时,集中实现核心功能。顺序是:数据库建表、列表展示、添加待办、删除待办、标记完成。每完成一个功能就打开浏览器手动测一遍,不要攒到最后一起测。最后12小时,用来做自测和收尾:把3.4节的测试清单过一遍,修掉明显的问题,补好README,整理代码结构,删掉不必要的临时文件。最后留2小时出来,把作业提交好,包括确认压缩包命名、检查能不能在干净环境里跑起来。这份时间表看起来不宽裕,但只要中途不随便加需求,时间是完全够用的。
5.2 哪些部分可以战略性放弃
时间紧的时候,最怕的是什么都想要。所以我想明确告诉你:有些功能在这个阶段可以理直气壮地不做。比如复杂的搜索过滤、拖拽排序、标签分类、云同步,这些都是“加分项”,而不是“必选项”。你的首要任务是让核心流程完整且稳定。一个只有增删改查、但数据持久化做得很好的作业,通常比一个功能很多但错误百出的作业得分更高。
另一种需要战略性放弃的是“过度设计”。比如为了一个简单列表设计复杂的类层次结构,或者引入设计模式、额外抽象层。这些在真实项目里可能是好习惯,但在只有几天的作业里,它们会显著拖慢进度。核心是“能跑、能测、能解释”,而不是“架构优美”。你可以把这些想法写在报告里的“后续优化方向”部分,老师看到的是你有思考,而不会因为没实现而扣分。
5.3 作业做完之后的扩展方向
如果做完核心功能后还有余力,我建议你从三个方向做扩展。第一个方向是给核心函数写单元测试。哪怕只有几条,也能让老师一眼看出你不只是会调框架,还懂如何验证代码行为。第二个方向是把你本地跑通的应用部署到一个他人可访问的地址,让老师不用配置环境也能直接在线看到效果。这一步听起来复杂,但对于这类小型Web应用,现代平台一般几分钟就能部署完,完全可以作为作业的加分项。
第三个方向是认真写一份README。很多人觉得README是给开源社区准备的,课程作业随便写两句就行。但实际上,一份结构清晰的README包括项目简介、运行方法、依赖清单、功能说明和目录结构,能帮老师节省大量摸索时间,这也是你“沟通能力”的直接体现。做完这三个扩展,你的第四次作业就已经不是一份普通作业了,完全可以当成一个可以写进简历的练习项目。这也会让你在后面的课程中形成一个良性循环:每次作业不止为了提交,而是为了搭建自己的能力库。