Skip to main content

Command Palette

Search for a command to run...

Syllabus software engineering (1)

Updated
36 min readView as Markdown

Tổng quan các giai đoạn

Giai đoạn Tên Số tuần Ngày Ghi chú
0 Foundations for OOP 5 1–35
1 Object Oriented Programming 9 36–98
2 Refactoring & Code Smells 4 99–126
3 Design Patterns 9 127–189
4 Testing & Quality Engineering 4 190–217
5 Concurrency 7 218–266
6 Networking & OS I/O 4 267–294
7 Domain Driven Design 8 295–350
8 Architecture Patterns 11 351–427
9 Security & API Design 4 428–455
10 Framework Internals 18 456–581
11 Database Internals 9 582–644
12 Distributed Systems 11 645–721
13 DevOps/Infra & Observability 6 722–763
14 Runtime Internals 20 764–903
15 Source Code Reading (sprint có cấu trúc) 8 904–959 Nên duy trì tiếp tục sau mốc này
16 System Design Practice 6 960–1001
17 Framework Engineering (Capstone) 14 1002–1099

Giai đoạn 0 - Foundations for OOP (Ngày 1–35)

Mục tiêu chung: hiểu những thứ OOP đang che giấu bên dưới - phần cứng, bộ nhớ, cách hàm được gọi.

Nhóm 1: Computer Architecture (Ngày 1–7)

Ngày 1: CPU & Chu kỳ thực thi lệnh

  • Mục tiêu: Hiểu CPU thực thi một lệnh máy như thế nào.

  • Lý thuyết: Fetch–Decode–Execute cycle, Instruction Set, ALU, Control Unit.

  • Thực hành: Viết pseudo-trace cho 1 đoạn C đơn giản, mô tả từng bước CPU xử lý.

Ngày 2: Cache (L1/L2/L3)

  • Mục tiêu: Hiểu vì sao cache tồn tại và ảnh hưởng đến performance.

  • Lý thuyết: Cache line, cache hit/miss, spatial vs temporal locality.

  • Thực hành: Viết 2 vòng lặp duyệt mảng 2D theo row-major và column-major, đo thời gian chạy khác nhau.

Ngày 3: Register & Memory Hierarchy

  • Mục tiêu: Nắm được thứ bậc tốc độ Register → Cache → RAM → Disk.

  • Lý thuyết: Register file, độ trễ truy cập từng tầng, nguyên lý đánh đổi tốc độ/dung lượng.

  • Thực hành: Vẽ sơ đồ memory hierarchy kèm số liệu latency thực tế (ns) cho từng tầng.

Ngày 4: Virtual Memory

  • Mục tiêu: Hiểu vì sao mỗi process "thấy" toàn bộ không gian địa chỉ riêng.

  • Lý thuyết: Paging, Page Table, TLB, Page Fault.

  • Thực hành: Dùng /proc/[pid]/maps (Linux) xem address space của một chương trình C đang chạy.

Ngày 5: Context Switch & Process vs Thread

  • Mục tiêu: Phân biệt process và thread ở tầng OS.

  • Lý thuyết: Process Control Block, thread stack riêng - heap chung, chi phí context switch.

  • Thực hành: Viết chương trình đo thời gian context switch bằng cách tạo nhiều thread/process.

Ngày 6: Lab tổng hợp Computer Architecture

  • Mục tiêu: Thấy tác động thực tế của cache/memory lên hiệu năng code.

  • Lý thuyết: Ôn lại cache miss, false sharing.

  • Thực hành: Benchmark một hàm xử lý mảng lớn trước/sau khi tối ưu locality, ghi lại số liệu.

Ngày 7: Review & Quiz Computer Architecture

  • Mục tiêu: Củng cố kiến thức tuần 1.

  • Lý thuyết: Tự tổng hợp lại bằng sơ đồ tư duy (CPU – Cache – Register – Memory – Context switch).

  • Thực hành: Tự đặt và trả lời 10 câu hỏi giải thích "tại sao" (không phải "là gì").

Nhóm 2: Data Structures - tự cài đặt bằng C++ (Ngày 8–17)

Ngày 8: Dynamic Array - Lý thuyết & khởi tạo

  • Mục tiêu: Hiểu cơ chế mảng động hoạt động bên dưới std::vector.

  • Lý thuyết: Contiguous memory, capacity vs size.

  • Thực hành: Khởi tạo class DynamicArray<T> với constructor cấp phát bộ nhớ thô.

Ngày 9: Dynamic Array - Resize & Amortized Complexity

  • Mục tiêu: Hiểu vì sao push_back là O(1) amortized.

  • Lý thuyết: Growth factor (x1.5 vs x2), amortized analysis.

  • Thực hành: Cài push_back với resize, in ra số lần cấp phát lại khi thêm 10,000 phần tử.

Ngày 10: Singly Linked List

  • Mục tiêu: Cài đặt cấu trúc con trỏ nối tiếp cơ bản.

  • Lý thuyết: Node, head/tail pointer, trade-off vs array.

  • Thực hành: Cài insert đầu/cuối, delete, traverse cho Singly Linked List.

Ngày 11: Doubly Linked List

  • Mục tiêu: Mở rộng thêm khả năng duyệt ngược.

  • Lý thuyết: Prev/next pointer, chi phí bộ nhớ tăng thêm.

  • Thực hành: Cài Doubly Linked List, so sánh chi phí insert/delete giữa vị trí đầu/giữa/cuối với Singly.

Ngày 12: Stack

  • Mục tiêu: Hiểu 2 cách cài Stack và ưu nhược điểm.

  • Lý thuyết: LIFO, array-based vs linked-based stack.

  • Thực hành: Cài Stack<T> bằng cả 2 cách, viết test push/pop/peek.

Ngày 13: Queue

  • Mục tiêu: Cài Queue hiệu quả bằng circular buffer.

  • Lý thuyết: FIFO, circular buffer, vấn đề "wasted space" của queue mảng thường.

  • Thực hành: Cài CircularQueue<T> với enqueue/dequeue O(1).

Ngày 14: Hash Table - Collision Resolution

  • Mục tiêu: Hiểu 2 chiến lược xử lý va chạm hash.

  • Lý thuyết: Separate chaining vs open addressing (linear/quadratic probing).

  • Thực hành: Cài HashMap<K,V> bằng separate chaining.

