Skip to content

Code Quality + Refactoring ​

Mở đầu

Code viết xong chạy được là OK? Bạn có thể viết code như sau: function OK, nhưng 2 tuần sau tự mình cũng không hiểu. Hoặc team có người nghỉ, để lại đống "chỉ chúa với họ hiểu" code.

Chương này: hiểu code tốt là gì, identify bad code, refactor an toàn.

Bạn sẽ học:

ChươngNội dung
1Code smells
2Refactoring techniques
3Code review
4Quality metrics

0. Toàn cảnh: code lifecycle ​

Software dev có 1 sự thật hay bị bỏ qua: code bị đọc nhiều hơn nhiều lần được viết.

Đời code

  • Write: dev viết version đầu, function chạy được, test pass
  • Review: team đọc, suggest improvement
  • Maintain: fix bug, add feature, adapt new req — chiếm 80%+ lifecycle
  • Refactor: code khó maintain → improve internal structure mà không đổi external behavior
  • Retire: tech iterate, code cũ replace

Martin Fowler trong "Refactoring": "Bất kỳ thằng ngốc nào cũng viết được code máy hiểu. Chỉ programmer tốt viết được code người hiểu."


1. Code smells ​

1.1 Code smell là gì? ​

"Code smell" (Kent Beck) = feature trong code, không phải bug, nhưng hint design issue sâu hơn. Như mùi lạ trong phòng — không bệnh ngay, nhưng cần clean.

代码坏味道识别器 ── 点击切换不同示例
问题代码
function processOrder(order) {
  // 验证订单... (20行)
  // 计算价格... (15行)
  // 检查库存... (10行)
  // 发送通知... (15行)
  // 更新数据库... (10行)
  // 生成报表... (10行)
  // 总计 80+ 行!
}

📏 过长函数

一个函数超过 50 行,做了太多事情,难以理解和测试。

改进建议:将大函数拆分为多个职责单一的小函数:validateOrder()、calculatePrice()、checkInventory() 等。

1.2 Common smells ​

SmellSymptomHại
Long functionFunction >50 dòngKhó hiểu, test, reuse
Magic numberCode viết 86400000 trực tiếpMeaning unclear, sửa hay sót
Duplicate codeLogic giống ở nhiều chỗSửa phải sync nhiều chỗ
Deep nesting>3 layer if/forLogic như mê cung
Long parameter listParam >4Call khó, dễ sai order
God class1 class/module làm nhiều việcTrách nhiệm không rõ, sửa 1 break nhiều

Core insight

Smell không phải "error", mà "signal". Cho biết: design ở đây có thể cần improve. Không phải mọi smell cần fix ngay, nhưng phải có khả năng identify.


2. Refactoring techniques ​

2.1 Refactoring là gì? ​

Definition chính xác: không đổi external behavior, improve internal structure.

Key: "không đổi external behavior". Refactor không phải rewrite, không add feature, không fix bug. Là "organize" code internal.

重构手法对比演示 ── 选择一种手法查看前后对比
Extract Function:将一段代码从大函数中提取出来,放入一个命名清晰的新函数中。
重构前
function printReport(invoice) {
  console.log("=== 账单 ===")
  // 计算总额
  let total = 0
  for (let item of invoice.items) {
    total += item.price * item.qty
  }
  console.log(`总计: ${total}`)
}
→
重构后
function printReport(invoice) {
  console.log("=== 账单 ===")
  const total = calcTotal(invoice.items)
  console.log(`总计: ${total}`)
}

function calcTotal(items) {
  return items.reduce(
    (s, i) => s + i.price * i.qty, 0
  )
}
要点:提炼函数是最常用的重构手法。好的函数名就是最好的注释——如果你需要写注释解释一段代码在做什么,那它就该被提炼成函数。

2.2 Common techniques ​

Extract function

Technique dùng nhất. Khi 1 đoạn code có thể tóm tắt bằng tên có nghĩa → extract thành function.

javascript
// Before
function printReport(data) {
  // Calc total
  let total = 0
  for (const item of data.items) {
    total += item.price * item.qty
  }
  // Print...
}

// After
function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price * item.qty, 0)
}

function printReport(data) {
  const total = calculateTotal(data.items)
  // Print...
}

Rename

Naming tốt = doc rẻ nhất + hiệu quả nhất. Khi cần comment giải thích variable/function = name không đủ tốt.

javascript
// Before
const d = new Date() - startTime
const arr = users.filter(u => u.a)

// After
const elapsedMs = new Date() - startTime
const activeUsers = users.filter(user => user.isActive)

Replace nested conditional với guard clauses

