软件工程第二次结对作业

从原型到程序:校园拾光——第二次结对编程作业

项目 内容
所属课程 2026 软件工程与软件工程实践
作业要求 第二次结对作业:程序实现
本人 052402234 郭泽强 · 个人博客
结对同学 032401339 沈冠宇 · 队友博客
GitHub 主仓库 monkery-king-nice/052402234-032401339
队友 Fork 2074599796-cpu/052402234-032401339
协作 PR PR #1:日期筛选、本地评论与界面完善,已合并
第一次作业原型 Figma:校园失物招领原型

一、项目介绍与分工

上一次作业完成了校园失物招领的原型设计,这次作业则需要让页面上的操作真正生效。我们将项目命名为“校园拾光”,围绕“发布信息—浏览或搜索—查看详情—联系发布者—更新状态”完成核心流程,并增加照片上传、日期筛选、本地评论等功能。

项目使用 HTML、CSS 和 JavaScript,下载后可直接用 Google Chrome 打开 index.html。启事、照片和评论保存在当前浏览器的 localStorage 中,无需服务器。联系方式由发布者填写,联系与交接在线下或其他通信工具中完成,页面不提供即时聊天。

1.1 分工

以下按本次主仓库与 Fork 的开发范围整理。

成员 负责范围 主要产出
郭泽强 基础功能与主仓库整合;发布、搜索、详情、状态维护;照片上传和删除功能;提交版本检查与博客整理 基础页面与业务模型、原有单元测试、图片资源、主仓库开发记录
沈冠宇 在 Fork 中增加日期范围筛选、本地评论和界面优化;补充测试与展示材料;向主仓库提交 PR 日期及评论规则、新增测试、Chrome 验收脚本、截图、PR #1

协作采用“主仓库维护基础版本—队友 Fork 后在功能分支开发—提交 PR—合并回主仓库”的方式。队友的开发分支为 feat/date-filter-comments-ui,PR #1 已合并,合并提交为 ff5ffd1。

开发过程中使用了 Codex 辅助编码、测试和文档整理。本文中的功能结论以代码、提交记录与实际运行结果为依据;个人工作量不能直接用 AI 的运行时间或提交之间的时间间隔代替。

二、PSP 与时间复盘

PSP2.1 工作内容 参考估算 本次实际耗时
Planning / Estimate 明确范围、拆分任务与安排顺序 30 40
Analysis 分析核心流程、学习本地存储及测试方法 90 100
Design Spec 整理数据结构、页面与异常流程 60 65
Design Review 检查原型与课程范围是否一致 30 40
Coding Standard 约定命名、目录、校验与提交方式 20 30
Design 设计模型函数、筛选条件与交互细节 90 120
Coding 实现基础功能、图片、日期、评论及样式 360 450
Code Review 检查数据兼容、保存顺序和权限判断 60 80
Test 单元测试、Chrome 页面测试与问题修正 180 150
Reporting / Test Report 整理测试结果、说明与截图 60 60
Size Measurement 统计模块、测试和有效提交 20 30
Postmortem & Process Improvement Plan 总结问题、整理博客和改进计划 80 60

三、解题思路与设计实现

3.1 先完成一个能走通的流程

用户操作 页面入口 程序处理 用户得到的结果
发布寻物或招领 首页“我丢了东西”“我捡到了”或发布按钮 校验必填项、处理图片、写入本地存储 在“我的发布”及广场看到新启事
搜索或筛选 广场搜索框和筛选区域 组合关键词、类型、类别、状态、日期条件 展示匹配结果;无结果时可清除筛选
查看与联系 物品卡片的详情入口 展示描述、地点、日期、图片和联系方式 复制联系方式,进一步核实物品
结束信息 “我的发布”中打开详情 核对当前浏览器的发布者标识,保存新状态 寻物显示“已找到”,招领显示“已归还”
补充线索 详情下方“评论与线索” 校验昵称和正文,按启事 ID 保存 当前浏览器刷新后仍可查看留言