Ngày 15: Hash Table - Load Factor & Resize

  • Mục tiêu: Hiểu khi nào và tại sao hash table cần resize.

  • Lý thuyết: Load factor, rehashing, hàm hash tốt vs xấu.

  • Thực hành: Thêm cơ chế auto-resize khi load factor > 0.75, benchmark trước/sau.

Ngày 16: Binary Search Tree

  • Mục tiêu: Cài đặt cấu trúc cây tìm kiếm nhị phân cơ bản.

  • Lý thuyết: BST property, insert/delete/search, traversal (in-order, pre-order, post-order).

  • Thực hành: Cài BST<T> đầy đủ insert/delete/search + in-order traversal.

Ngày 17: Heap (Binary Heap)

  • Mục tiêu: Hiểu cấu trúc dùng cho priority queue.

  • Lý thuyết: Min-heap/max-heap, heapify up/down, array representation của heap.

  • Thực hành: Cài MinHeap<T> với insert và extract-min.

Nhóm 3: Memory Model - So sánh C++/Java/Python (Ngày 18–24)

Ngày 18: C++ - Stack vs Heap

  • Mục tiêu: Phân biệt rõ vùng nhớ stack và heap trong C++.

  • Lý thuyết: Lifetime, new/delete, con trỏ vs giá trị.

  • Thực hành: Viết chương trình in địa chỉ biến stack và biến heap, quan sát khác biệt.

Ngày 19: C++ - RAII

  • Mục tiêu: Hiểu nguyên lý quản lý tài nguyên gắn với lifetime object.

  • Lý thuyết: RAII, destructor tự động, vì sao C++ không cần GC.

  • Thực hành: Viết một class FileGuard tự đóng file trong destructor.

Ngày 20: Java - Heap, Stack & Object Allocation

  • Mục tiêu: Hiểu Java quản lý object khác C++ thế nào.

  • Lý thuyết: Mọi object nằm trên heap, stack chỉ chứa reference & primitive.

  • Thực hành: Dùng JVM flag in ra thông tin heap khi chạy 1 chương trình Java đơn giản.

Ngày 21: Java - Garbage Collector tổng quan

  • Mục tiêu: Hiểu ý tưởng generational GC.

  • Lý thuyết: Young/Old generation, Minor GC vs Major GC, GC roots.

  • Thực hành: Bật GC log, quan sát các lần GC chạy khi tạo nhiều object tạm.

Ngày 22: Python - Object Reference & Reference Counting

  • Mục tiêu: Hiểu mô hình biến trong Python là reference, không phải giá trị.

  • Lý thuyết: Mọi thứ là object, refcount tăng/giảm khi gán/xóa biến.

  • Thực hành: Dùng sys.getrefcount() quan sát refcount thay đổi qua các thao tác gán.

Ngày 23: Python - Garbage Collector (Cycle Detector)

  • Mục tiêu: Hiểu vì sao refcounting không đủ, cần thêm cycle collector.

  • Lý thuyết: Reference cycle, generational GC của CPython, gc module.

  • Thực hành: Tạo 1 cycle tham chiếu vòng, quan sát gc.collect() dọn nó.

Ngày 24: Tổng hợp so sánh 3 memory model

  • Mục tiêu: Có bảng so sánh rõ ràng để dùng về sau.

  • Lý thuyết: Tự lập bảng: cơ chế cấp phát, cơ chế giải phóng, ai chịu trách nhiệm, chi phí.

  • Thực hành: Viết cùng 1 bài toán (linked list có cycle) bằng cả 3 ngôn ngữ, so sánh cách mỗi ngôn ngữ xử lý bộ nhớ.

Nhóm 4: Function Call Internals (Ngày 25–29)

Ngày 25: Call Stack & Stack Frame

  • Mục tiêu: Hiểu cấu trúc 1 stack frame khi gọi hàm.

  • Lý thuyết: Return address, saved registers, local variables, stack pointer/base pointer.

  • Thực hành: Vẽ sơ đồ stack frame cho 1 hàm C có tham số và biến local.

Ngày 26: Recursion & Stack Depth

  • Mục tiêu: Hiểu giới hạn thực tế của đệ quy.

  • Lý thuyết: Stack overflow, tail call, vì sao không phải ngôn ngữ nào cũng tối ưu tail call.

  • Thực hành: Viết hàm đệ quy tính giai thừa, tìm độ sâu tối đa trước khi stack overflow.

Ngày 27: Calling Convention

  • Mục tiêu: Hiểu quy ước truyền tham số ở tầng thấp.

  • Lý thuyết: cdecl, stdcall, System V AMD64 ABI (truyền qua register vs stack).

  • Thực hành: Đọc tài liệu System V ABI, tóm tắt cách 6 tham số đầu được truyền qua register nào.

Ngày 28: Nhìn Function Call ở tầng Assembly

  • Mục tiêu: Thấy tận mắt lời gọi hàm biến thành assembly.

  • Lý thuyết: call/ret instruction, push/pop cho stack frame.

  • Thực hành: Dùng objdump -d hoặc gdb disassemble một hàm C đơn giản, chỉ ra đoạn prologue/epilogue.

Ngày 29: Ôn tập Function Call Internals

  • Mục tiêu: Củng cố nhóm kiến thức tuần.

  • Lý thuyết: Tổng hợp lại toàn bộ pipeline: gọi hàm → tạo stack frame → thực thi → return → dọn stack frame.

  • Thực hành: Tự vẽ full diagram từ lúc gọi hàm đến khi return, áp cho ví dụ đệ quy 2 tầng.

Nhóm 5: Project - Tự viết vector/hashmap/linked_list (Ngày 30–35)

Ngày 30: Setup Project & Vector Skeleton

  • Mục tiêu: Khởi động project tổng hợp, thiết kế API cho vector<T>.

  • Lý thuyết: Thiết kế interface trước khi implement (push_back, size, operator[], iterator).

  • Thực hành: Tạo repo, viết header vector.hpp với skeleton class + test framework cơ bản (catch2 hoặc tự viết assert).

Ngày 31: Hoàn thiện Vector

  • Mục tiêu: Vector chạy đúng và hiệu năng chấp nhận được.

  • Lý thuyết: Copy constructor, move semantics, iterator invalidation.

  • Thực hành: Hoàn thiện push_back, resize, iterator; viết test so sánh hành vi với std::vector.