javascript
// Before
function getPayAmount(employee) {
  if (employee.isSeparated) {
    return { amount: 0 }
  } else {
    if (employee.isRetired) {
      return { amount: employee.pension }
    } else {
      return { amount: employee.salary }
    }
  }
}

// After
function getPayAmount(employee) {
  if (employee.isSeparated) return { amount: 0 }
  if (employee.isRetired) return { amount: employee.pension }
  return { amount: employee.salary }
}

Refactor safety net

Risk lớn nhất refactor = "sửa sửa sửa thành bug". Prerequisite refactor = test coverage. Mỗi small step refactor → run test, đảm bảo behavior không đổi. Code không test → bổ sung test trước → refactor sau.


3. Code review ​

3.1 Sao cần? ​

CR = 1 trong cách hiệu quả nhất đảm bảo quality. Giá trị không chỉ bug detection:

  • Knowledge share: team biết code nhau, giảm "bus factor"
  • Unify style: convention dần thành standard team
  • Phát hiện design issue sớm: khó fix hơn bug = bad architecture
  • Mutual learning: đọc code người khác = shortcut improve

3.2 Review gì? ​

DimFocus
CorrectnessLogic đúng? Edge case handle?
ReadabilityNaming rõ? Structure dễ hiểu?
SecurityInjection risk? Sensitive data expose?
PerformanceIssue rõ ràng? N+1 query?
TestCó test tương ứng? Cover critical path?

3.3 Etiquette ​

CR tốt = bàn về code, không phải critize người:

  • "Chúng ta" thay vì "bạn": "Bạn sai đây" → "Đây có thể guard clause"
  • Ask thay vì command: "Đổi const" → "Variable này sau sẽ reassign? Nếu không, const an toàn hơn"
  • Give reason: không chỉ "không tốt", mà "sao không tốt" + "thế nào tốt hơn"

4. Code quality metrics ​

4.1 Cyclomatic complexity ​

Cyclomatic complexity = số path độc lập trong code. Mỗi if, for, case, &&, || tăng complexity.

ComplexityEvaluationRecommend
1-10SimpleDễ hiểu + test
11-20MediumCân nhắc tách
21-50ComplexPhải refactor
50+UnmaintainableRefactor khẩn

4.2 Code coverage ​

TypeNote
Line coverage% code line được execute
Branch coverage% branch được execute

Coverage trap

80% coverage ≠ code tốt. Coverage chỉ cho biết "code nào không test", không cho biết "test có nghĩa không". Test expect(true).toBe(true) tăng coverage nhưng vô giá trị.

4.3 Practical tools ​

ToolUse
ESLintJS/TS static analysis
PrettierCode format, unify style
SonarQubeComprehensive quality platform
HuskyGit hooks, pre-commit check

5. AI assist code quality ​

LLM ở code quality cực practical, có thể làm "24/7 code reviewer".

5.1 Identify code smells ​

Prompt:

Review code, identify code smell, bao gồm:
long function, magic number, duplicate code, deep nesting, long param list.
Mỗi issue: location + description + improvement.

[paste code]

5.2 Auto refactor ​

Prompt:

Refactor code:
1. Không đổi external behavior
2. Dùng extract function, guard clause
3. Improve naming, loại magic number
4. Giải thích mỗi step refactor

[paste code]

5.3 Mock code review ​

Prompt:

Review code as senior dev, feedback từ:
- Correctness: logic có bug? Edge case?
- Readability: naming rõ? Structure dễ?
- Performance: issue rõ?
- Security: injection / data leak risk?
Tone "suggest" not "command", give improvement.

[paste code]

AI caveat

AI refactor suggestion phải self-verify — run test confirm behavior unchanged. Treat AI as "colleague suggesting", không "authority trust unconditionally".


6. Tổng kết ​

  1. Identify: smell code, biết chỗ cần improve
  2. Refactor: safe techniques, small step under test protection
  3. Collaborate: CR, team guard quality together
  4. Measure: objective metric track code health

Insight cuối

Code quality không one-time, mà ongoing habit. Như giữ phòng sạch — không phải đợi lộn xộn mới big clean, mà daily tidy. Boy Scout Rule: leave code cleaner than you found it.

2026 cho VN dev

  • Modern stack 2026:
    • ESLint flat config: format mới
    • Biome: thay ESLint + Prettier, faster (Rust)
    • Knip: tìm dead code TypeScript
    • CodeRabbit / Greptile: AI-powered code review
  • VN context:
    • Startup: ESLint + Prettier + Husky đủ
    • Enterprise: SonarQube + strict review process
  • AI-era:
    • Copilot, Cursor catch many bug + smell tự động
    • GPT-4 / Claude review PR efficient
    • Codium AI auto-gen test
  • Bài tập: configure ESLint + Prettier + Husky cho 1 project

Tài liệu ​