状态由发布者维护,更新入口在“我的发布”的详情中。完成后,广场卡片和详情都会显示新状态;误操作时可以恢复为进行中,减少错误结束信息带来的影响。

3.2 模块与数据结构

程序将业务规则和页面交互分开:model.js 管理校验、筛选、状态和存储;app.js 绑定事件并刷新界面;images.js 处理照片;seed.js 提供演示启事。这样测试核心规则时不必启动整个页面。

一条启事包含 id、ownerId、type、title、category、location、date、description、contact、publisher、images、status、createdAt。其中 date 是丢失或拾取日期,createdAt 是发布时间,两者分别用于日期筛选和列表排序。

数据 存储键 作用
启事列表及照片 campus-light-items-v1 保存物品信息和状态
当前发布者标识 campus-light-owner-v1 限制页面上维护他人启事的操作
单条启事评论 campus-light-comments-v1: + 编码后的启事 ID 避免不同物品的留言混在一起

3.3 核心流程图

发布、寻找、联系和更新状态的完整流程

图中的“联系与交接”属于页面之外的用户行为。程序提供联系方式及状态维护入口,不会把复制联系方式视为物品已经找回。

3.4 关键代码一:先校验,再创建记录

下面节选自 js/model.js 的 createItem:

const errors = validateDraft(draft);
if (Object.keys(errors).length) {
  const error = new Error('信息不完整,请检查表单');
  error.fields = errors;
  throw error;
}
if (!clean(ownerId)) throw new Error('缺少发布者标识');

validateDraft 会分别检查类型、名称、类别、地点、真实日历日期、描述、联系方式、称呼和照片。例如物品名称为 2~40 个字符,详细描述为 10~500 个字符。错误返回到具体字段,页面能够提示用户修改哪一项;通过校验后才创建默认状态为 active 的记录。

保存时也遵循“先保存、后更新界面”的顺序,下面是 app.js 中实际使用的函数:

function commitItems(next) {
  M.saveItems(storage, next);
  items = next;
}

如果本地存储已满,saveItems 会抛出明确错误,内存中的启事列表不会提前切换成未保存的结果,避免页面提示成功而刷新后数据消失。

3.5 关键代码二:由发布者维护状态

function updateStatus(items, id, ownerId, status) {
  if (!['active', 'resolved'].includes(status)) {
    throw new Error('无效状态');
  }
  const item = items.find(entry => entry.id === id);
  if (!item) throw new Error('信息不存在');
  if (!ownerId || item.ownerId !== ownerId) {
    throw new Error('只有发布者可以更新状态');
  }
  return items.map(entry =>
    entry.id === id ? { ...entry, status } : entry
  );
}

这里分别检查状态是否合法、记录是否存在、操作者是否匹配。函数返回新数组,并保留照片等其他字段。对于同一个 resolved 状态,寻物信息展示“已找到”,招领信息展示“已归还”,使结果符合业务含义。

四、附加特点及展示

4.1 按丢失或拾取日期组合筛选

只记得物品大概在哪几天丢失时,可以设置日期范围,再结合类别和关键词缩小查找范围。开始和结束当天都包含在结果内;仅填写一端时,另一端不限;起始日期晚于结束日期时显示错误,保留原输入。

下面节选自 filterItems:

if (validateDateRange(filters)) return [];
const start = clean(filters.startDate), end = clean(filters.endDate);
// 以下判断位于 items.filter 的回调中。
if (start && (!validDate(item.date) || item.date < start)) return false;
if (end && (!validDate(item.date) || item.date > end)) return false;

在确认日期有效后,固定格式的 YYYY-MM-DD 字符串可按日历顺序比较,避免将日期转成本地时区时间点后产生一天偏差。类型、类别、状态和关键词判断继续在同一筛选函数中执行。

桌面广场:关键词、类别、状态与日期范围筛选

4.2 每条启事独立的本地评论

详情下方可以填写昵称和线索,昵称为 2~24 个字符,正文为 1~500 个字符。提交前清除首尾空白;保存中禁用提交按钮;成功后清空正文;失败时保留输入和原评论,方便重试。