Ngày 32: Viết HashMap

  • Mục tiêu: Áp dụng kiến thức Ngày 14–15 vào 1 implementation hoàn chỉnh.

  • Lý thuyết: Chọn hash function, thiết kế bucket array.

  • Thực hành: Viết hashmap.hpp với insert/get/erase cơ bản.

Ngày 33: Hoàn thiện HashMap

  • Mục tiêu: Xử lý các edge case còn thiếu.

  • Lý thuyết: Xử lý collision khi bucket đầy, resize khi load factor cao.

  • Thực hành: Thêm auto-resize + test với 100,000 key ngẫu nhiên, đo thời gian insert/lookup.

Ngày 34: Viết Linked List

  • Mục tiêu: Hoàn thiện thành phần thứ 3 của project.

  • Lý thuyết: Ôn lại thiết kế node-based structure, chọn singly hay doubly cho project này.

  • Thực hành: Viết linked_list.hpp với insert/delete tại vị trí bất kỳ, iterator hỗ trợ range-based for.

Ngày 35: Test & Benchmark tổng kết Giai đoạn 0

  • Mục tiêu: Đánh giá lại toàn bộ 3 cấu trúc dữ liệu đã viết.

  • Lý thuyết: Big-O thực tế vs lý thuyết, ảnh hưởng của cache locality lên kết quả benchmark.

  • Thực hành: Viết benchmark suite so sánh vector/hashmap/linked_list tự viết với thư viện chuẩn (std::vector, std::unordered_map, std::list), ghi báo cáo kết quả và giải thích chênh lệch.

Giai đoạn 1 - Object Oriented Programming (Ngày 36–98)

Module 1: Object Model (Ngày 36–40)

Ngày 36: Class, Object, Instance

  • Mục tiêu: Phân biệt rạch ròi 3 khái niệm hay bị dùng lẫn lộn.

  • Lý thuyết: Class là blueprint, Object là thực thể trong bộ nhớ, Instance là quan hệ giữa object và class nó thuộc về.

  • Thực hành: Viết 1 class Car bằng cả Java/C++/Python, tạo 3 instance, in địa chỉ/id để thấy chúng là các object riêng biệt.

Ngày 37: State & Behavior

  • Mục tiêu: Thiết kế class tách bạch trạng thái và hành vi hợp lý.

  • Lý thuyết: State (fields/attributes) mô tả dữ liệu, Behavior (methods) mô tả hành vi tác động lên state.

  • Thực hành: Thiết kế class TrafficLight với state (màu hiện tại) và behavior (chuyển màu theo quy tắc).

Ngày 38: Java Object Model

  • Mục tiêu: Hiểu mọi thứ trong Java đều kế thừa từ Object.

  • Lý thuyết: Reference type, Object class (equals, hashCode, toString), object luôn nằm trên heap.

  • Thực hành: Override equals/hashCode/toString cho class Car, giải thích vì sao cần override đồng thời cả 2 hàm đầu.

Ngày 39: C++ Object Model

  • Mục tiêu: Hiểu C++ có value semantics, khác Java/Python.

  • Lý thuyết: Object có thể nằm trên stack hoặc heap, copy semantics mặc định, không có "mọi thứ kế thừa 1 root class".

  • Thực hành: Viết ví dụ minh hoạ copy-by-value khi truyền object C++ vào hàm, so với truyền reference (Java) cho cùng logic.

Ngày 40: Python Object Model & So sánh tổng hợp

  • Mục tiêu: Hiểu "everything is an object" trong Python, kể cả class.

  • Lý thuyết: Class cũng là instance của type, mọi biến là reference tới object.

  • Thực hành: Lập bảng so sánh Object Model Java vs C++ vs Python (nơi lưu trữ, semantics khi gán, root class).

Module 2: Encapsulation (Ngày 41–46)

Ngày 41: Access Control

  • Mục tiêu: Hiểu cơ chế kiểm soát truy cập ở 3 ngôn ngữ.

  • Lý thuyết: public/private/protected (Java, C++) vs quy ước _/__ (Python - "consenting adults").

  • Thực hành: Viết cùng 1 class với field private, thử truy cập trái phép để thấy compiler/runtime phản ứng khác nhau.

Ngày 42: Invariants

  • Mục tiêu: Hiểu vì sao encapsulation tồn tại là để bảo vệ invariant.

  • Lý thuyết: Invariant là điều kiện luôn đúng trong suốt vòng đời object; setter/method phải giữ invariant đó.

  • Thực hành: Liệt kê invariant cho 1 class Temperature (ví dụ: không dưới -273.15°C), viết validate trong setter.

Ngày 43: Information Hiding

  • Mục tiêu: Hiểu lợi ích của việc giấu chi tiết implementation.

  • Lý thuyết: Giảm coupling, cho phép thay đổi implementation mà không phá vỡ client code.

  • Thực hành: Refactor 1 class đang expose field trực tiếp thành encapsulated, đổi implementation bên trong mà không đổi API.

Ngày 44: Lab - BankAccount

  • Mục tiêu: Áp dụng encapsulation vào bài toán tài chính có invariant chặt.

  • Lý thuyết: Invariant "số dư không âm", "giao dịch phải atomic".

  • Thực hành: Viết class BankAccount với deposit/withdraw đảm bảo invariant, viết test cho trường hợp withdraw quá số dư.

Ngày 45: Lab - Wallet

  • Mục tiêu: Thực hành composition + encapsulation.

  • Lý thuyết: Wallet chứa nhiều BankAccount, quản lý qua interface thống nhất.

  • Thực hành: Viết class Wallet chứa list BankAccount, thêm method tổng số dư, chuyển tiền giữa 2 account trong cùng wallet.

Ngày 46: Lab - Money (Value Object)

  • Mục tiêu: Làm quen với khái niệm value object (sẽ gặp lại ở DDD).

  • Lý thuyết: Value object bất biến (immutable), so sánh bằng giá trị chứ không bằng identity.

  • Thực hành: Viết class Money (amount + currency) immutable, override equals theo giá trị, không cho phép cộng 2 currency khác nhau.

Module 3: Constructors & Lifecycle (Ngày 47–54)

Ngày 47: Java Constructor

  • Mục tiêu: Hiểu constructor overloading và constructor chaining.

  • Lý thuyết: Nhiều constructor cùng class, this(...) gọi constructor khác.

  • Thực hành: Viết class Rectangle với 3 constructor overload (không tham số, 1 tham số cho hình vuông, 2 tham số).

