🔄 Software Development Lifecycle (SDLC)🔄 软件开发生命周期 (SDLC)
The Software Development Lifecycle (SDLC) is the structured process used to develop software. Understanding its phases is crucial for exam questions about project management and software engineering practices.软件开发生命周期 (SDLC) 是用于开发软件的结构化流程。理解其各个阶段对于项目管理和软件工程实践的考试题目至关重要。
📋 The 5 Core Phases of SDLC📋 SDLC 的 5 个核心阶段
Requirements Analysis需求分析 - Gather and document what the software should do - 收集和记录软件应该做什么
Design设计 - Plan the architecture, UI/UX, and technical approach - 规划架构、UI/UX 和技术方法
Implementation/Coding实现/编码 - Write the actual code - 编写实际代码
Testing测试 - Find and fix bugs, verify requirements are met - 发现并修复错误,验证是否满足需求
Deployment & Maintenance部署与维护 - Release to users and provide ongoing support - 发布给用户并提供持续支持
💡 Exam Tip: What's NOT part of SDLC?💡 考试技巧:什么不是 SDLC 的组成部分?
Risk Management is often confused as an SDLC phase, but it's actually part of Project Management, not the core SDLC itself. While important, it's not one of the 5 fundamental phases listed above.风险管理常被误认为是 SDLC 阶段,但它实际上是项目管理的一部分,不是核心 SDLC 本身。虽然很重要,但它不是上述 5 个基本阶段之一。
🔀 Git Workflow: The Correct Order🔀 Git 工作流:正确的顺序
Git is the version control system used in COMP1531. Understanding the correct order of Git commands is essential for both lab work and exam questions.Git 是 COMP1531 中使用的版本控制系统。理解 Git 命令的正确顺序对于实验工作和考试题目都至关重要。
// ❌ WRONG ORDER
git commit → git add → git push // Error: nothing to commit
// ❌ WRONG ORDER
git push → git add → git commit // Error: local changes not committed
// ✅ CORRECT ORDER
git add → git commit → git push
📝 What Each Command Does📝 每个命令的作用
Command命令
Purpose用途
Analogy类比
git add
Stage changes for commit暂存更改以供提交
Adding items to shopping cart将商品添加到购物车
git commit
Save staged changes locally在本地保存暂存的更改
Placing the order下单
git push
Send commits to remote repository将提交发送到远程仓库
Shipping the order发货
💡 Remember: You must add before you can commit, and you must commit before you can push. This is the fundamental Git workflow!💡 记住:你必须先add才能commit,必须先commit才能push。这是基本的 Git 工作流!
📦 npm: Development vs Production Dependencies📦 npm:开发依赖与生产依赖
⚠️ Common Exam Question: What does --save-dev do?⚠️ 常见考试题:--save-dev 是做什么的?
Correct Answer: It installs a package that is needed only for development (e.g., testing frameworks, build tools) and NOT included in production dependencies.正确答案:它安装仅在开发时需要的包(如测试框架、构建工具),不包含在生产依赖中。
🔍 Dynamic vs Static Verification 易错点🔍 动态 vs 静态验证 易错点
🚨 TRICKY: Don't Be Fooled by "Analysis"!🚨 陷阱:别被"分析"迷惑了!
The keyword "executing" (执行) means DYNAMIC verification. Static analysis tools might "analyze" code, but if you're running the code with test data, it's DYNAMIC!关键词"executing"(执行)表示动态验证。静态分析工具可能"分析"代码,但如果你运行代码并用测试数据测试,那就是动态验证!
Jest tests, Manual testing, DebuggingJest 测试、手动测试、调试
// Static Analysis - No execution, finds errors by reading code
function add(a: number, b: number): number {
return a + "hello"; // TypeScript error WITHOUT running
}
// Dynamic Verification - MUST run code to find issues
function divide(a, b) {
return a / b;
}
divide(10, 0); // Only discovers divide-by-zero WHEN RUNNING
💡 Memory Trick:executing = Dynamic, without running = Static. Focus on whether the code RUNS!💡 记忆技巧:executing(执行)= 动态,without running(不运行)= 静态。关注代码是否运行!
🌐 HTTP Methods: GET vs POST 易错点🌐 HTTP 方法:GET vs POST 易错点
🚨 TRICKY: Don't Confuse Behavior with Protocol!🚨 陷阱:不要混淆行为与协议!
GET requests are "usually" cached and POST are "usually" not cached, but that's browser behavior, NOT the fundamental protocol difference! The real difference is where the data goes!GET 请求"通常"被缓存,POST"通常"不被缓存,但那是浏览器行为,不是协议层面的本质区别!真正的区别在于数据去哪里!
📋 The FUNDAMENTAL Difference (Exam Answer A)📋 本质区别(考试答案 A)
Feature特性
GET
POST
Data Location数据位置
URL query string ?key=valueURL 查询字符串 ?key=value
Request Body请求体
Visibility可见性
Visible in URL在 URL 中可见
Not in URL不在 URL 中显示
Bookmarkable可收藏
✅ Yes✅ 是
❌ No❌ 否
Length Limit长度限制
~2000 chars (URL limit)~2000 字符(URL 限制)
No practical limit无实际限制
// GET - Data in URL (visible, bookmarkable)
fetch('/api/users?name=John&age=25')
// Full URL: https://api.com/users?name=John&age=25
// POST - Data in body (hidden, not in URL)
fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name: 'John', age: 25 })
})
// URL: https://api.com/users (clean!)
💡 Memory Trick:GET gets data FROM the URL. POST posts data IN the body. Caching is secondary behavior!💡 记忆口诀:GET 从 URL 获取数据。POST 把数据放入请求体。缓存是次要行为!
💾 Data Persistence: Immediate vs Batched 易错点💾 数据持久化:立即 vs 批量 易错点
🚨 TRICKY: It's About Performance, Not Space!🚨 陷阱:是关于性能,不是空间!
Frequent disk writes don't "double" the space - they overwrite. The real issue is I/O performance: disk operations are 100,000x slower than memory operations!频繁的磁盘写入不会让空间"翻倍"——它们是覆盖写入的。真正的问题是I/O 性能:磁盘操作比内存操作慢 10 万倍!
⚡ Performance Comparison⚡ 性能对比
Operation Speed (relative to CPU):
CPU Calculation ████████████████████████████████ 1 ns
Memory Access ████████████████████ 100 ns
SSD Read/Write ████ 10,000 ns
HDD Read/Write █ 10,000,000 ns
Disk I/O is 100,000x SLOWER than memory!
// ❌ BAD: Write on every API call
app.post('/order', (req, res) => {
orders.push(newOrder);
fs.writeFileSync('orders.json', JSON.stringify(orders)); // Every request!
res.send('OK');
});
// Problem: Each request blocks on disk I/O
// ✅ GOOD: Batch writes
let pendingWrites = [];
setInterval(() => {
if (pendingWrites.length > 0) {
fs.writeFileSync('orders.json', JSON.stringify(pendingWrites));
pendingWrites = [];
}
}, 5000); // Write every 5 seconds
// Benefit: Multiple orders = one disk write
💡 Remember: The main downside of immediate persistence is performance degradation due to frequent I/O operations, not increased disk space usage.💡 记住:立即持久化的主要缺点是由于频繁 I/O 操作导致的性能下降,而不是磁盘空间使用增加。
🧪 Branch Coverage: Testing ALL Paths🧪 分支覆盖:测试所有路径
Branch coverage measures whether every possible path through your code has been tested. Unlike line coverage (which just checks if code ran), branch coverage requires testing BOTH outcomes of every decision.分支覆盖衡量是否测试了代码中所有可能的路径。与行覆盖率(只检查代码是否运行)不同,分支覆盖需要测试每个决策的两种结果。
💡 Exam Tip: For 100% branch coverage, you need test values that hit each boundary and each range. Don't forget the "else" path!💡 考试技巧:要获得 100% 分支覆盖率,你需要测试每个边界和每个范围的值。别忘了 "else" 分支!
💡 Key Point:finallyALWAYS executes, regardless of whether an error occurred or not. This is why it's used for cleanup (closing files, releasing resources).💡 关键点:finally始终会执行,无论是否发生错误。这就是为什么它用于清理操作(关闭文件、释放资源)。
🔒 Security: Never Trust the Client!🔒 安全:永远不要信任客户端!
🚨 Security Anti-Pattern🚨 安全反模式
If a frontend cache (localStorage) replaces server-side authorization checks, that's a critical security vulnerability. Users can edit localStorage and gain unauthorized access!如果前端缓存(localStorage)替代了服务器端授权检查,那就是一个严重的安全漏洞。用户可以编辑 localStorage 并获得未授权访问!
💡 Security Principle: Never trust data from the client. Authentication and authorization MUST happen on the server. Frontend "optimizations" that bypass server checks are security holes.💡 安全原则:永远不要信任来自客户端的数据。认证和授权必须在服务器上进行。绕过服务器检查的前端"优化"是安全漏洞。
🚨 TRICKY: Know Which Principle Matches Which Description!🚨 陷阱:要知道哪个原则对应哪个描述!
"Only write the code you know you will need" = YAGNI (You Aren't Gonna Need It), NOT DRY!"只写你知道你会需要的代码" = YAGNI(你不会需要它),不是 DRY!
📊 The 4 Principles Quick Reference📊 4 个原则快速参考
Acronym缩写
Full Name全称
Core Idea核心思想
YAGNI
You Aren't Gonna Need It
Only write code you know you need只写你确定需要的代码
DRY
Don't Repeat Yourself
Avoid code duplication避免代码重复
KISS
Keep It Simple, Stupid
Choose the simplest solution选择最简单的解决方案
SOLID
5 OOP principles
Single responsibility, Open/Closed, etc.单一职责、开闭原则等
// ❌ Violating YAGNI: Writing "future-proof" code
function createUser(name, email) {
// "We might need multi-language support later!"
const translations = loadAllLanguages(); // Not needed NOW
// "We might add SMS notifications!"
const smsService = initSMSService(); // Not needed NOW
return { name, email };
}
// ✅ Following YAGNI: Only what's needed NOW
function createUser(name, email) {
return { name, email };
}
// ❌ Violating DRY: Code duplication
function areaCircle(r) { return 3.14 * r * r; }
function areaSquare(s) { return s * s; }
function areaRect(w, h) { return w * h; }
// ✅ Following DRY: Abstract common logic
function area(shape, ...dims) {
const formulas = {
circle: (r) => 3.14 * r * r,
square: (s) => s * s,
rectangle: (w, h) => w * h
};
return formulas[shape](...dims);
}
💡 Memory Tricks:
• YAGNI = "You" = you don't need that code yet
• DRY = "Dry" = code should be dry, no watery duplication
• KISS = "Kiss" = keep it simple💡 记忆技巧:
• YAGNI = "You" = 你不需要那些代码
• DRY = "Dry" = 代码要干燥,不要有重复的水分
• KISS = "Kiss" = 保持简单
📝 Requirements: Use Cases vs User Stories📝 需求:用例 vs 用户故事
📊 Comparison📊 对比
Aspect方面
User Stories用户故事
Use Cases用例
Format格式
Informal, simple非正式、简单
Formal, detailed正式、详细
Focus重点
User value, goals用户价值、目标
System flow, all scenarios系统流程、所有场景
Best for最适合
Agile, rapid iteration敏捷开发、快速迭代
Stable requirements, documentation稳定需求、文档化
// User Story format
As a ,
I want ,
So that .
// Example:
As a student,
I want to view my exam marks,
So that I can track my academic progress.
💡 Exam Tip: For agile/startup contexts, choose User Stories. They emphasize user value and support iteration. Use Cases are more formal and lock in design early.💡 考试技巧:对于敏捷/初创环境,选择用户故事。它们强调用户价值并支持迭代。用例更正式,会早期锁定设计。
📚 Documentation: Why Skip It?📚 文档:为什么要跳过?
⚠️ Long-term Consequence of Skipping Docs⚠️ 跳过文档的长期后果
The most significant consequence is reduced maintainability and knowledge transfer. When developers leave or new ones join, undocumented code becomes a liability.最显著的后果是可维护性降低和知识传递困难。当开发人员离开或新人员加入时,未记录的代码会成为负担。
💡 Key Point: Skipping documentation might speed up deployment NOW, but creates technical debt that slows down FUTURE development and onboarding.💡 关键点:跳过文档现在可能加快部署,但会产生技术债务,会减慢未来的开发和入职。
📄 Swagger/OpenAPI: What It Does 易错点📄 Swagger/OpenAPI:它能做什么 易错点
🚨 TRICKY: Swagger Describes, It Doesn't Execute!🚨 陷阱:Swagger 描述,它不执行!
Swagger defines API structure (endpoints, parameters, data types) but does NOT generate authentication tokens, store credentials, or encrypt messages. Those are runtime operations, not documentation!Swagger 定义 API 结构(端点、参数、数据类型),但不生成认证令牌、存储凭据或加密消息。那些是运行时操作,不是文档!
✅ What Swagger DOES✅ Swagger 能做什么
Define endpoints (URL paths)定义端点(URL 路径)
Specify request parameters指定请求参数
Show data types/schemas显示数据类型/模式
Document response formats记录响应格式
❌ What Swagger Does NOT Do❌ Swagger 不做什么
Generate authentication tokens (backend does this)生成认证令牌(后端做这个)
Store credentials securely (that's a key vault)安全存储凭据(那是密钥保管库)
# Swagger/OpenAPI specification
openapi: 3.0.0
paths:
/users/{id}: # [A] Defines endpoint
get:
parameters: # [A] Defines parameters
- name: id
in: path
schema:
type: integer # [D] Shows data type
responses:
200:
content:
application/json:
schema:
type: object
properties:
name:
type: string # [D] Shows data type
💡 Remember: Swagger is a documentation tool. It describes what an API looks like. It doesn't execute business logic or handle security operations.💡 记住:Swagger 是一个文档工具。它描述 API 的样子。它不执行业务逻辑或处理安全操作。
"Functions must be declared at the top of the file" describes Hoisting, NOT First-Class status! First-Class means functions can be treated like values."函数必须在文件顶部声明"描述的是变量提升,不是一等函数状态!一等函数意味着函数可以像值一样被对待。
🎯 What "First-Class" REALLY Means🎯 "一等"的真正含义
In JavaScript, functions are first-class citizens, meaning they can be:在 JavaScript 中,函数是一等公民,意味着它们可以:
Stored in variables存储在变量中
Passed as arguments to other functions作为参数传递给其他函数
Returned as values from functions作为值从函数返回
Assigned as object properties作为对象属性赋值
// First-Class Function Examples:
// 1. Stored in variables
const greet = function(name) {
return `Hello, ${name}!`;
};
// 2. Passed as arguments
const names = ['Alice', 'Bob'];
const greetings = names.map(greet); // Function as argument!
// 3. Returned as values
function createMultiplier(n) {
return function(x) { // Return a function!
return x * n;
};
}
// 4. Assigned as object properties
const calculator = {
add: function(a, b) { return a + b; }, // Function as property
subtract: (a, b) => a - b
};
💡 Don't confuse:
• First-Class = functions can be used like values (stored, passed, returned)
• Hoisting = function declarations can be called before they're defined
These are DIFFERENT concepts!💡 不要混淆:
• 一等函数 = 函数可以像值一样使用(存储、传递、返回)
• 变量提升 = 函数声明可以在定义之前调用
这是不同的概念!
🚨 TRICKY: Function vs Function Call Result!🚨 陷阱:函数 vs 函数调用结果!
If result = double(5), then result stores a NUMBER (the return value), NOT a function reference! The function was called (parentheses!), so it executed and returned a value.如果 result = double(5),那么 result 存储的是一个数字(返回值),不是函数引用!函数被调用了(有括号!),所以它执行并返回了一个值。
function makeMultiplier(n: number) {
return function (x: number): number { // Anonymous function!
return x * n;
};
}
const double = makeMultiplier(2);
// double IS a function: function(x) { return x * 2; }
const result = double(5);
// result = 5 * 2 = 10 (a NUMBER, not a function!)
// Key distinction:
const add = (a, b) => a + b; // add is a FUNCTION
const sum = add(3, 4); // sum is a NUMBER (7)
📊 Higher-Order Function Definition📊 高阶函数定义
A higher-order function is a function that does at least one of the following:高阶函数是满足以下至少一项的函数:
Takes a function as an argument (e.g., map, filter)接受函数作为参数(如 map、filter)
Returns a function as a result (e.g., makeMultiplier)返回函数作为结果(如 makeMultiplier)
// Higher-Order Function Examples:
// Type 1: Takes a function as argument
[1, 2, 3].map(x => x * 2); // map takes a function
[1, 2, 3].filter(x => x > 1); // filter takes a function
// Type 2: Returns a function
function makeMultiplier(n) {
return x => x * n; // Returns a function
}
// Combining both:
function withLogging(fn) {
return function(...args) {
console.log('Calling with:', args);
const result = fn(...args);
console.log('Result:', result);
return result;
};
}
💡 Exam Tip: When you see (), a function is being CALLED and returns a VALUE. Without (), you're referring to the function itself. This is the key distinction!💡 考试技巧:当你看到 ()时,函数正在被调用并返回一个值。没有 ()时,你指的是函数本身。这是关键区别!
📋 Requirements: Functional vs Non-functional📋 需求:功能性 vs 非功能性
📊 Quick Comparison📊 快速对比
Type类型
Question it Answers回答的问题
Examples例子
Functional功能性
What the system DOES系统做什么
User can view marks, Admin can ban users用户可以查看成绩、管理员可以封禁用户
💡 Exam Tip: "Staff can view project marks but not exam marks" is Functional - it specifies WHAT data different users can/cannot access.💡 考试技巧:"工作人员可以查看项目成绩但不能查看考试成绩"是功能性需求——它指定了不同用户可以/不能访问什么数据。
Scenario-based acceptance criteria use the Given-When-Then format to describe testable user scenarios.基于场景的验收标准使用 Given-When-Then 格式来描述可测试的用户场景。
GIVEN a COMP1531 staff member is logged into the system
WHEN they navigate to view a student's marks
THEN project marks are displayed
AND exam marks are NOT displayed
📝 Format Breakdown📝 格式分解
GIVEN - The initial context/precondition初始上下文/前置条件
WHEN - The action/user trigger操作/用户触发器
THEN - The expected outcome预期结果
AND - Additional outcomes附加结果
⚔️ Git: Resolving Merge Conflicts⚔️ Git:解决合并冲突
Merge conflicts occur when two branches have modified the same lines in different ways, and Git cannot automatically resolve them.合并冲突发生在两个分支以不同方式修改了相同的行,Git 无法自动解决它们。
// Conflict markers in the file:
<<<<<<< HEAD
Your code here
=======
Their code here
>>>>>>> branch-name
// Resolution steps:
1. git status // See conflicted files
2. Open file, resolve conflict manually
3. Remove conflict markers
4. git add
5. git commit -m "Resolve merge conflict"
6. git push
// Example code:
if (start < 0) { // Decision point 1
return -1;
} else if (start === 0) { // Decision point 2
return 0;
}
let i = start;
while (i > 0) { // Decision point 3
if (i === 1) { // Decision point 4
console.log("last");
}
i--;
}
// Complexity = 4 + 1 = 5
// ❌ Violating DRY - duplicated logic
function aliceMarks() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
console.log("Alice's total = " + total);
}
function bobMarks() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
console.log("Bob's total = " + total);
}
// ✅ Following DRY - extracted common logic
function totalMarks(name, marks) {
let total = 0;
for (let i = 0; i < marks.length; i++) {
total += marks[i];
}
console.log(`${name}'s total marks = ${total}`);
}
// Usage:
totalMarks('Alice', [85, 90, 78]);
totalMarks('Bob', [70, 88, 95]);
🎯 Ready to Test Yourself?🎯 准备好自测了吗?
Take the 15-question quiz covering all Day 4 theory topics!参加涵盖 Day 4 所有理论主题的 15 题测验!