function commentStorageKey(itemId) {
  if (!clean(itemId)) throw new Error('缺少启事标识');
  return COMMENTS_KEY + encodeURIComponent(itemId);
}

每条启事使用不同存储键,因此校园卡的线索不会出现在耳机的详情下。展示正文时采用以下代码:

const text = document.createElement('p');
text.textContent = comment.body;

使用 textContent 后,即便正文包含 <script> 或 <img> 字样,也会作为文字显示,而不会作为 HTML 执行。评论按发表时间从早到晚显示;已完成的启事仍能查看和补充留言。

评论校验、读取与保存流程

详情中的本地评论与线索

本功能是纯前端本地留言演示,评论仅保存在当前浏览器,不同用户的设备和不同浏览器之间不会同步。它能演示补充线索的交互,但不能称为已上线的公共聊天室。

4.3 照片上传、压缩与预览

每条启事可上传最多 3 张 JPG、PNG 或 WebP 图片,单张原图不超过 5 MB。图片先在浏览器解码,最长边缩至不超过 1280 像素,再通过 JPEG 编码质量和必要的继续缩放,将每张保存图片控制在 200 KB 以内;压缩失败会提示重新选择。

images.js 中缩放比例的关键计算如下:

const scale = Math.min(
  1, 1280 / Math.max(image.naturalWidth, image.naturalHeight)
);
let width = Math.max(1, Math.round(image.naturalWidth * scale));
let height = Math.max(1, Math.round(image.naturalHeight * scale));

等比例缩放避免物品变形,上传前可预览和移除照片。详情优先展示发布者实际上传的照片;六条演示启事使用与名称对应的写实示例图片,并标注为示例图。示例素材用于展示界面,不代表真实失物。

4.4 其他便捷设计

设计 使用意义 实现方式
一键复制联系方式 减少手动抄录 优先剪贴板 API,失败时尝试兼容复制,并反馈结果
状态恢复 修正误标记 发布者可将已完成信息恢复为进行中
删除前二次确认 减少误删 确认后保存新列表,再清理对应评论
空结果与清除筛选 帮助用户继续搜索 显示明确空状态,统一清空筛选条件
手机布局与键盘焦点 方便不同屏幕和操作方式 响应式布局、底部导航、可见焦点;桌面 / 聚焦搜索

mobile-square

mobile-comments

mobile-publish

五、目录组织与使用说明

052402234-032401339/
├─ index.html                 页面入口,Chrome 直接打开
├─ css/
│  └─ style.css               配色、布局和手机适配
├─ js/
│  ├─ model.js                业务规则与本地存储
│  ├─ app.js                  页面渲染、事件和反馈
│  ├─ images.js               上传照片的校验与压缩
│  └─ seed.js                 六条演示启事
├─ assets/items/              本地示例图片及素材说明
├─ tests/
│  ├─ model.test.js           基础功能及照片相关测试
│  ├─ date-comments.test.js   日期范围与评论输入测试
│  ├─ comments.test.js        评论存储、隔离与异常测试
│  └─ browser.cjs             Chrome 页面自动验收
├─ docs/
│  ├─ screenshots/           界面及异常状态截图
│  ├─ diagrams/              核心流程和评论流程图
│  ├─ browser-tests.json     队友提交的浏览器测试记录
│  └─ unit-tests.xml         队友提交的单元测试记录
├─ package.json              开发测试命令
├─ package-lock.json         开发依赖版本锁定
├─ README.md                 下载、操作与限制说明
├─ BLOG_DRAFT.md             早期博客草稿
└─ BLOG_FINAL.md             本文整理稿

5.1 测试人员如何运行

  1. 打开主仓库,选择 Code → Download ZIP,将整个压缩包解压。
  2. 保持 index.html、css、js、assets 的相对位置,用 Google Chrome 打开 index.html。
  3. 在广场浏览示例信息,输入关键词或日期筛选,点击卡片查看详情和复制联系方式。
  4. 发布一条自己的测试信息,可选上传照片;在“我的发布”中修改状态或删除。
  5. 打开任意启事,在评论区域填写昵称和线索,刷新后检查本地保存结果。