Ngày 48: Java Lifecycle & GC liên hệ

  • Mục tiêu: Hiểu object Java "chết" như thế nào (không có destructor tường minh).

  • Lý thuyết: Không còn reference trỏ tới → eligible for GC; finalize() đã deprecated, vì sao nên tránh.

  • Thực hành: Viết ví dụ object mất hết reference, dùng -Xlog:gc quan sát khi nó được thu hồi.

Ngày 49: C++ Constructor

  • Mục tiêu: Nắm các loại constructor trong C++.

  • Lý thuyết: Default constructor, parameterized constructor, copy constructor.

  • Thực hành: Viết class Point với đủ 3 loại constructor, trace khi nào mỗi loại được gọi.

Ngày 50: C++ Destructor & RAII Lifecycle

  • Mục tiêu: Hiểu vòng đời object C++ gắn liền với scope.

  • Lý thuyết: Destructor gọi tự động khi object ra khỏi scope, RAII cho resource management.

  • Thực hành: Viết class ScopedTimer in ra thời gian sống khi destructor được gọi.

Ngày 51: C++ Rule of Three/Five

  • Mục tiêu: Hiểu vì sao cần định nghĩa đồng thời copy constructor, copy assignment, destructor (và move variants).

  • Lý thuyết: Rule of Three (C++98), Rule of Five (C++11 thêm move constructor/move assignment).

  • Thực hành: Viết class quản lý raw pointer, cố tình bỏ qua Rule of Three để thấy lỗi double-free, sau đó sửa đúng.

Ngày 52: Python new vs init

  • Mục tiêu: Phân biệt 2 bước tạo object trong Python.

  • Lý thuyết: __new__ tạo instance (allocate), __init__ khởi tạo state (configure) trên instance đã tồn tại.

  • Thực hành: Override __new__ để implement Singleton pattern đơn giản, giải thích vì sao không nên dùng __init__ cho việc này.

Ngày 53: Python del

  • Mục tiêu: Hiểu finalizer trong Python và các cạm bẫy.

  • Lý thuyết: __del__ không đảm bảo thời điểm gọi (phụ thuộc GC), không nên dùng cho resource cleanup quan trọng - dùng context manager thay thế.

  • Thực hành: So sánh dọn resource bằng __del__ vs bằng with + __enter__/__exit__.

Ngày 54: So sánh Lifecycle 3 ngôn ngữ

  • Mục tiêu: Tổng hợp toàn bộ Module 3.

  • Lý thuyết: Lập bảng: thời điểm tạo, thời điểm huỷ, ai kiểm soát, cơ chế dọn resource.

  • Thực hành: Làm quiz tự đặt 10 câu hỏi tình huống (VD: "Object này bị leak ở ngôn ngữ nào, tại sao?").

Module 4: Inheritance (Ngày 55–60)

Ngày 55: IS-A Relationship

  • Mục tiêu: Hiểu khi nào quan hệ kế thừa thực sự hợp lý.

  • Lý thuyết: Liskov Substitution Principle sơ khởi - subclass phải thay thế được superclass mà không phá vỡ hành vi.

  • Thực hành: Đánh giá 3 ví dụ quan hệ (Square-Rectangle, Dog-Animal, Circle-Ellipse), chỉ ra ví dụ nào IS-A giả.

Ngày 56: Reuse qua Inheritance

  • Mục tiêu: Hiểu lợi ích tái sử dụng code qua kế thừa, và giới hạn của nó.

  • Lý thuyết: Code reuse vs coupling chặt giữa base và derived class.

  • Thực hành: Viết 1 hierarchy 2 tầng (ShapeCircle/Square) chia sẻ logic chung ở base class.

Ngày 57: Polymorphism qua Inheritance (preview)

  • Mục tiêu: Thấy trước lợi ích lớn nhất của inheritance là polymorphism.

  • Lý thuyết: Base class reference có thể trỏ tới derived object, gọi method đúng phiên bản derived.

  • Thực hành: Viết hàm printArea(Shape s) nhận bất kỳ subclass nào của Shape.

Ngày 58: Anti-pattern - Fragile Base Class

  • Mục tiêu: Nhận diện vấn đề khi sửa base class làm vỡ subclass.

  • Lý thuyết: Fragile Base Class Problem - thay đổi tưởng chừng vô hại ở base phá vỡ hành vi ở derived.

  • Thực hành: Tạo ví dụ minh hoạ: sửa 1 method ở base class làm subclass hoạt động sai, phân tích nguyên nhân.

Ngày 59: Anti-pattern - Deep Inheritance Hierarchy

  • Mục tiêu: Nhận diện vấn đề khi hierarchy quá sâu.

  • Lý thuyết: Khó hiểu, khó test, khó thay đổi khi hierarchy có 5-6 tầng.

  • Thực hành: Vẽ sơ đồ 1 hierarchy 5 tầng giả định, chỉ ra vấn đề khi cần thêm behavior mới ở tầng giữa.

Ngày 60: Lab - Refactor Inheritance sai thành đúng

  • Mục tiêu: Áp dụng kiến thức cả tuần vào 1 case thực tế.

  • Lý thuyết: Ôn lại Liskov Substitution Principle.

  • Thực hành: Lấy ví dụ Square kế thừa Rectangle (vi phạm LSP), refactor lại thiết kế đúng.

Module 5: Polymorphism (Ngày 61–66)

Ngày 61: Dynamic Dispatch

  • Mục tiêu: Hiểu cơ chế chọn đúng phiên bản method lúc runtime.

  • Lý thuyết: Dynamic dispatch vs static dispatch, tại sao polymorphism cần dynamic dispatch.

  • Thực hành: Viết ví dụ 3 class kế thừa cùng override 1 method, gọi qua base reference, quan sát method nào thực thi.

Ngày 62: Late Binding vs Early Binding

  • Mục tiêu: Phân biệt thời điểm quyết định method nào được gọi.

  • Lý thuyết: Early binding (compile-time, VD: overloading) vs Late binding (runtime, VD: overriding).

  • Thực hành: Viết ví dụ minh hoạ cả 2 loại binding trong cùng 1 class, chỉ rõ cái nào xảy ra lúc nào.

Ngày 63: Runtime Polymorphism trong Java

  • Mục tiêu: Hiểu Java mặc định virtual (trừ static/final/private).

  • Lý thuyết: Mọi method instance trong Java là virtual by default.

  • Thực hành: Viết ví dụ override method, thử đánh dấu final để thấy compiler chặn override.

