COMP1531 是 UNSW 计算机科学专业第一门真正意义上的工程实践课,和你之前学过的 COMP1511(程序设计基础)完全不同。
COMP1511 教你"写代码",COMP1531 教你"作为团队交付软件"——这两件事的难度差距比很多学生想象的要大得多。
课程核心架构
COMP1531 的核心是一个贯穿整个学期的组队项目,分为三次 Iteration 提交:
| 阶段 | 内容 | 典型权重 |
|---|---|---|
| Iteration 1 | 基础数据结构 + 接口定义 | ~25% |
| Iteration 2 | 核心功能实现 + 测试覆盖 | ~35% |
| Iteration 3 | 完整系统 + 部署 + 文档 | ~40% |
每次迭代都需要:代码提交到 GitLab、通过 CI pipeline、完成 peer review、提交反思报告。
技术栈
典型的 COMP1531 项目栈(以 Toohak/Beans 类项目为例):
后端:Python 3.10+ / Flask
数据:内存存储(JSON 序列化)/ 部分学期引入 SQLite
测试:pytest / coverage
版本控制:GitLab + CI/CD
文档:Swagger / 接口注释
Iteration 1:先把地基打好
很多团队在 Iteration 1 犯的错:把所有时间花在写功能,忽略了接口设计和测试。
Iteration 1 的核心不是"做多少功能",而是:
1. 数据结构设计
早期的数据结构决定后续所有迭代的开发速度。推荐模式:
# 用全局 data store 模拟数据库
data_store = {
'users': [], # 用户列表
'channels': [], # 频道列表
'messages': [], # 消息列表
'tokens': [] # 活跃 token
}
def get_data():
global data_store
return data_store
def set_data(store):
global data_store
data_store = store
常见错误:每个函数各自维护一份数据,导致 Iteration 2 重构地狱。
2. Auth 功能:正确处理 Token
import hashlib
import jwt
import os
SECRET = os.environ.get('JWT_SECRET', 'dev_secret')
def generate_token(u_id: int, session_id: int) -> str:
payload = {'u_id': u_id, 'session_id': session_id}
return jwt.encode(payload, SECRET, algorithm='HS256')
def decode_token(token: str) -> dict:
try:
return jwt.decode(token, SECRET, algorithms=['HS256'])
except jwt.InvalidTokenError:
raise AccessError('Invalid token')
常见丢分点:
- Token 验证不够严格(任意字符串都能通过)
- 没有处理
AccessErrorvsInputError的区别(两者 HTTP 状态码不同)
3. 错误处理规范
from src.error import InputError, AccessError
# InputError → 400
# AccessError → 403
# 一定要在 error.py 里正确定义这两个 exception
Iteration 2:测试覆盖是关键
Iteration 2 的评分非常重视测试覆盖率和测试质量,不是只看功能有没有实现。
pytest 测试结构
tests/
├── auth_test.py
├── channel_test.py
├── channels_test.py
├── message_test.py
└── conftest.py # 共享 fixtures
conftest.py 示例:
import pytest
import requests
BASE_URL = 'http://127.0.0.1:8080'
@pytest.fixture
def clear():
requests.delete(f'{BASE_URL}/clear/v1')
@pytest.fixture
def register_user(clear):
resp = requests.post(f'{BASE_URL}/auth/register/v3', json={
'email': 'test@example.com',
'password': 'password123',
'name_first': 'Test',
'name_last': 'User'
})
return resp.json()
测试覆盖率要求
# 检查覆盖率
pytest --cov=src tests/ --cov-report=term-missing
# 目标:80%+ 语句覆盖率
# 但更重要的是"边界测试"和"错误路径"覆盖
最容易丢分的测试遗漏:
- 无效 token 测试(每个需要 auth 的接口都要测)
- 权限测试(普通用户 vs channel owner vs global owner)
- 分页参数测试(start 超出范围时的行为)
- 重复操作测试(加入已在的频道、重复发送等)
Iteration 3:部署与 Deployment
Iteration 3 通常要求把应用部署到服务器(CSE 服务器或本地)并能通过 CI pipeline 自动测试。
GitLab CI 配置
# .gitlab-ci.yml 基础结构
stages:
- test
- coverage
test:
stage: test
image: python:3.10
before_script:
- pip install -r requirements.txt
script:
- pytest tests/
coverage:
stage: coverage
script:
- pytest --cov=src tests/ --cov-fail-under=80
Flask 部署启动
# server.py
from flask import Flask
from src import config
app = Flask(__name__)
if __name__ == '__main__':
app.run(port=config.port, debug=True)
7 个最容易丢分的雷区
根据往届学生经验总结:
1. 忽略 spec 里的"assume"条款 每条接口说明里的 assume 是你不需要处理的边界情况,但其他未说明的都需要防御性处理。
2. token 与 session 混淆 token 应该是 session-based 的——用户登出后旧 token 应该失效,即使 u_id 相同。
3. GitLab commit 频率太低 CI 要求每个 merge request 都有合理的 commit 历史。3 人团队最后一天 push 20 个 commit = 扣分。
4. 测试文件依赖顺序
每个测试必须独立可运行,不能依赖其他测试留下的数据。用 clear fixture 确保每次测试前数据被重置。
5. HTTP 状态码错误
InputError 必须返回 400,AccessError 必须返回 403。很多学生把两者都返回 400。
6. 文档注释缺失 每个函数的 docstring 都要写参数说明和异常说明,这会被检查。
7. 不处理并发写入 data store 的全局变量在多线程 Flask 下可能出现 race condition,建议用 threading.Lock 或 Flask 的 app context。
组队建议
COMP1531 是你第一次真正意义上的团队协作,有几个事情比代码更重要:
分工要明确,不要"谁空谁做"
- 每个 iteration 开始前开会,用 GitLab Issues 把任务分配到人
- 每个任务设 deadline 比项目 deadline 早 2 天
Code Review 是必须的,不是选做的
- 不要直接 push 到 main,所有改动通过 merge request
- 至少一个人 review 后才能合并
先写测试,再写实现 TDD(测试驱动开发)在这门课里不只是建议,很多情况下接口定义完就该先写测试,确保所有人对预期行为理解一致。
遇到了困难?
COMP1531 的 bug 有时很难排查——可能是 token 问题、可能是数据结构设计的债、可能是 CI 环境和本地不一致。
如果你:
- Iteration deadline 临近但功能还没跑通
- pytest 报错但不知道从哪里下手
- 团队协作出了问题,进度落后
可以找我们具体看你的代码——发项目结构和报错信息给客服,30 分钟内告诉你问题出在哪。