日常使用不需要 Node.js、服务器或联网。Node.js 和浏览器测试依赖只用于开发验收。请勿只下载 HTML 而遗漏资源,也不要继续使用合并前的旧压缩包。

5.2 数据保存范围

同一 Chrome 用户配置、同一路径下可继续读取原数据。更换设备、浏览器用户配置、无痕会话或移动文件路径后,不应假定旧数据会自动出现。清除浏览器存储会删除本地记录;升级时保留原存储键,无需清空数据。

六、单元测试与自动化验收

6.1 工具选择及学习思路

单元测试使用 Node.js 内置的 node:test 和 node:assert/strict。业务函数不依赖页面,通过输入、返回值和异常即可检查;存储测试使用内存中的 Map 模拟浏览器存储,因此不会修改用户实际发布的信息。

学习和应用这套方法可以分成四步:先找出可独立调用的函数;再写清给定输入的预期结果;然后使用 assert.equal、assert.deepEqual 或 assert.throws 表达预期;最后运行测试,从失败信息定位具体分支。修正后重新运行整个测试集,检查是否破坏原功能。

6.2 一份可以照着操作的简易教程

第一步: 安装 Node.js 20 或以上版本,仅做测试时需要。打开项目目录中的 CMD,输入:

node --version
node --test tests/*.test.js

第二步: 理解一个最小测试。下面是可运行的教学示例,数据使用固定日期,不受运行当天影响。需要实践时可另存为 tests/tutorial.example.js,再执行 node --test tests/tutorial.example.js;它不计入仓库现有的 47 个测试。

const test = require('node:test');
const assert = require('node:assert/strict');
const M = require('../js/model.js');

test('起止日期相同时,包含当天的物品', () => {
  const items = [
    { id: 'a', date: '2026-09-28', createdAt: '2026-10-01' },
    { id: 'b', date: '2026-09-29', createdAt: '2026-10-01' }
  ];
  const result = M.filterItems(items, {
    startDate: '2026-09-28', endDate: '2026-09-28'
  });
  assert.deepEqual(result.map(item => item.id), ['a']);
});

这个测试刻意让发布时间与物品日期不同,可以发现“错误地使用发布时间筛选”的问题。把日期比较中的 >= 边界理解成严格大于时,同一天测试就会失败。

第三步: 阅读项目中的实际异常测试。下面节选自评论测试,用配额异常模拟存储已满:

const full = {
  getItem: storage.getItem,
  setItem: () => {
    throw Object.assign(new Error('quota'), {
      name: 'QuotaExceededError'
    });
  }
};
assert.throws(() => M.addComment(full, 'a', draft), /存储空间不足/);
assert.equal(storage.getItem(M.commentStorageKey('a')), before);

测试前已创建内存存储、保存原评论,并将原值记录为 before。两条断言同时检查“有明确提示”和“旧记录没有被覆盖”,而不仅是检查函数有没有抛出异常。

第四步: 页面功能还需要 Chrome 测试。安装仓库锁定的开发依赖后执行:

npm ci
npm run test:browser

脚本使用独立浏览器上下文,在离线模式下直接访问本地 HTML,覆盖真实点击、输入、上传、刷新和手机视口。运行时会生成截图及 test-results/browser.json。这与只检查模型函数的单元测试相互补充。

6.3 白盒思路与用例设计

用例围绕代码中的条件判断设计:有效/无效输入、合法/非法状态、发布者匹配/不匹配、存在/不存在记录、正常/失败存储。对于长度、日期和文件大小采用边界值;对于列表筛选采用条件组合;对于可能破坏原数据的操作检查写入前后是否一致。

下表列出实际测试覆盖的代表性情形,部分行对应同一个测试函数中的多条断言;全套测试共 47 项。

编号 函数或场景 输入与构造方式 预期结果 结果
1 createItem 完整合法的寻物信息 创建成功,默认进行中 通过
2 validateDraft 空物品名称 返回名称错误 通过
3 validateDraft 不存在的日历日期 拒绝创建 通过
4 filterItems 名称、地点、描述中的关键词及大小写变化 匹配对应启事 通过
5 filterItems 同时指定类型、类别、状态 只保留全部符合条件的记录 通过
6 updateStatus 正确发布者标记完成,再恢复 状态正确变化 通过
7 updateStatus 非发布者、记录不存在或非法状态 分别拒绝 通过
8 removeItem 删除自己的某条信息 其他启事和照片不变 通过
9 removeItem 尝试删除他人或演示信息 拒绝删除 通过
10 照片规则 无照片、三张以内、超过三张 接受可选合法照片,拒绝超量 通过
11 照片规则 空文件、不支持格式、超过 5 MB 返回明确错误 通过
12 图片数据 200 KB 边界与超出边界、外链或 SVG 只接受受限图片数据 通过
13 日期筛选 起止日期与物品日期相同 包含当天 通过
14 日期筛选 仅开始、仅结束、两端为空 单侧限制或不限日期 通过
15 日期校验 开始晚于结束、2 月 30 日 提示错误并返回空结果 通过
16 日期组合筛选 日期与类型、类别、状态、关键词组合 正确匹配或明确空结果 通过
17 评论校验 空白、昵称 24/25 字、正文 500/501 字 接受合法边界,拒绝超长或空白 通过
18 评论持久化 保存后重新读取 内容、时间和启事关联保持一致 通过
19 评论隔离 两个启事 ID,包括特殊字符 分别保存,不串条 通过
20 评论排序 时间乱序及相同时间 时间升序,同时间保持插入顺序 通过
21 保存失败 注入 QuotaExceededError 提示失败,原记录不变 通过
22 损坏评论 无效 JSON、错误结构、关联错误 读取报错,提交不覆盖原数据 通过
23 评论清理 删除目标启事的评论 不影响其他启事、照片和评论 通过
24 页面安全展示 含 HTML 标签的昵称和正文 作为文字显示,无脚本执行 Chrome 验收通过

对于测试人员可能输入的异常数据,重点考虑了空格与换行、不存在的日期、相反的日期范围、超量图片、超长评论、错误的发布者标识和保存失败。测试关注具体可观察结果,而不是只走一次正常发布流程。

6.4 实际结果与测试边界

验证轮次 环境与方式 结果
队友提交前验收 2026-10-10,Chrome 154.0.8037.93;记录已随 PR 提交 47/47 单元测试,10/10 页面场景
合并后复验 2026-10-10,合并版本 ff5ffd1;Chrome 155.0.8059.39 47/47 单元测试,10/10 页面场景

合并后页面复验在独立副本中使用已有 Playwright 1.62.1 的测试接口,未重新验证 package-lock.json 所锁定的 Playwright 1.64.0 安装过程。两轮环境不同,分别记录,不把它们混写为同一环境。合并后页面复验未出现页面脚本错误,也没有 HTTP 资源请求;覆盖了 320、390、768 像素宽度下的布局检查。

invalid-date

comment-storage-error

这些测试覆盖了主要业务分支、关键边界和保存异常,能够支持本次纯前端演示验收;没有生成分支覆盖率报告,因此不声称达到 100% 代码覆盖率,也不能据此保证没有任何缺陷。尚未验证真实多用户并发、跨设备共享或大量数据下的性能,因为本版没有对应的服务端能力。后续可补充更全面的可访问性检查和大数据量测试。

七、GitHub 协作与分阶段提交

本次保留了真实开发提交,功能完成后的本地 commit 与上传远程的 push 并不总是一一对应。早期受上传环境影响,曾通过 GitHub 网页上传并调整文件目录,随后合并保留了原有本地开发历史;后续部分本地提交由一次 push 一起上传。

阶段 提交或 PR 内容
基础模型 77c68cc 发布校验、筛选和状态规则
基础交互 27969a0 响应式页面与失物招领流程
测试与说明 55d1924 基础测试、使用文档
网页上传与目录整理 bedbb3d、daedfbd、71d5ee9、fd202be、3810bae、d8fa1db 上传文件并整理 CSS、JS 和测试文件的位置
历史整合 5a02abf 保留最初本地开发提交,整合网页上传历史
照片功能 104cb16 图片上传、压缩与详情图库
图片展示 6e2d334 示例物品与写实照片对应
删除功能 eb6ec0b 发布者二次确认后删除
队友功能开发 78cb701 日期筛选、评论与界面;此时包含共享服务方案
调整运行范围 6e48bbf 移除共享服务依赖,评论改为本地存储
验收与文档 2ab1d54、8f43d7a 测试记录、截图、运行说明和提交链接
合并协作成果 ff5ffd1 / PR #1 队友功能分支合并到主仓库

查看主仓库真实提交历史;查看队友 PR 与合并情况。

以下截图于 2026 年 10 月 10 日(北京时间)在 Chrome 中直接打开 GitHub 公开页面取得,保留网页显示的日期、提交信息和合并状态。页面原始日期显示与本地日期口径可能不同,未对截图内容进行改写。

github-commits-recent

上图可看到照片上传、图片匹配、删除功能,以及队友的日期筛选、评论调整和最终合并记录。

github-commits-earlier

上图保留了基础模型、页面流程和测试阶段,也如实展示了网页上传期间的目录移动提交。

github-pr-merged

PR 页面显示 Merged,从队友 Fork 的功能分支合并了 4 个提交。完整提交历史长截图另存于
github-commits-full
,截图来源及浏览器记录见 docs/github-screenshot-evidence.json。

八、遇到的问题、尝试与收获

8.1 本地有提交,远程却看不到完整开发过程

问题: 早期上传遇到 TLS、Git 辅助进程和认证相关错误,网页上传又产生了文件移动等提交,远程记录一度不能直观反映最初的开发阶段。

尝试: 检查远程地址和本地分支,先保留原开发历史;通过网页上传处理文件,再整合历史。后续在本机 CMD 中执行 push,确认本地提交上传成功,并用 git status -sb 检查本地与远程跟踪分支的关系。

结果: 原始开发提交已保留,照片、删除等后续成果也进入远程,队友 PR 已合并。不过 Codex 内的 Git 辅助进程故障尚未修复,不能把本地 CMD 上传成功写成所有环境都恢复正常。

收获: commit 是保存开发阶段,push 是同步到远程,两者要分别检查;目录整理提交应如实说明,不能充当新的功能开发记录。

8.2 评论方案超出了最终运行范围

问题: 希望不同浏览器看到公共评论时,需要共享数据来源,最初方案引入了本地共享服务,与最终“直接打开 HTML 使用”的要求不一致。

尝试: 重新明确纯前端范围,改为按启事 ID 保存本地评论,同时更新页面提示、README 和自动化测试,移除服务入口与运行依赖。

结果: 在关闭共享服务、浏览器离线的条件下,仍可直接打开 HTML 使用日期筛选、留言和原有功能;不同浏览器不会同步,文档与页面明确说明这一限制。

收获: 增加一个功能时,要一起确认它的运行条件和数据范围。提出“公共评论”与实现“本地留言”代表不同能力,验收材料必须与实际功能一致。

8.3 图片与旧数据的兼容

问题: 增加上传图片后,旧启事可能没有照片,例如此前自己发布的手机信息。图片较大时,还会增加本地存储压力。

尝试: 图片设为可选字段,读取旧记录时兼容缺失的照片数组;实际上传照片优先展示,示例图片只匹配对应演示启事;对原图限制数量、格式和大小,并在保存前压缩。

结果: 没有照片的旧记录仍可读取,不会错误地使用无关物品照片。测试验证了照片刷新保存、状态更新保留照片,以及容量不足时的错误提示。

收获: 新增字段不能要求用户清空旧数据才能升级,演示图片也不能假装成用户已经上传的照片。

九、对队友的评价

值得学习的地方: 沈冠宇补充功能时,也提交了对应测试、截图和运行说明。日期筛选没有停留在“增加两个输入框”,还处理了单侧日期、起止边界、无效范围和组合条件;评论也覆盖了保存失败、输入保留和启事隔离。这提醒我,功能交付应包括正常操作、异常反馈和可复现的验证材料。

需要改进的地方: 开发前对运行范围还可以确认得更早。评论最初采用共享服务方案,后面改为纯前端,带来了代码、测试和文档的同步调整。以后可以在任务开始时写清“是否需要服务器、数据是否共享、怎样验收”,完成一个小阶段后就按约定方式运行一次,减少最后集中返工。

对自己的反思: 我在整合阶段需要更及时地检查远程提交是否同步、博客说明是否过期,以及 PSP 是否持续记录。程序能运行只是交付的一部分,最终说明和协作证据也应随着开发更新。

十、总结

通过这次结对作业,我们将第一次设计的“校园拾光”原型转化成了可以实际运行的网页,完成了“发布信息—浏览或搜索—查看详情—联系发布者—更新状态”的基本流程,并增加了照片上传、日期筛选、本地评论、删除确认和手机布局。对我来说,这次作业让我更具体地理解了从原型设计到程序实现之间的差距:原型中一个简单的按钮,落实到代码里,往往还涉及输入校验、数据保存、异常提示和页面更新等一系列工作。

在我负责的基础功能与项目整合中,体会比较深的是数据处理的顺序。例如,发布信息时,如果先更新页面再保存数据,一旦浏览器存储失败,用户就可能看到“发布成功”,却在刷新后找不到刚才的内容。因此,程序采用先保存、后更新界面的方式。增加照片功能时,也需要兼容原先没有图片字段的启事,不能要求用户清空旧数据才能继续使用。这些细节让我开始关注功能在不同情况下是否都能给出合理结果。

日期筛选和评论功能的完善,也让我认识到提前明确需求范围的重要性。评论最初采用了共享服务方案,后来根据直接打开 HTML 使用的要求,调整为浏览器本地存储。这个变化同时影响了代码、测试方式和使用说明。如果一开始就明确“是否需要服务器、数据是否跨设备共享、测试人员如何运行”,就能减少后续调整。今后拆分任务时,我会把运行条件和验收方法一起写清楚,让双方对最终要交付的内容有一致的理解。

测试是这次作业中另一项重要收获。项目的 47 个单元测试和 10 个 Chrome 页面验收场景,除了检查正常操作,还覆盖了日期范围错误、空白评论、图片超限、存储失败和非发布者修改状态等情况。设计这些测试时,需要先明确程序在每一种情况下应该怎样表现,再用断言验证结果。这个过程也能反过来发现需求中没有考虑清楚的地方。测试全部通过能够为当前版本提供依据,但仍不能代替对真实使用情况的持续检查。

在结对协作方面,我负责基础功能和主仓库整合,沈冠宇通过 Fork 和功能分支补充日期筛选、评论与界面调整,再通过 PR 合并到主仓库。这让我熟悉了从独立开发到整合交付的协作过程。队友同时提交了测试、截图和说明,也提醒我:交付一个模块时,应让接收者能够理解改动,并复现验证结果。合并之后重新运行原有功能和新增功能的测试,是确认双方成果能够一起工作的必要步骤。

Git 上传过程中遇到的问题,则让我进一步区分了本地 commit 和远程 push。代码在本地保存了提交,并不代表 GitHub 上已经同步;网页上传产生的目录调整记录,也需要与实际功能开发记录区分。以后我会在每个阶段完成后及时检查分支状态和远程历史,并同步维护 README、截图和博客,减少最后集中整理时的遗漏。

posted @ 2026-10-10 01:36  郭泽强  阅读(3)  评论(0)    收藏  举报