Ngày 64: Runtime Polymorphism trong C++

  • Mục tiêu: Hiểu C++ cần khai báo virtual tường minh.

  • Lý thuyết: Không có virtual → static binding (khác Java); vtable sẽ học sâu ở Module 8.

  • Thực hành: Viết ví dụ base class không có virtual, gọi qua pointer, so sánh kết quả khi thêm virtual.

Ngày 65: Duck Typing trong Python

  • Mục tiêu: Hiểu polymorphism không cần inheritance trong Python.

  • Lý thuyết: "If it walks like a duck and quacks like a duck..." - chỉ cần có đúng method là dùng được.

  • Thực hành: Viết hàm nhận bất kỳ object nào có method .quack(), không cần base class chung.

Ngày 66: Lab - Payment Gateway

  • Mục tiêu: Áp dụng polymorphism vào bài toán thực tế.

  • Lý thuyết: Ôn lại toàn bộ Module 5.

  • Thực hành: Thiết kế PaymentMethod (abstract) với CreditCard/Paypal/BankTransfer, viết hàm xử lý thanh toán generic qua interface chung.

Module 6: Abstraction (Ngày 67–72)

Ngày 67: Interface vs Abstract Class

  • Mục tiêu: Phân biệt 2 công cụ abstraction chính.

  • Lý thuyết: Interface = pure contract (không implementation), Abstract class = contract + có thể có implementation chung.

  • Thực hành: Lập bảng khi nào dùng interface, khi nào dùng abstract class.

Ngày 68: Interface trong Java

  • Mục tiêu: Thực hành interface Java, bao gồm default method.

  • Lý thuyết: interface keyword, multiple interface implementation, default method (Java 8+).

  • Thực hành: Viết interface Drivable với default method, 2 class implement.

Ngày 69: Abstract Class trong C++

  • Mục tiêu: Thực hành pure virtual function.

  • Lý thuyết: virtual ... = 0, abstract class không thể instantiate.

  • Thực hành: Viết abstract class Shape với pure virtual area(), 2 class con implement.

Ngày 70: Duck Typing / Protocol trong Python

  • Mục tiêu: Hiểu cách Python formalize abstraction qua abc module.

  • Lý thuyết: ABC, @abstractmethod, Protocol (structural typing, PEP 544).

  • Thực hành: Viết abstract base class bằng ABC, so sánh với dùng Protocol (không cần kế thừa).

Ngày 71: Contract - Design by Contract

  • Mục tiêu: Hiểu khái niệm hợp đồng giữa method và caller.

  • Lý thuyết: Precondition, postcondition, class invariant (Bertrand Meyer's Design by Contract).

  • Thực hành: Viết precondition/postcondition dạng assertion cho 1 method withdraw(amount).

Ngày 72: Lab - Storage Abstraction

  • Mục tiêu: Áp dụng abstraction vào bài toán thực tế thường gặp production.

  • Lý thuyết: Ôn lại Module 6.

  • Thực hành: Thiết kế interface Storage với S3/Local/GCS implementation, viết code client không phụ thuộc implementation cụ thể.

Module 7: Composition (Ngày 73–77)

Ngày 73: HAS-A Relationship

  • Mục tiêu: Hiểu quan hệ "chứa" khác với "là" (inheritance) thế nào.

  • Lý thuyết: Composition = object này chứa object khác như 1 field.

  • Thực hành: Viết ví dụ Car HAS-A Engine, so sánh với thiết kế sai Car IS-A Engine.

Ngày 74: Delegation

  • Mục tiêu: Hiểu cách object A "nhờ" object B thực hiện hành vi.

  • Lý thuyết: Delegation pattern, forwarding method calls.

  • Thực hành: Viết class Car delegate method start() cho Engine.start().

Ngày 75: Composition over Inheritance

  • Mục tiêu: Hiểu nguyên lý thiết kế nổi tiếng này thực sự nghĩa là gì.

  • Lý thuyết: Composition linh hoạt hơn, tránh Fragile Base Class, dễ thay đổi hành vi lúc runtime.

  • Thực hành: So sánh 2 thiết kế cho cùng bài toán (VD: Character trong game) - 1 bản dùng inheritance sâu, 1 bản dùng composition.

Ngày 76: Refactor Inheritance Tree → Composition

  • Mục tiêu: Thực hành refactor thực tế.

  • Lý thuyết: Ôn lại kỹ thuật Extract Interface, Replace Inheritance with Delegation.

  • Thực hành: Lấy hierarchy BirdFlyingBird/SwimmingBird/Penguin (vốn có vấn đề), refactor sang composition dùng FlyBehavior/SwimBehavior.

Ngày 77: Lab hoàn thiện Composition

  • Mục tiêu: Chốt lại Module 7 bằng review.

  • Lý thuyết: Tổng hợp lại khi nào composition thắng inheritance, khi nào không.

  • Thực hành: Viết report ngắn (1 trang) so sánh ưu nhược 2 cách tiếp cận dựa trên các lab đã làm.

Module 8: Object Internals (Ngày 78–86)

Ngày 78: C++ vtable

  • Mục tiêu: Hiểu cơ chế bảng ảo đứng sau virtual function.

  • Lý thuyết: Virtual table (vtable) là mảng con trỏ hàm, mỗi class có polymorphic behavior sẽ có 1 vtable riêng.

  • Thực hành: Vẽ sơ đồ vtable cho 1 hierarchy 2 tầng có override.

Ngày 79: C++ vptr & Object Layout

  • Mục tiêu: Hiểu object polymorphic có thêm 1 con trỏ ẩn.

  • Lý thuyết: vptr (virtual pointer) nằm đầu object, trỏ tới vtable của class thực sự.

  • Thực hành: Dùng sizeof() so sánh kích thước object có và không có virtual function, giải thích chênh lệch.

Ngày 80: C++ Multiple Inheritance & vtable phức tạp

  • Mục tiêu: Hiểu vtable trở nên phức tạp thế nào khi đa kế thừa.

  • Lý thuyết: Nhiều vptr trong 1 object, vấn đề diamond inheritance.

  • Thực hành: Viết ví dụ diamond inheritance với virtual base class, giải thích cách C++ giải quyết bằng virtual inheritance.

Ngày 81: Java invokevirtual

  • Mục tiêu: Hiểu bytecode Java thực hiện dynamic dispatch ra sao.

  • Lý thuyết: JVM bytecode instruction invokevirtual - lookup method table dựa trên runtime class.

  • Thực hành: Compile 1 class Java đơn giản, dùng javap -c xem bytecode, tìm instruction invokevirtual.

Ngày 82: Java invokeinterface

  • Mục tiêu: Hiểu vì sao gọi qua interface cần instruction riêng.

  • Lý thuyết: invokeinterface khác invokevirtual vì lookup phức tạp hơn (object có thể implement nhiều interface).

  • Thực hành: Viết ví dụ gọi method qua interface reference, dùng javap -c so sánh bytecode với gọi qua class reference.

Ngày 83: Java Method Dispatch Table

  • Mục tiêu: Hiểu JVM tổ chức method table tương đương vtable ra sao.

  • Lý thuyết: Method table trong class metadata của JVM, so sánh khái niệm với vtable C++.

  • Thực hành: Lập bảng so sánh cơ chế dispatch Java vs C++ (điểm giống và khác).

Ngày 84: Python MRO

  • Mục tiêu: Hiểu Python giải quyết đa kế thừa bằng thuật toán tuyến tính hoá.

  • Lý thuyết: Method Resolution Order, thuật toán C3 linearization.

  • Thực hành: Viết 1 ví dụ đa kế thừa (diamond) trong Python, in ClassName.__mro__, giải thích thứ tự.

Ngày 85: Python Descriptor Protocol

  • Mục tiêu: Hiểu cơ chế đứng sau property, method binding.

  • Lý thuyết: __get__/__set__/__delete__, descriptor là nền tảng của property, staticmethod, classmethod.

  • Thực hành: Tự viết 1 descriptor đơn giản validate giá trị khi gán (tương tự property có validation).

Ngày 86: Tổng hợp Object Internals

  • Mục tiêu: Chốt lại toàn bộ Module 8.

  • Lý thuyết: So sánh 3 cơ chế dispatch: vtable (C++) vs method table (JVM) vs MRO + descriptor (Python).

  • Thực hành: Viết bài tổng hợp (dạng bảng) so sánh chi phí runtime của mỗi cơ chế dispatch.

Project: Plugin System (Ngày 87–98)

Ngày 87: Thiết kế kiến trúc Plugin System

  • Mục tiêu: Lên thiết kế tổng thể trước khi code.

  • Lý thuyết: Plugin architecture cần: contract (interface), discovery mechanism, lifecycle management.

  • Thực hành: Vẽ sơ đồ kiến trúc Plugin System sẽ xây (chọn 1 ngôn ngữ chính, khuyến nghị Java hoặc Python).

Ngày 88: Định nghĩa Plugin Interface

  • Mục tiêu: Thiết kế contract chuẩn cho mọi plugin.

  • Lý thuyết: Interface tối thiểu cần có (VD: name(), execute(), init(config)).

  • Thực hành: Viết interface/abstract class Plugin.

Ngày 89: Plugin Registry

  • Mục tiêu: Xây nơi lưu trữ và tra cứu plugin đã đăng ký.

  • Lý thuyết: Registry pattern - trung tâm quản lý các instance plugin.

  • Thực hành: Viết class PluginRegistry với register()/get()/getAll().

Ngày 90: Plugin Loader - Load động

  • Mục tiêu: Load plugin không cần hard-code trong source.

  • Lý thuyết: Java dùng reflection (Class.forName), Python dùng importlib, C++ dùng dlopen.

  • Thực hành: Viết PluginLoader load class plugin từ tên string cấu hình, khởi tạo qua reflection/importlib.

Ngày 91: Plugin mẫu 1 - Logging Plugin

  • Mục tiêu: Có plugin thực tế đầu tiên chạy qua hệ thống.

  • Lý thuyết: Ôn lại interface đã định nghĩa Ngày 88.

  • Thực hành: Viết LoggingPlugin implement interface, đăng ký và chạy qua registry.

Ngày 92: Plugin mẫu 2 - Validation Plugin

  • Mục tiêu: Thêm plugin thứ 2 để kiểm tra tính mở rộng.

  • Lý thuyết: Đảm bảo thêm plugin mới không cần sửa code core.

  • Thực hành: Viết ValidationPlugin, verify Open/Closed Principle được giữ vững.

Ngày 93: Plugin mẫu 3 - Notification Plugin

  • Mục tiêu: Có đủ 3 plugin để test hệ thống chạy nhiều plugin cùng lúc.

  • Lý thuyết: Thứ tự thực thi plugin, có cần priority không.

  • Thực hành: Viết NotificationPlugin, chạy pipeline cả 3 plugin tuần tự.

Ngày 94: Plugin Lifecycle

  • Mục tiêu: Thêm quản lý vòng đời cho plugin.

  • Lý thuyết: init → start → stop, tương tự lifecycle của framework thật (Spring bean lifecycle sẽ gặp lại sau).

  • Thực hành: Thêm method init()/start()/stop() vào interface, cập nhật cả 3 plugin mẫu.

Ngày 95: Plugin Configuration

  • Mục tiêu: Cho phép mỗi plugin có config riêng.

  • Lý thuyết: Configuration injection - mỗi plugin nhận 1 config object/map lúc init.

  • Thực hành: Thêm file config (JSON/YAML) chứa cấu hình riêng từng plugin, load và inject vào init().

Ngày 96: Error Handling & Isolation

  • Mục tiêu: Đảm bảo 1 plugin lỗi không kéo sập cả hệ thống.

  • Lý thuyết: Fault isolation, try/catch quanh từng plugin execution, logging lỗi riêng biệt.

  • Thực hành: Cố tình viết 1 plugin lỗi (throw exception), verify hệ thống vẫn chạy tiếp các plugin khác.

Ngày 97: Test toàn bộ Plugin System

  • Mục tiêu: Đảm bảo hệ thống hoạt động đúng ở nhiều kịch bản.

  • Lý thuyết: Ôn lại toàn bộ thiết kế đã xây.

  • Thực hành: Viết test suite: load nhiều plugin, plugin lỗi, plugin config sai, thứ tự thực thi.

Ngày 98: Review & Retrospective Giai đoạn 1

  • Mục tiêu: Tổng kết toàn bộ giai đoạn OOP.

  • Lý thuyết: Nhìn lại 8 module đã học, liên hệ chúng với Plugin System vừa xây (module nào được dùng ở đâu).

  • Thực hành: Viết báo cáo retrospective: những gì khó nhất, những gì áp dụng được ngay vào công việc hiện tại.

Giai đoạn 2 - Refactoring & Code Smells (Ngày 99–126)

Tài liệu chính: Refactoring (Martin Fowler). Mục tiêu: nhìn ra code "xấu" và có kỹ thuật sửa nó an toàn, có hệ thống - không phải sửa cảm tính.

Nhóm 1: Code Smells (Ngày 99–108)

Ngày 99: Giới thiệu Code Smells

  • Mục tiêu: Hiểu khái niệm code smell và vì sao nó quan trọng hơn "code sai".

  • Lý thuyết: Code smell không phải bug - là dấu hiệu cảnh báo thiết kế có vấn đề, dễ dẫn tới bug/khó bảo trì về sau.

  • Thực hành: Đọc lại 1 đoạn code cũ của chính bạn (dự án cũ), liệt kê cảm giác "khó chịu" khi đọc - đó chính là smell.

Ngày 100: Long Method

  • Mục tiêu: Nhận diện và hiểu tác hại của method quá dài.

  • Lý thuyết: Method dài thường làm nhiều việc, khó test, khó đặt tên rõ nghĩa.

  • Thực hành: Tìm 1 method > 50 dòng trong codebase thật, liệt kê các "đoạn logic con" có thể tách ra.

Ngày 101: God Object (God Class)

  • Mục tiêu: Nhận diện class ôm quá nhiều trách nhiệm.

  • Lý thuyết: Vi phạm Single Responsibility Principle, thường là class kiểu Manager/Utils/Helper phình to dần.

  • Thực hành: Tìm 1 class có > 10 method không liên quan nhau, phân nhóm các method theo trách nhiệm.

Ngày 102: Shotgun Surgery

  • Mục tiêu: Nhận diện khi 1 thay đổi nhỏ buộc phải sửa ở rất nhiều nơi.

  • Lý thuyết: Logic liên quan bị rải rác thay vì tập trung - ngược lại với Divergent Change.

  • Thực hành: Giả lập 1 thay đổi yêu cầu (VD: đổi định dạng ngày tháng) trên 1 codebase, đếm số file phải sửa.

Ngày 103: Feature Envy

  • Mục tiêu: Nhận diện method "ganh tị" dữ liệu của class khác.

  • Lý thuyết: Method dùng dữ liệu của class khác nhiều hơn dữ liệu của chính class nó - dấu hiệu đặt sai vị trí.

  • Thực hành: Tìm 1 method truy cập field của object khác nhiều lần liên tiếp, đánh giá xem có nên move sang class kia không.

Ngày 104: Data Clumps

  • Mục tiêu: Nhận diện nhóm dữ liệu hay đi chung nhưng chưa được gom thành object.

  • Lý thuyết: VD: street, city, zipcode luôn xuất hiện cùng nhau ở nhiều method → nên là 1 class Address.

  • Thực hành: Tìm 3 method có cùng nhóm tham số lặp lại, đề xuất object gom nhóm.

Ngày 105: Duplicate Code

  • Mục tiêu: Nhận diện logic trùng lặp - smell phổ biến và nguy hiểm nhất.

  • Lý thuyết: Duplicate code làm tăng chi phí bảo trì gấp N lần (N = số chỗ trùng); "Rule of Three" khi nào nên trừu tượng hoá.

  • Thực hành: Dùng công cụ phát hiện duplicate code (hoặc tìm thủ công) trên 1 project, liệt kê top 3 đoạn trùng lặp nhiều nhất.

Ngày 106: Primitive Obsession

  • Mục tiêu: Nhận diện lạm dụng kiểu nguyên thuỷ thay vì object có ý nghĩa.

  • Lý thuyết: VD: dùng String cho email/phone/currency thay vì class riêng - mất khả năng validate và mất ý nghĩa domain.

  • Thực hành: Tìm 3 chỗ dùng String/int cho khái niệm domain có quy tắc riêng, đề xuất value object thay thế.

Ngày 107: Switch Statements / Conditional Complexity

  • Mục tiêu: Nhận diện switch/if-else phình to lặp lại nhiều nơi theo cùng 1 loại điều kiện.

  • Lý thuyết: Khi cùng 1 switch trên "loại" xuất hiện ở nhiều method → dấu hiệu cần polymorphism (sẽ học kỹ thuật sửa ở Ngày 111).

  • Thực hành: Tìm 1 switch/if-else theo type/enum xuất hiện ở ít nhất 2 nơi trong codebase.

Ngày 108: Lab tổng hợp - Phát hiện Code Smells

  • Mục tiêu: Luyện khả năng "ngửi" smell trên codebase thật, chưa sửa vội.

  • Lý thuyết: Ôn lại toàn bộ 8 smell đã học.

  • Thực hành: Chọn 1 open-source project vừa (hoặc project cũ của bạn), viết báo cáo liệt kê ít nhất 10 smell tìm thấy, phân loại theo từng nhóm.

Nhóm 2: Refactoring Techniques (Ngày 109–118)

Ngày 109: Extract Method

  • Mục tiêu: Học kỹ thuật cơ bản nhất, dùng để sửa Long Method.

  • Lý thuyết: Tách 1 đoạn logic thành method riêng có tên rõ nghĩa, giữ nguyên hành vi.

  • Thực hành: Áp dụng Extract Method lên method dài đã tìm ở Ngày 100.

Ngày 110: Introduce Parameter Object

  • Mục tiêu: Học kỹ thuật sửa Data Clumps.

  • Lý thuyết: Gom nhóm tham số hay đi cùng nhau thành 1 object truyền vào.

  • Thực hành: Áp dụng lên nhóm tham số đã tìm ở Ngày 104, tạo class Address/tương tự.

Ngày 111: Replace Conditional with Polymorphism

  • Mục tiêu: Học kỹ thuật sửa Switch Statements - liên hệ trực tiếp Module 5 (Polymorphism) đã học.

  • Lý thuyết: Thay switch theo type bằng cách để mỗi type override 1 method riêng.

  • Thực hành: Áp dụng lên switch đã tìm ở Ngày 107, tạo hierarchy/interface thay thế.

Ngày 112: Move Method

  • Mục tiêu: Học kỹ thuật sửa Feature Envy.

  • Lý thuyết: Chuyển method sang class mà nó thực sự "quan tâm" dữ liệu nhiều nhất.

  • Thực hành: Áp dụng lên method đã tìm ở Ngày 103.

Ngày 113: Extract Class

  • Mục tiêu: Học kỹ thuật sửa God Object.

  • Lý thuyết: Tách 1 nhóm field + method liên quan thành class mới, giữ lại quan hệ composition với class gốc.

  • Thực hành: Áp dụng lên God Class đã tìm ở Ngày 101, tách thành 2-3 class có trách nhiệm rõ ràng.

Ngày 114: Replace Temp with Query

  • Mục tiêu: Học kỹ thuật giảm biến tạm, tăng khả năng Extract Method sau này.

  • Lý thuyết: Biến tạm chỉ dùng 1 lần nên thay bằng method trả về giá trị đó - dễ tách nhỏ hơn.

  • Thực hành: Tìm 1 method có biến tạm tính toán phức tạp, thay bằng method riêng.

Ngày 115: Inline Method & Inline Class

  • Mục tiêu: Học kỹ thuật ngược lại Extract - đôi khi gộp lại mới là refactor đúng.

  • Lý thuyết: Khi 1 method/class quá nhỏ và không còn ý nghĩa tách riêng, nên gộp lại để giảm indirection thừa.

  • Thực hành: Tìm 1 ví dụ over-engineered (quá nhiều lớp indirection cho logic đơn giản), áp dụng Inline.

Ngày 116: Encapsulate Field & Encapsulate Collection

  • Mục tiêu: Học kỹ thuật bảo vệ state khỏi bị sửa trực tiếp từ bên ngoài.

  • Lý thuyết: Field/collection public dễ bị mutate không kiểm soát - bọc qua getter trả về bản sao/view bất biến.

  • Thực hành: Tìm 1 class expose List trực tiếp, sửa lại để trả về unmodifiable view.

Ngày 117: Lab - Áp dụng chuỗi kỹ thuật liên tiếp

  • Mục tiêu: Luyện phản xạ chọn đúng kỹ thuật cho đúng smell, áp dụng nối tiếp nhau.

  • Lý thuyết: Refactoring thường là chuỗi bước nhỏ (baby steps), không phải 1 lần sửa lớn.

  • Thực hành: Lấy 1 method vừa dài vừa có switch vừa có data clump, áp dụng liên tiếp Extract Method → Replace Conditional with Polymorphism → Introduce Parameter Object.

Ngày 118: Ôn tập Refactoring Techniques

  • Mục tiêu: Củng cố toàn bộ nhóm kỹ thuật.

  • Lý thuyết: Lập bảng "Smell → Technique tương ứng" để dùng làm cheat-sheet về sau.

  • Thực hành: Tự làm quiz: cho 5 đoạn code có smell khác nhau, chọn đúng kỹ thuật sửa cho từng đoạn.

Nhóm 3: Project - Refactor hệ thống E-commerce (Ngày 119–126)

Ngày 119: Phân tích codebase E-commerce xấu

  • Mục tiêu: Có bức tranh tổng thể trước khi sửa.

  • Lý thuyết: Luôn phân tích/lập bản đồ smell trước khi refactor, tránh sửa tuỳ hứng.

  • Thực hành: Chuẩn bị (hoặc viết sẵn) 1 codebase E-commerce nhỏ có chủ đích chứa nhiều smell (Order, Product, Payment, Customer), liệt kê toàn bộ smell tìm thấy theo từng module.

Ngày 120: Refactor Order Module

  • Mục tiêu: Áp dụng kỹ thuật vào module đầu tiên.

  • Lý thuyết: Ôn lại Extract Method, Extract Class cho God Object.

  • Thực hành: Refactor class Order/OrderService đang ôm quá nhiều logic (tính tiền, validate, gửi email...) thành các class tách bạch.

Ngày 121: Refactor Product/Inventory Module

  • Mục tiêu: Xử lý smell Data Clumps và Primitive Obsession thường gặp ở module này.

  • Lý thuyết: Ôn lại Introduce Parameter Object, value object cho Price/SKU.

  • Thực hành: Refactor Product class, gom nhóm dữ liệu rời rạc thành value object.

Ngày 122: Refactor Payment Module

  • Mục tiêu: Xử lý switch statement điển hình theo loại phương thức thanh toán.

  • Lý thuyết: Ôn lại Replace Conditional with Polymorphism (đã làm ở Lab OOP Ngày 66 - liên hệ lại).

  • Thực hành: Refactor logic xử lý payment đang if-else theo type thành hierarchy polymorphism.

Ngày 123: Refactor Customer/User Module

  • Mục tiêu: Xử lý Feature Envy và Shotgun Surgery thường gặp ở module quản lý user.

  • Lý thuyết: Ôn lại Move Method.

  • Thực hành: Refactor các method đang truy cập chéo dữ liệu giữa CustomerOrder về đúng vị trí.

Ngày 124: Characterization Tests

  • Mục tiêu: Đảm bảo refactor không phá vỡ hành vi cũ.

  • Lý thuyết: Characterization test - viết test ghi lại hành vi hiện tại của code (kể cả khi chưa chắc đúng) trước khi refactor, để có lưới an toàn.

  • Thực hành: Viết bộ test bao phủ toàn bộ 4 module trước khi refactor (nếu chưa làm), verify test vẫn pass sau khi đã refactor ở các ngày trước.

Ngày 125: Đo lường cải thiện

  • Mục tiêu: Định lượng kết quả refactor, không chỉ cảm tính "sạch hơn".

  • Lý thuyết: Cyclomatic complexity, coupling giữa class, số dòng/method trung bình - công cụ đo (VD: SonarQube, hoặc thủ công).

  • Thực hành: Đo các chỉ số trên trước/sau refactor cho cả 4 module, lập bảng so sánh.

Ngày 126: Review & Retrospective Giai đoạn 2

  • Mục tiêu: Tổng kết toàn bộ giai đoạn Refactoring.

  • Lý thuyết: Nhìn lại mối liên hệ Smell → Technique → Kết quả đo lường được.

  • Thực hành: Viết báo cáo retrospective, đề xuất quy trình refactor bạn sẽ áp dụng cho công việc thực tế (VD: mỗi PR nên kèm 1 refactor nhỏ, definition of done bao gồm "không còn smell rõ ràng").

Knowledge

Part 1 of 50