Syllabus software engineering (2)
Giai đoạn 3 - Design Patterns (Ngày 127–189)
Tài liệu chính: Design Patterns (GoF). Mỗi pattern học theo nhịp 3 ngày: khái niệm & cấu trúc → lab thực hành → so sánh/tradeoff với pattern gần giống.
Nhóm 1: Giới thiệu (Ngày 127–128)
Ngày 127: Giới thiệu Design Patterns
Mục tiêu: Hiểu pattern là gì và cạm bẫy lớn nhất khi học pattern (áp dụng bừa).
Lý thuyết: 3 nhóm pattern GoF (Creational/Structural/Behavioral), pattern là "vocabulary" để giao tiếp thiết kế, không phải checklist bắt buộc dùng.
Thực hành: Đọc lại Plugin System đã xây ở Giai đoạn 1, xác định nó đang dùng ngầm pattern nào (gợi ý: Strategy/Factory).
Ngày 128: Singleton - Vì sao không ưu tiên
Mục tiêu: Hiểu vì sao Singleton phổ biến nhưng bị đánh giá là anti-pattern trong nhiều trường hợp.
Lý thuyết: Global state ẩn, khó test (khó mock), che giấu dependency thay vì inject rõ ràng qua constructor.
Thực hành: Viết 1 ví dụ Singleton, chỉ ra vì sao viết unit test cho code phụ thuộc Singleton đó khó khăn; đề xuất thay thế bằng Dependency Injection.
Nhóm 2: Creational Patterns (Ngày 129–140)
Ngày 129: Factory Method - Concept & Structure
Mục tiêu: Hiểu cách trì hoãn việc quyết định class cụ thể nào được tạo cho subclass.
Lý thuyết: Factory Method định nghĩa 1 interface tạo object, để subclass quyết định class nào sẽ được instantiate.
Thực hành: Vẽ sơ đồ UML cho Factory Method áp dụng vào ví dụ
NotificationFactory(Email/SMS/Push).
Ngày 130: Factory Method - Lab
Mục tiêu: Thực hành implement đầy đủ.
Lý thuyết: Ôn lại cấu trúc Creator/ConcreteCreator/Product/ConcreteProduct.
Thực hành: Cài đặt
NotificationFactoryvới 3 loại notification, viết client code không phụ thuộc concrete class.
Ngày 131: Factory Method - So sánh với Simple Factory & Abstract Factory
Mục tiêu: Phân biệt 3 khái niệm hay bị nhầm lẫn.
Lý thuyết: Simple Factory (không phải pattern GoF chính thức, chỉ là idiom) vs Factory Method (dùng inheritance) vs Abstract Factory (họ nhiều factory).
Thực hành: Lập bảng so sánh 3 cách tiếp cận, chỉ rõ khi nào dùng cái nào.
Ngày 132: Abstract Factory - Concept & Structure
Mục tiêu: Hiểu cách tạo ra cả 1 họ object liên quan mà không cần biết class cụ thể.
Lý thuyết: Abstract Factory cung cấp interface tạo ra các họ object có liên quan (family of related objects).
Thực hành: Vẽ sơ đồ UML cho ví dụ
UIThemeFactorytạo raButton/Checkbox/Scrollbarđồng bộ theo theme (Light/Dark).
Ngày 133: Abstract Factory - Lab
Mục tiêu: Thực hành implement family of objects.
Lý thuyết: Ôn lại quan hệ giữa Abstract Factory và Factory Method (Abstract Factory thường implement bằng nhiều Factory Method).
Thực hành: Cài đặt
UIThemeFactoryvớiLightThemeFactory/DarkThemeFactory, verify các component luôn đồng bộ theme.
Ngày 134: Abstract Factory - Khi nào dùng, Tradeoffs
Mục tiêu: Hiểu chi phí của pattern này.
Lý thuyết: Thêm 1 product mới vào family đòi hỏi sửa interface (vi phạm Open/Closed ở chiều này) - tradeoff cần cân nhắc.
Thực hành: Thử thêm 1 product mới (
Tooltip) vào ví dụ Ngày 133, quan sát số chỗ phải sửa.
Ngày 135: Builder - Concept & Structure
Mục tiêu: Hiểu cách tách quá trình xây dựng object phức tạp khỏi representation cuối cùng.
Lý thuyết: Builder tách construction logic ra khỏi class, cho phép xây object từng bước với nhiều biến thể.
Thực hành: Vẽ sơ đồ UML cho
HttpRequestBuilder(method, url, headers, body, timeout).
Ngày 136: Builder - Lab
Mục tiêu: Thực hành implement fluent API.
Lý thuyết: Method chaining, trả về
thischo từng bước build.Thực hành: Cài đặt
HttpRequestBuilderđầy đủ với fluent API, viết client tạo request theo nhiều cấu hình khác nhau.
Ngày 137: Builder vs Telescoping Constructor
Mục tiêu: Hiểu vấn đề Builder giải quyết.
Lý thuyết: Telescoping constructor (nhiều constructor overload tăng dần tham số) trở nên khó đọc khi > 4-5 tham số.
Thực hành: Viết ví dụ class với telescoping constructor xấu, refactor sang Builder.
Ngày 138: Prototype - Concept & Structure
Mục tiêu: Hiểu cách tạo object mới bằng cách sao chép object có sẵn thay vì new từ đầu.
Lý thuyết: Prototype hữu ích khi việc khởi tạo object tốn kém (VD: load config nặng) - clone rẻ hơn tạo mới.
Thực hành: Vẽ sơ đồ UML cho
DocumentPrototype(clone 1 template document).
Ngày 139: Prototype - Lab
Mục tiêu: Thực hành phân biệt shallow copy và deep copy.
Lý thuyết: Shallow copy chỉ copy reference cấp 1 - nguy hiểm nếu object chứa nested mutable object.
Thực hành: Cài đặt
clone()cho 1 object có nested object, viết cả bản shallow lẫn deep, chứng minh bug khi dùng nhầm shallow.
Ngày 140: Review Creational Patterns
Mục tiêu: Tổng hợp toàn bộ nhóm Creational.
Lý thuyết: Lập bảng "Tình huống → Pattern phù hợp" cho cả 4 pattern (+Singleton).
Thực hành: Cho 5 tình huống thực tế, chọn đúng creational pattern và giải thích vì sao.
Nhóm 3: Structural Patterns (Ngày 141–158)
Ngày 141: Adapter - Concept & Structure
Mục tiêu: Hiểu cách làm 2 interface không tương thích hoạt động cùng nhau.
Lý thuyết: Adapter "bọc" 1 interface cũ/không tương thích thành interface mà client mong đợi.
Thực hành: Vẽ sơ đồ UML cho việc adapt 1 thư viện logging cũ (
LegacyLogger) vào interfaceLoggermới của hệ thống.
Ngày 142: Adapter - Lab
Mục tiêu: Thực hành wrap 1 API/thư viện thật.
Lý thuyết: Ôn lại quan hệ composition trong Adapter (Object Adapter).
Thực hành: Cài đặt
LegacyLoggerAdapterimplementLogger, verify code mới không cần biếtLegacyLoggertồn tại.
Ngày 143: Object Adapter vs Class Adapter
Mục tiêu: Hiểu 2 biến thể implement Adapter.
Lý thuyết: Object Adapter (composition, phổ biến ở ngôn ngữ không đa kế thừa) vs Class Adapter (multiple inheritance, khả dụng ở C++).
Thực hành: Viết Class Adapter bằng C++ (đa kế thừa), so sánh ưu nhược với Object Adapter đã viết ở Java/Python.
Ngày 144: Facade - Concept & Structure
Mục tiêu: Hiểu cách đơn giản hoá 1 subsystem phức tạp.
Lý thuyết: Facade cung cấp 1 interface đơn giản che giấu sự phức tạp bên trong của nhiều subsystem con.
Thực hành: Vẽ sơ đồ UML cho
OrderFacadeche giấu tương tác giữaInventory/Payment/Shipping.
Ngày 145: Facade - Lab
Mục tiêu: Thực hành đơn giản hoá 1 quy trình nhiều bước.
Lý thuyết: Ôn lại Facade không thêm behavior mới, chỉ tổ chức lại lời gọi.
Thực hành: Cài đặt
OrderFacade.placeOrder()gọi tuần tự 3 subsystem, verify client code chỉ cần gọi 1 method.
Ngày 146: Facade vs Adapter
Mục tiêu: Phân biệt 2 pattern hay bị nhầm vì cùng "bọc" cái gì đó.
Lý thuyết: Adapter thay đổi interface để tương thích; Facade đơn giản hoá interface phức tạp có sẵn (không nhất thiết không tương thích).
Thực hành: Lập bảng so sánh intent của 2 pattern qua ví dụ đã làm.
Ngày 147: Decorator - Concept & Structure
Mục tiêu: Hiểu cách thêm behavior cho object tại runtime mà không sửa class gốc.
Lý thuyết: Decorator bọc object gốc, thêm behavior trước/sau khi delegate cho object gốc - có thể xếp chồng nhiều decorator.
Thực hành: Vẽ sơ đồ UML kiểu
java.io(InputStream→BufferedInputStream→GZIPInputStream).
Ngày 148: Decorator - Lab
Mục tiêu: Thực hành xếp chồng nhiều decorator.
Lý thuyết: Ôn lại mỗi decorator implement cùng interface với object nó bọc.
Thực hành: Cài đặt
Coffeevới các decoratorMilkDecorator/SugarDecorator/WhipDecorator, verify có thể kết hợp tuỳ ý.
Ngày 149: Decorator vs Inheritance
Mục tiêu: Hiểu vì sao Decorator tránh được "combinatorial explosion" của inheritance.
Lý thuyết: Nếu dùng inheritance cho mọi tổ hợp (
CoffeeWithMilkAndSugar,CoffeeWithSugarAndWhip...) số class tăng theo cấp số nhân - Decorator giải quyết bằng composition runtime.Thực hành: Thử vẽ hierarchy inheritance cho ví dụ Coffee với 3 topping, đếm số class cần tạo, so với Decorator chỉ cần 3 class.
Ngày 150: Proxy - Concept & Structure
Mục tiêu: Hiểu 4 loại proxy phổ biến.
Lý thuyết: Virtual Proxy (lazy loading), Remote Proxy (RPC stub), Protection Proxy (access control), Logging/Caching Proxy.
Thực hành: Vẽ sơ đồ UML cho
ImageProxy(Virtual Proxy) chỉ load ảnh thật khi cần hiển thị.
Ngày 151: Proxy - Lab
Mục tiêu: Thực hành lazy-loading proxy.
Lý thuyết: Ôn lại Proxy implement cùng interface với object thật, kiểm soát truy cập tới nó.
Thực hành: Cài đặt
ImageProxyimplementImage, verify object ảnh thật chỉ được tạo khidisplay()được gọi lần đầu.
Ngày 152: Proxy vs Decorator
Mục tiêu: Phân biệt 2 pattern có cấu trúc UML gần như giống hệt nhau.
Lý thuyết: Cấu trúc giống nhau nhưng intent khác: Decorator thêm behavior, Proxy kiểm soát truy cập (không nhất thiết thêm behavior).
Thực hành: Viết nhận xét so sánh dựa trên 2 ví dụ đã cài (Coffee Decorator vs Image Proxy).
Ngày 153: Composite - Concept & Structure
Mục tiêu: Hiểu cách xử lý object đơn lẻ và object nhóm (tree) theo cùng 1 interface.
Lý thuyết: Composite cho phép client đối xử với object đơn (
Leaf) và object nhóm (Composite) giống hệt nhau.Thực hành: Vẽ sơ đồ UML cho hệ thống file (
Filelà Leaf,Directorylà Composite).
Ngày 154: Composite - Lab
Mục tiêu: Thực hành cấu trúc cây đệ quy.
Lý thuyết: Ôn lại method
getSize()/print()được gọi đệ quy tự nhiên qua cấu trúc Composite.Thực hành: Cài đặt
File/Directoryimplement chung interfaceFileSystemNode, tính tổng dung lượng đệ quy qua nhiều tầng thư mục.
Ngày 155: Composite + Visitor - Liên hệ trước
Mục tiêu: Thấy trước vì sao Composite hay đi cùng Visitor (sẽ học ở Ngày 177).
Lý thuyết: Khi cần thêm operation mới lên cấu trúc Composite mà không sửa từng node - đó là lúc cần Visitor.
Thực hành: Liệt kê 3 operation khác nhau (print, count, export JSON) bạn sẽ cần thêm vào ví dụ file system, ghi chú lại để áp dụng Visitor sau.
Ngày 156: Bridge - Concept & Structure
Mục tiêu: Hiểu cách tách abstraction khỏi implementation để cả 2 phát triển độc lập.
Lý thuyết: Bridge tách 1 class thành 2 hierarchy riêng (abstraction và implementation) nối với nhau qua composition thay vì inheritance.
Thực hành: Vẽ sơ đồ UML cho
Shape(abstraction: Circle/Square) tách khỏiRenderer(implementation: VectorRenderer/RasterRenderer).
Ngày 157: Bridge - Lab
Mục tiêu: Thực hành tránh combinatorial explosion tương tự Decorator nhưng ở bối cảnh khác.
Lý thuyết: Ôn lại nếu không có Bridge, số class sẽ là (số shape) × (số renderer).
Thực hành: Cài đặt
Shape/Renderertheo Bridge, verify thêm 1 shape mới hoặc 1 renderer mới không làm nổ số class.
Ngày 158: Bridge vs Adapter + Review Structural Patterns
Mục tiêu: Chốt lại toàn bộ nhóm Structural.
Lý thuyết: Bridge thiết kế trước (proactive) để tách 2 hierarchy; Adapter thiết kế sau (reactive) để ghép 2 interface có sẵn không tương thích.
Thực hành: Lập bảng tổng hợp cả 6 pattern Structural: intent, ví dụ, khi nào dùng.
Nhóm 4: Behavioral Patterns (Ngày 159–179)
Ngày 159: Strategy - Concept & Structure
Mục tiêu: Hiểu cách hoán đổi thuật toán/hành vi tại runtime.
Lý thuyết: Strategy đóng gói 1 họ thuật toán thành các class có thể thay thế cho nhau qua cùng 1 interface.
Thực hành: Vẽ sơ đồ UML cho
SortStrategy(BubbleSort/QuickSort/MergeSort) chọn được tại runtime.
Ngày 160: Strategy - Lab
Mục tiêu: Thực hành thay if-else bằng Strategy, liên hệ lại
PaymentMethodđã làm ở Giai đoạn 1.Lý thuyết: Ôn lại Strategy pattern chính là hình thức hoá của Replace Conditional with Polymorphism đã học ở Giai đoạn 2.
Thực hành: Mở rộng
PaymentMethodcũ, thêm khả năng chọnDiscountStrategy(NoDiscount/PercentageDiscount/FixedDiscount) độc lập với loại payment.
Ngày 161: Strategy vs State - Preview
Mục tiêu: Thấy trước điểm giống/khác giữa 2 pattern có cấu trúc UML gần giống hệt.
Lý thuyết: Strategy: client chủ động chọn thuật toán. State: object tự chuyển đổi hành vi dựa trên state nội tại.
Thực hành: Ghi chú lại câu hỏi "ai là người quyết định thay đổi" cho từng ví dụ đã gặp, dùng để phân biệt khi học State (Ngày 168).
Ngày 162: Observer - Concept & Structure
Mục tiêu: Hiểu cơ chế publish-subscribe cổ điển.
Lý thuyết: Observer định nghĩa quan hệ 1-nhiều: khi Subject đổi state, mọi Observer đăng ký đều được thông báo.
Thực hành: Vẽ sơ đồ UML cho
StockPrice(Subject) và nhiềuPriceDisplay(Observer).
Ngày 163: Observer - Lab
Mục tiêu: Thực hành implement event system cơ bản.
Lý thuyết: Ôn lại
subscribe()/unsubscribe()/notify().Thực hành: Cài đặt
StockPrice+ 2 loạiObserver(bảng giá, cảnh báo), verify khi giá đổi tất cả observer được gọi.
Ngày 164: Observer - Pitfalls
Mục tiêu: Hiểu lỗi thực tế hay gặp khi dùng Observer trong production.
Lý thuyết: Memory leak do quên
unsubscribe(lapsed listener problem), thứ tự notify không đảm bảo, observer ném exception làm hỏng cả chuỗi notify.Thực hành: Viết ví dụ minh hoạ memory leak (observer không được GC vì subject vẫn giữ reference), đề xuất cách khắc phục (weak reference/explicit unsubscribe).
Ngày 165: Command - Concept & Structure
Mục tiêu: Hiểu cách đóng gói 1 yêu cầu (request) thành object.
Lý thuyết: Command biến 1 hành động thành object có thể lưu trữ, xếp hàng đợi, log, hoặc undo.
Thực hành: Vẽ sơ đồ UML cho
TextEditorvới cácCommand(InsertCommand/DeleteCommand).
Ngày 166: Command - Lab
Mục tiêu: Thực hành tính năng undo/redo - lý do chính người ta dùng Command.
Lý thuyết: Ôn lại mỗi Command lưu đủ thông tin để tự
execute()vàundo().Thực hành: Cài đặt
TextEditorvới command history stack, hỗ trợ undo/redo nhiều bước.
Ngày 167: Command vs Strategy
Mục tiêu: Phân biệt 2 pattern cùng "đóng gói hành vi thành object".
Lý thuyết: Strategy tập trung vào "làm cách nào" (thuật toán thay thế nhau); Command tập trung vào "làm gì, khi nào, có thể hoàn tác không".
Thực hành: Viết nhận xét so sánh dựa trên 2 ví dụ đã cài đặt.
Ngày 168: State - Concept & Structure
Mục tiêu: Hiểu cách object tự thay đổi hành vi khi state nội tại thay đổi.
Lý thuyết: State đóng gói mỗi trạng thái thành 1 class, object chuyển hành vi bằng cách đổi state object đang giữ.
Thực hành: Vẽ sơ đồ UML cho
Ordervới các state (Pending/Paid/Shipped/Cancelled).
Ngày 169: State - Lab
Mục tiêu: Thực hành state machine thực tế.
Lý thuyết: Ôn lại mỗi state class biết những transition nào hợp lệ từ chính nó.
Thực hành: Cài đặt
Orderchuyển trạng thái qua các state class, verify transition không hợp lệ (VD:Shipped→Pending) bị chặn.
Ngày 170: State vs Strategy - Kết luận
Mục tiêu: Chốt lại phân biệt đã preview ở Ngày 161.
Lý thuyết: Cấu trúc UML gần như giống hệt, khác nhau ở "ai kiểm soát chuyển đổi" và "có nhận biết lẫn nhau giữa các state/strategy không".
Thực hành: Áp câu hỏi phân biệt vào ví dụ
Order(State) vàDiscountStrategy(Strategy) đã làm, viết kết luận rõ ràng.
Ngày 171: Mediator - Concept & Structure
Mục tiêu: Hiểu cách giảm coupling giữa nhiều object bằng cách tập trung giao tiếp qua 1 điểm.
Lý thuyết: Mediator đóng vai trò trung gian, các object không giao tiếp trực tiếp với nhau mà thông qua Mediator.
Thực hành: Vẽ sơ đồ UML cho
ChatRoom(Mediator) điều phối nhiềuUser(Colleague).
Ngày 172: Mediator - Lab
Mục tiêu: Thực hành giảm coupling giữa nhiều component.
Lý thuyết: Ôn lại nếu không có Mediator, mỗi
Userphải biết về mọiUserkhác (N² kết nối).Thực hành: Cài đặt
ChatRoomđiều phối tin nhắn giữa nhiềuUser, verifyUserkhông cần biết sự tồn tại củaUserkhác.
Ngày 173: Mediator vs Observer
Mục tiêu: Phân biệt 2 pattern cùng liên quan tới giao tiếp gián tiếp.
Lý thuyết: Observer là quan hệ 1-nhiều 1 chiều (broadcast); Mediator điều phối giao tiếp nhiều-nhiều 2 chiều phức tạp hơn.
Thực hành: Viết nhận xét so sánh dựa trên ví dụ
StockPrice(Observer) vàChatRoom(Mediator).
Ngày 174: Chain of Responsibility - Concept & Structure
Mục tiêu: Hiểu cách 1 request đi qua chuỗi handler cho tới khi được xử lý.
Lý thuyết: Mỗi handler quyết định xử lý request hoặc chuyển tiếp cho handler kế tiếp trong chain.
Thực hành: Vẽ sơ đồ UML cho chuỗi xử lý HTTP request (
AuthHandler→RateLimitHandler→BusinessLogicHandler).
Ngày 175: Chain of Responsibility - Lab
Mục tiêu: Thực hành middleware-style pipeline - sẽ dùng trực tiếp ở project cuối giai đoạn.
Lý thuyết: Ôn lại mỗi handler giữ reference tới handler kế tiếp (successor).
Thực hành: Cài đặt chuỗi 3 handler xử lý request, verify request bị chặn ở
AuthHandlerkhông đi tiếp xuống các handler sau.
Ngày 176: Chain of Responsibility vs Decorator
Mục tiêu: Phân biệt 2 pattern đều tạo thành "chuỗi" các object bọc nhau.
Lý thuyết: Decorator luôn gọi qua object tiếp theo (tất cả đều chạy); CoR có thể dừng giữa chừng, chỉ 1 handler xử lý (hoặc không handler nào).
Thực hành: Viết nhận xét so sánh dựa trên
CoffeeDecoratorvà request handler chain đã cài.
Ngày 177: Visitor - Concept & Structure
Mục tiêu: Hiểu cách thêm operation mới vào 1 cấu trúc object mà không sửa class của object đó.
Lý thuyết: Visitor dùng double dispatch - cho phép thêm operation mới (visit) mà không cần sửa hierarchy element đã tồn tại.
Thực hành: Vẽ sơ đồ UML áp dụng Visitor lên cấu trúc file system (Composite) đã làm ở Ngày 154, thêm operation
ExportJsonVisitor.
Ngày 178: Visitor - Lab
Mục tiêu: Thực hành double dispatch thật sự (không chỉ if-instanceof).
Lý thuyết: Ôn lại mỗi Element có method
accept(visitor)gọi ngược lại đúng methodvisit()tương ứng type của nó.Thực hành: Cài đặt
ExportJsonVisitorvàPrintVisitorcho cấu trúcFile/Directory, verify thêm operation mới không cần sửaFile/Directory.
Ngày 179: Review Behavioral Patterns
Mục tiêu: Tổng hợp toàn bộ nhóm Behavioral (7 pattern) và toàn bộ 17 pattern + Singleton đã học.
Lý thuyết: Lập bảng tổng hợp cuối: Category → Pattern → Intent → Ví dụ đã cài.
Thực hành: Tự quiz: cho 7 tình huống thực tế khác nhau (1 cho mỗi behavioral pattern), chọn đúng pattern và giải thích.
Nhóm 5: Project - Mini Web Framework (Ngày 180–189)
Ngày 180: Thiết kế kiến trúc tổng thể
Mục tiêu: Lên bản thiết kế trước khi code, xác định pattern nào dùng ở đâu.
Lý thuyết: Framework cần: Router (Composite-ish tree hoặc Chain), Middleware (Chain of Responsibility), DI Container (Factory/Builder), Plugin (đã có sẵn từ Giai đoạn 1).
Thực hành: Vẽ sơ đồ kiến trúc tổng thể Mini Web Framework, ghi chú pattern dự kiến áp dụng cho từng thành phần.
Ngày 181: Xây Router
Mục tiêu: Xây thành phần định tuyến request tới đúng handler.
Lý thuyết: Route matching (exact, path param), cấu trúc dữ liệu lưu route (trie hoặc list + regex).
Thực hành: Cài đặt
RoutervớiaddRoute(method, path, handler)vàmatch(method, path)trả về handler + path params.
Ngày 182: Xây Middleware Pipeline
Mục tiêu: Áp dụng trực tiếp Chain of Responsibility đã học.
Lý thuyết: Middleware chạy trước/sau handler chính, có thể chặn request (giống
AuthHandlerđã làm Ngày 175).Thực hành: Cài đặt
MiddlewarePipelinecho phép đăng ký nhiều middleware, verify middleware có thể chặn hoặc pass tiếp request.
Ngày 183: Xây DI Container cơ bản
Mục tiêu: Áp dụng Factory/Builder để quản lý khởi tạo dependency.
Lý thuyết: DI Container đăng ký "cách tạo" 1 type, tự động resolve dependency qua constructor injection.
Thực hành: Cài đặt
Containervớiregister(type, factory)vàresolve(type), hỗ trợ resolve dependency lồng nhau.
Ngày 184: Tích hợp Plugin System
Mục tiêu: Tái sử dụng Plugin System đã xây ở Giai đoạn 1 vào framework mới.
Lý thuyết: Plugin trong framework có thể là middleware, có thể là route handler - cần thiết kế extension point rõ ràng.
Thực hành: Tích hợp
PluginRegistry/PluginLoadercũ vào Mini Web Framework, cho phép plugin đăng ký route hoặc middleware.
Ngày 185: Request/Response & Handler Interface
Mục tiêu: Hoàn thiện các abstraction còn thiếu.
Lý thuyết:
Request/Responseobject đóng gói thông tin HTTP,Handlerinterface thống nhất cho mọi route.Thực hành: Cài đặt
Request/Response, chuẩn hoá interfaceHandler.handle(req, res).
Ngày 186: Ứng dụng ví dụ - CRUD API
Mục tiêu: Kiểm tra framework hoạt động với use case thực tế.
Lý thuyết: Ôn lại toàn bộ các thành phần đã ghép: Router + Middleware + DI + Plugin.
Thực hành: Viết 1 API CRUD đơn giản (VD: quản lý
Task) chạy trên chính Mini Web Framework vừa xây.
Ngày 187: Viết Test cho Framework
Mục tiêu: Đảm bảo framework đáng tin cậy.
Lý thuyết: Test ở tầng framework cần cover: route matching đúng, middleware chạy đúng thứ tự, DI resolve đúng dependency.
Thực hành: Viết test suite cho
Router/MiddlewarePipeline/Containerđộc lập với CRUD API.
Ngày 188: Đo lường & Tối ưu
Mục tiêu: Đánh giá hiệu năng cơ bản của framework tự viết.
Lý thuyết: Overhead của route matching, middleware chain, DI resolve - cái nào tốn chi phí nhất.
Thực hành: Benchmark số request/giây xử lý được, xác định điểm nghẽn và thử tối ưu 1 điểm.
Ngày 189: Review & Retrospective Giai đoạn 3
Mục tiêu: Tổng kết toàn bộ Giai đoạn Design Patterns.
Lý thuyết: Nhìn lại bản đồ pattern → thành phần framework đã vẽ ở Ngày 180, đối chiếu với những gì thực sự dùng.
Thực hành: Viết báo cáo retrospective: pattern nào hữu ích nhất, pattern nào áp dụng gượng ép không cần thiết trong project này.
Giai đoạn 4 - Testing & Quality Engineering (Ngày 190–217)
Giai đoạn mới bổ sung. Không có mảng này thì mọi kiến trúc/pattern đã học ở trên không thể gọi là "production-ready".
Nhóm 1: Giới thiệu (Ngày 190–191)
Ngày 190: Giới thiệu Testing & Quality Engineering
Mục tiêu: Có bức tranh tổng thể về các tầng test trước khi đi sâu từng loại.
Lý thuyết: Test Pyramid (Unit → Integration → E2E), vì sao nên có nhiều unit test, ít E2E test.
Thực hành: Vẽ lại Test Pyramid, liệt kê ví dụ cụ thể cho từng tầng dựa trên Mini Web Framework đã xây ở Giai đoạn 3.
Ngày 191: Chi phí bug theo giai đoạn phát hiện
Mục tiêu: Hiểu vì sao đầu tư vào test sớm rẻ hơn nhiều so với sửa bug ở production.
Lý thuyết: Chi phí sửa bug tăng theo cấp số nhân qua từng giai đoạn (dev → test → staging → production).
Thực hành: Viết 1 ví dụ cụ thể (từ kinh nghiệm cá nhân hoặc giả định) minh hoạ chi phí sửa bug nếu phát hiện ở unit test vs phát hiện sau khi khách hàng report.
Nhóm 2: Unit Testing (Ngày 192–196)
Ngày 192: Unit Test cơ bản - AAA Pattern
Mục tiêu: Nắm cấu trúc chuẩn của 1 unit test tốt.
Lý thuyết: Arrange-Act-Assert, tiêu chí FIRST (Fast, Independent, Repeatable, Self-validating, Timely).
Thực hành: Viết 3 unit test theo AAA cho 1 hàm thuần (pure function) đơn giản.
Ngày 193: JUnit 5 (Java)
Mục tiêu: Thành thạo công cụ test chuẩn của Java.
Lý thuyết:
@Test,@BeforeEach/@AfterEach, assertion (assertEquals,assertThrows), parameterized test.Thực hành: Viết bộ test JUnit 5 đầy đủ cho class
BankAccountđã xây ở Giai đoạn 1.
Ngày 194: pytest (Python)
Mục tiêu: Thành thạo công cụ test chuẩn của Python.
Lý thuyết: Fixture, parametrize, assertion tự nhiên (
assert x == y), plugin ecosystem.Thực hành: Viết bộ test pytest cho cùng logic
BankAccount, dùng fixture để setup account mẫu.
Ngày 195: Google Test/Catch2 (C++)
Mục tiêu: Làm quen framework test phổ biến ở C++.
Lý thuyết: Test fixture (
TEST_F), matcher (Google Mock preview), so sánh Google Test vs Catch2.Thực hành: Viết bộ test cho
vector/hashmaptự viết ở Giai đoạn 0 bằng Google Test hoặc Catch2.
Ngày 196: Lab - Coverage cho module thật
Mục tiêu: Áp dụng unit test vào codebase đã refactor ở Giai đoạn 2.
Lý thuyết: Đo code coverage bằng công cụ (JaCoCo/coverage.py/gcov).
Thực hành: Viết test cho module
Orderđã refactor ở Giai đoạn 2, đo coverage trước/sau, đặt mục tiêu coverage hợp lý (không chạy theo 100%).
Nhóm 3: Test Doubles & Mocking (Ngày 197–200)
Ngày 197: Phân loại Test Double
Mục tiêu: Phân biệt 5 loại test double hay bị gọi chung là "mock".
Lý thuyết: Dummy, Fake, Stub, Spy, Mock - khác nhau ở mục đích sử dụng (theo phân loại của Martin Fowler).
Thực hành: Cho 5 tình huống test khác nhau, xác định nên dùng loại double nào.
Ngày 198: Mocking Framework - Mockito (Java)
Mục tiêu: Thành thạo mock dependency trong Java.
Lý thuyết:
@Mock,when().thenReturn(),verify().Thực hành: Viết test cho 1 service phụ thuộc
PaymentGateway(interface), mockPaymentGatewayđể test logic mà không gọi API thật.
Ngày 199: Mocking Framework - unittest.mock (Python)
Mục tiêu: Thành thạo mock dependency trong Python.
Lý thuyết:
Mock,patch,MagicMock, khác biệt giữa mock ở class-level vs instance-level.Thực hành: Viết test tương tự Ngày 198 bằng Python, dùng
patchđể thay thế lời gọi API thật.
Ngày 200: Lab - Mock dependency ngoài
Mục tiêu: Thực hành tình huống thực tế: test logic phụ thuộc external service.
Lý thuyết: Ôn lại nguyên tắc chỉ mock ở boundary của hệ thống (external API, database, filesystem), không mock nội bộ quá mức (over-mocking).
Thực hành: Viết test đầy đủ cho 1 flow gọi external API (VD: gửi email xác nhận đơn hàng), mock toàn bộ external call, verify logic nghiệp vụ đúng mà không cần network thật.
Nhóm 4: Test-Driven Development (Ngày 201–205)
Ngày 201: Giới thiệu TDD
Mục tiêu: Hiểu quy trình Red-Green-Refactor.
Lý thuyết: Viết test fail trước (Red) → viết code tối thiểu để pass (Green) → refactor code sạch hơn (Refactor) mà không phá test.
Thực hành: Thực hiện 1 chu kỳ Red-Green-Refactor hoàn chỉnh cho 1 hàm rất đơn giản (VD:
isPrime).
Ngày 202: TDD Lab 1 - Class nhỏ từ đầu
Mục tiêu: Luyện phản xạ viết test trước khi viết code.
Lý thuyết: Ôn lại nguyên tắc chỉ viết code đủ để pass test hiện tại, không code trước cho tương lai.
Thực hành: Viết class
Stack<T>hoàn toàn bằng TDD, mỗi tính năng đều bắt đầu bằng 1 test fail.
Ngày 203: TDD Lab 2 - Tính năng phức tạp hơn
Mục tiêu: Áp dụng TDD cho logic có nhiều edge case.
Lý thuyết: Ôn lại việc liệt kê edge case trước khi viết test đầu tiên giúp thiết kế API tốt hơn.
Thực hành: Viết
DiscountCalculator(áp dụng nhiều rule giảm giá) hoàn toàn bằng TDD.
Ngày 204: TDD - Outside-In vs Inside-Out
Mục tiêu: Hiểu 2 trường phái tiếp cận TDD.
Lý thuyết: Outside-In (London School, bắt đầu từ test tích hợp/acceptance, mock hết dependency) vs Inside-Out (Chicago School, bắt đầu từ unit nhỏ nhất rồi ghép dần lên).
Thực hành: Viết lại 1 phần của
DiscountCalculator(Ngày 203) theo hướng Outside-In, so sánh trải nghiệm với cách Inside-Out đã làm.
Ngày 205: TDD Retrospective
Mục tiêu: Đánh giá khách quan lợi ích và chi phí của TDD.
Lý thuyết: TDD giúp thiết kế API tốt hơn và có lưới an toàn ngay từ đầu, nhưng tốn thời gian ban đầu hơn - cần cân nhắc theo ngữ cảnh (code nghiệp vụ phức tạp nên TDD, code thử nghiệm/prototype có thể không cần).
Thực hành: Viết báo cáo so sánh: code viết bằng TDD (Ngày 202-203) vs code viết theo cách cũ (test sau) - về chất lượng thiết kế, thời gian, độ tự tin khi refactor.
Nhóm 5: Integration Testing (Ngày 206–209)
Ngày 206: Integration Test là gì
Mục tiêu: Phân biệt rõ Integration Test với Unit Test.
Lý thuyết: Integration test verify nhiều thành phần thật phối hợp đúng với nhau (không mock hết), thường chậm hơn và ít hơn unit test theo Test Pyramid.
Thực hành: Xác định trong Mini Web Framework (Giai đoạn 3), đâu là ranh giới nên test bằng unit test, đâu nên test bằng integration test.
Ngày 207: Integration Test với Database
Mục tiêu: Học cách test code có tương tác database mà không cần database production thật.
Lý thuyết: In-memory database (H2), Testcontainers (chạy database thật trong Docker container tạm cho test).
Thực hành: Viết integration test cho 1 repository layer, dùng Testcontainers khởi động PostgreSQL tạm thời cho test.
Ngày 208: Integration Test với HTTP API
Mục tiêu: Test toàn bộ 1 API endpoint từ request tới response.
Lý thuyết: Test client (
MockMvcở Java,TestClientở FastAPI/Python), test cả tầng routing + business logic + serialization.Thực hành: Viết integration test cho CRUD API
Taskđã xây ở Mini Web Framework, verify status code + response body.
Ngày 209: Lab - Integration Test cho Mini Web Framework
Mục tiêu: Hoàn thiện bộ test tích hợp cho project Giai đoạn 3.
Lý thuyết: Ôn lại kết hợp Testcontainers + test client cho 1 flow end-to-end trong phạm vi service.
Thực hành: Viết integration test đầy đủ cho flow tạo Task → lưu DB → trả response, chạy qua toàn bộ pipeline Router → Middleware → DI → Handler thật.
Nhóm 6: Contract Testing (Ngày 210–212)
Ngày 210: Giới thiệu Contract Testing
Mục tiêu: Hiểu vấn đề mà contract testing giải quyết.
Lý thuyết: E2E test giữa nhiều service tốn kém, chậm, dễ flaky - contract test verify "hợp đồng" giữa consumer và provider mà không cần cả hệ thống chạy cùng lúc.
Thực hành: Vẽ sơ đồ minh hoạ vấn đề khi 2 team (Order service, Payment service) đổi API mà không báo nhau, dẫn tới lỗi ở production.
Ngày 211: Consumer-Driven Contract - Pact
Mục tiêu: Hiểu mô hình contract test phổ biến nhất.
Lý thuyết: Consumer định nghĩa contract mong đợi, Provider verify contract đó trong CI của chính mình - không cần 2 service chạy cùng lúc.
Thực hành: Đọc tài liệu Pact, tóm tắt luồng hoạt động (consumer test → publish contract → provider verify).
Ngày 212: Lab - Contract Test giữa 2 service giả định
Mục tiêu: Thực hành contract test thật.
Lý thuyết: Ôn lại cấu trúc 1 pact file (request mong đợi, response mong đợi).
Thực hành: Viết consumer test định nghĩa contract cho API
GET /order/{id}, viết provider verification test dựa trên contract đó.
Nhóm 7: Property-Based Testing (Ngày 213–214)
Ngày 213: Giới thiệu Property-Based Testing
Mục tiêu: Hiểu cách tiếp cận test khác với example-based testing truyền thống.
Lý thuyết: Thay vì viết test cho từng input cụ thể, định nghĩa "property" (tính chất luôn đúng) và để framework tự sinh hàng trăm input ngẫu nhiên để kiểm tra.
Thực hành: Xác định 1 property cho hàm
sort()(VD: kết quả luôn có cùng độ dài với input, luôn tăng dần).
Ngày 214: Lab - Property Test
Mục tiêu: Thực hành viết property test thật.
Lý thuyết: Hypothesis (Python) hoặc jqwik (Java) - cách định nghĩa generator cho input.
Thực hành: Viết property test cho hàm
sort()tự viết, verify với hàng trăm input ngẫu nhiên do framework sinh ra; thử tìm 1 bug mà example-based test trước đó bỏ sót.
Nhóm 8: Coverage & Mutation Testing (Ngày 215–216)
Ngày 215: Code Coverage - Giới hạn thật sự
Mục tiêu: Hiểu coverage là chỉ số hữu ích nhưng dễ bị lạm dụng.
Lý thuyết: Line coverage vs branch coverage; 100% coverage không đảm bảo không có bug (test có thể chạy qua code mà không thực sự assert đúng).
Thực hành: Viết 1 ví dụ test đạt 100% line coverage nhưng vẫn bỏ sót bug rõ ràng, để thấy giới hạn của coverage.
Ngày 216: Mutation Testing
Mục tiêu: Học cách đo chất lượng test thực sự, không chỉ đo coverage.
Lý thuyết: Mutation testing tự động sửa nhỏ code (mutant, VD đổi
<thành<=), nếu test vẫn pass nghĩa là test đó yếu (không "giết" được mutant).Thực hành: Chạy công cụ mutation testing (PIT cho Java, mutmut cho Python) trên bộ test đã viết ở Ngày 196, xem mutation score và cải thiện test yếu.
Nhóm 9: Review (Ngày 217)
Ngày 217: Review & Retrospective Giai đoạn 4
Mục tiêu: Chốt lại thành 1 chiến lược testing cá nhân áp dụng được cho production.
Lý thuyết: Tổng hợp lại Test Pyramid, khi nào dùng unit/integration/contract/property test, testing strategy nên gắn với risk của từng phần hệ thống (không phải test mọi thứ như nhau).
Thực hành: Viết "Testing Strategy Playbook" cá nhân (1-2 trang): cho từng loại thành phần trong hệ thống (business logic thuần, tầng gọi external API, tầng database, tầng API endpoint) nên dùng loại test nào, tỷ lệ bao nhiêu.
Giai đoạn 5 - Concurrency (Ngày 218–266)
Mảng nhiều syllabus OOP bỏ qua. Học song song 3 ngôn ngữ để thấy 3 triết lý concurrency rất khác nhau, sau đó đào sâu internals chung.
Nhóm 1: Giới thiệu (Ngày 218–219)
Ngày 218: Concurrency vs Parallelism
Mục tiêu: Phân biệt 2 khái niệm hay bị dùng lẫn.
Lý thuyết: Concurrency = xử lý nhiều việc trong cùng khoảng thời gian (có thể xen kẽ trên 1 core); Parallelism = thực sự chạy đồng thời trên nhiều core.
Thực hành: Vẽ sơ đồ timeline minh hoạ khác biệt giữa 1 chương trình concurrent chạy trên 1 core vs chạy parallel trên 4 core.
Ngày 219: Tổng quan các mô hình Concurrency
Mục tiêu: Có bức tranh tổng thể trước khi học chi tiết từng ngôn ngữ.
Lý thuyết: Thread-based (shared memory), Process-based (isolated memory), Event-loop/async (single-threaded non-blocking), Actor model (preview, sẽ gặp lại ở Distributed Systems).
Thực hành: Lập bảng: mỗi mô hình phù hợp với loại workload nào (CPU-bound vs I/O-bound).
Nhóm 2: Java Concurrency (Ngày 220–229)
Ngày 220: Thread cơ bản
Mục tiêu: Tạo và điều khiển thread thủ công trong Java.
Lý thuyết:
Threadclass,Runnableinterface,start()vsrun(),join().Thực hành: Viết chương trình tạo 5 thread in số thứ tự của chúng, dùng
join()để đợi tất cả hoàn thành.
Ngày 221: Synchronization - synchronized keyword
Mục tiêu: Hiểu cách bảo vệ vùng dữ liệu chia sẻ khỏi race condition.
Lý thuyết: Intrinsic lock (monitor lock),
synchronizedmethod vssynchronizedblock.Thực hành: Viết bộ đếm
Counterbị race condition khi nhiều thread tăng cùng lúc, sửa bằngsynchronized.
Ngày 222: wait/notify
Mục tiêu: Hiểu cơ chế phối hợp thread ở tầng thấp trước khi dùng thư viện cao cấp hơn.
Lý thuyết:
wait()/notify()/notifyAll()phải gọi trong synchronized block, spurious wakeup.Thực hành: Viết bài toán Producer-Consumer đơn giản bằng
wait()/notify()thủ công (chưa dùngBlockingQueue).
Ngày 223: ExecutorService cơ bản
Mục tiêu: Chuyển từ quản lý thread thủ công sang thread pool.
Lý thuyết: Vì sao tạo thread thủ công tốn kém (chi phí tạo/huỷ thread) - ExecutorService quản lý pool tái sử dụng.
Thực hành: Viết lại ví dụ Ngày 220 dùng
ExecutorService.submit()thay vì tạoThreadthủ công.
Ngày 224: Các loại Thread Pool
Mục tiêu: Chọn đúng loại pool cho đúng workload.
Lý thuyết:
FixedThreadPool,CachedThreadPool,ScheduledThreadPool- khác nhau ở chiến lược tạo/tái sử dụng thread.Thực hành: Benchmark cùng 1 workload trên
FixedThreadPoolvàCachedThreadPool, so sánh hành vi khi workload tăng đột biến.
Ngày 225: Future & Callable
Mục tiêu: Lấy kết quả trả về từ task chạy bất đồng bộ.
Lý thuyết:
Callable<T>vsRunnable(có trả về giá trị),Future.get()blocking.Thực hành: Submit nhiều
Callabletính toán song song, thu kết quả quaFuture.get().
Ngày 226: CompletableFuture cơ bản
Mục tiêu: Học cách xử lý bất đồng bộ hiện đại, không cần block.
Lý thuyết:
thenApply/thenAccept/thenCompose, xây chuỗi xử lý bất đồng bộ không blocking.Thực hành: Viết chuỗi xử lý 3 bước bất đồng bộ (fetch data → transform → save) bằng
CompletableFuture.
Ngày 227: CompletableFuture nâng cao
Mục tiêu: Kết hợp nhiều future và xử lý lỗi.
Lý thuyết:
thenCombine,allOf/anyOf,exceptionally/handle.Thực hành: Viết ví dụ gọi 2 API song song rồi combine kết quả, thêm xử lý khi 1 trong 2 API lỗi.
Ngày 228: java.util.concurrent Collections
Mục tiêu: Dùng cấu trúc dữ liệu thread-safe có sẵn thay vì tự đồng bộ hoá.
Lý thuyết:
ConcurrentHashMap(segment locking),BlockingQueue(interface cho Producer-Consumer),CopyOnWriteArrayList.Thực hành: Viết lại Counter Ngày 221 dùng
AtomicInteger, so sánh với bảnsynchronized.
Ngày 229: Lab - Producer-Consumer với BlockingQueue
Mục tiêu: Áp dụng toàn bộ kiến thức Java Concurrency vào bài toán kinh điển.
Lý thuyết: Ôn lại
BlockingQueuetự xử lý wait/notify bên trong, an toàn hơn tự viết thủ công.Thực hành: Viết Producer-Consumer hoàn chỉnh với nhiều producer/consumer dùng
LinkedBlockingQueue, verify không mất/trùng dữ liệu.
Nhóm 3: Python Concurrency (Ngày 230–239)
Ngày 230: Threading cơ bản
Mục tiêu: Làm quen
threadingmodule.Lý thuyết:
Thread,Lock, cú pháp tương tự Java nhưng hành vi runtime khác biệt.Thực hành: Viết lại ví dụ đếm race condition (giống Ngày 221) bằng Python threading, sửa bằng
Lock.
Ngày 231: GIL - Global Interpreter Lock
Mục tiêu: Hiểu ràng buộc đặc thù của CPython.
Lý thuyết: GIL chỉ cho phép 1 thread thực thi Python bytecode tại 1 thời điểm - threading không giúp tăng tốc CPU-bound task trong CPython.
Thực hành: Benchmark 1 task CPU-bound (tính tổng số nguyên tố) chạy bằng nhiều thread, quan sát không có speedup (thậm chí chậm hơn single-thread).
Ngày 232: Khi nào Threading vẫn hữu ích
Mục tiêu: Hiểu GIL không có nghĩa là threading vô dụng.
Lý thuyết: GIL được nhả ra khi chờ I/O - threading vẫn hiệu quả cho I/O-bound task (đọc file, gọi network).
Thực hành: Benchmark 1 task I/O-bound (gọi nhiều HTTP request) bằng threading, quan sát speedup rõ rệt so với tuần tự.
Ngày 233: Multiprocessing cơ bản
Mục tiêu: Vượt qua giới hạn GIL cho CPU-bound task.
Lý thuyết:
Process,Pool- mỗi process có GIL riêng, chạy thực sự song song trên nhiều core.Thực hành: Viết lại benchmark Ngày 231 bằng
multiprocessing.Pool, quan sát speedup thực sự.
Ngày 234: Multiprocessing - Chia sẻ dữ liệu giữa Process
Mục tiêu: Hiểu process không share memory như thread, cần cơ chế riêng.
Lý thuyết:
Queue,Pipe,shared_memory/Value/Arraycho dữ liệu chia sẻ có kiểm soát.Thực hành: Viết Producer-Consumer giữa 2 process dùng
multiprocessing.Queue.
Ngày 235: Asyncio cơ bản
Mục tiêu: Làm quen mô hình concurrency thứ 3: event loop.
Lý thuyết: Coroutine (
async def),await, event loop chạy single-thread nhưng xử lý được nhiều I/O đồng thời.Thực hành: Viết 1 coroutine đơn giản mô phỏng I/O bằng
asyncio.sleep(), quan sát cách event loop xen kẽ nhiều coroutine.
Ngày 236: Asyncio - Task & gather
Mục tiêu: Chạy nhiều coroutine thực sự song song (về mặt I/O).
Lý thuyết:
asyncio.create_task()để schedule coroutine chạy nền,asyncio.gather()để đợi nhiều task cùng lúc.Thực hành: Viết 5 coroutine mô phỏng gọi API (sleep ngẫu nhiên), chạy song song bằng
gather, so sánh tổng thời gian với chạy tuần tự.
Ngày 237: Asyncio - I/O thực tế
Mục tiêu: Áp dụng asyncio vào tình huống thật, không chỉ
sleep().Lý thuyết: Thư viện async thực (
aiohttp), vì sao không thể trộn code blocking (requests) vào trong coroutine mà không mất lợi ích async.Thực hành: Viết chương trình gọi 10 HTTP request bằng
aiohttpchạy đồng thời, đo thời gian so với gọi tuần tự bằngrequests.
Ngày 238: So sánh Threading vs Multiprocessing vs Asyncio
Mục tiêu: Có tiêu chí rõ ràng chọn đúng công cụ cho đúng bài toán.
Lý thuyết: Threading (I/O-bound, cần shared state), Multiprocessing (CPU-bound), Asyncio (I/O-bound, số lượng connection lớn, chi phí thread cao).
Thực hành: Lập bảng quyết định cho 5 tình huống thực tế (web scraping, tính toán ma trận lớn, web server xử lý nhiều connection...).
Ngày 239: Lab - Web Scraper 3 cách tiếp cận
Mục tiêu: Thấy khác biệt thực tế qua benchmark trực tiếp.
Lý thuyết: Ôn lại toàn bộ Python Concurrency.
Thực hành: Viết cùng 1 web scraper (tải 50 trang) bằng threading, multiprocessing, và asyncio; so sánh thời gian chạy và giải thích kết quả.
Nhóm 4: C++ Concurrency (Ngày 240–249)
Ngày 240: std::thread cơ bản
Mục tiêu: Tạo và điều khiển thread trong C++.
Lý thuyết:
std::thread,join()/detach(), truyền tham số vào thread function.Thực hành: Viết chương trình tạo 5
std::thread, mỗi thread in ID của chính nó,join()toàn bộ trước khi kết thúcmain.
Ngày 241: std::mutex
Mục tiêu: Bảo vệ critical section bằng mutex thủ công.
Lý thuyết:
std::mutex,lock()/unlock(), nguy cơ quênunlock()khi có exception.Thực hành: Viết Counter bị race condition, sửa bằng
mutex.lock()/unlock()thủ công, cố tình gây lỗi quên unlock để thấy hậu quả.
Ngày 242: std::lock_guard & std::unique_lock
Mục tiêu: Áp dụng RAII cho quản lý lock, tránh lỗi Ngày 241.
Lý thuyết:
lock_guard(RAII đơn giản),unique_lock(linh hoạt hơn, hỗ trợcondition_variable).Thực hành: Viết lại Counter Ngày 241 bằng
lock_guard, verify lock luôn được giải phóng kể cả khi có exception.
Ngày 243: std::condition_variable
Mục tiêu: Phối hợp giữa các thread dựa trên điều kiện.
Lý thuyết:
condition_variable.wait()/notify_one()/notify_all(), tương đương wait/notify của Java nhưng cầnunique_lockđi kèm.Thực hành: Viết Producer-Consumer bằng
condition_variable+unique_lock.
Ngày 244: std::future & std::promise
Mục tiêu: Lấy kết quả từ thread bất đồng bộ.
Lý thuyết:
promiseđặt giá trị,futurelấy giá trị (blockingget()), tương đươngFuture/CompletableFuturebên Java.Thực hành: Viết ví dụ 1 thread tính toán, set kết quả vào
promise, thread chính lấy quafuture.get().
Ngày 245: std::async
Mục tiêu: Chạy task bất đồng bộ đơn giản hơn
thread+promisethủ công.Lý thuyết:
std::asynctự động trả vềfuture, có thể chạyasynchoặcdeferredtuỳ launch policy.Thực hành: Viết lại ví dụ Ngày 244 ngắn gọn hơn bằng
std::async.
Ngày 246: std::atomic
Mục tiêu: Thao tác lock-free cho các kiểu dữ liệu đơn giản.
Lý thuyết:
std::atomic<T>, compare-and-swap (CAS), khi nào atomic đủ dùng thay vì mutex.Thực hành: Viết lại Counter bằng
std::atomic<int>, benchmark so với bản dùngmutex.
Ngày 247: Memory Order trong C++
Mục tiêu: Hiểu các mức độ đảm bảo thứ tự bộ nhớ khi dùng atomic.
Lý thuyết:
memory_order_relaxed,acquire/release,seq_cst- trade-off giữa hiệu năng và tính đúng đắn.Thực hành: Đọc ví dụ code dùng
memory_order_relaxedsai cách gây bug, giải thích tại sao.
Ngày 248: Thread Pool tự viết - Concept
Mục tiêu: Thiết kế trước khi code, chuẩn bị cho project cuối giai đoạn.
Lý thuyết: Thread pool cần: task queue thread-safe, N worker thread lấy task từ queue, cơ chế shutdown an toàn.
Thực hành: Vẽ sơ đồ kiến trúc Thread Pool sẽ viết bằng C++.
Ngày 249: Lab - Thread Pool hoàn chỉnh
Mục tiêu: Hoàn thiện implementation thực tế.
Lý thuyết: Ôn lại
condition_variable+mutex+queuekết hợp cho task queue.Thực hành: Cài đặt
ThreadPoolvớisubmit(task)trả vềfuture, N worker cố định,shutdown()graceful.
Nhóm 5: Concurrency Internals (Ngày 250–257)
Ngày 250: Race Condition
Mục tiêu: Định nghĩa chính xác và học cách phát hiện.
Lý thuyết: Race condition xảy ra khi kết quả phụ thuộc vào thứ tự thực thi không xác định của nhiều thread truy cập dữ liệu chia sẻ.
Thực hành: Chạy lại ví dụ Counter chưa đồng bộ hoá (từ Ngày 221/230/241) nhiều lần, ghi lại kết quả sai khác nhau mỗi lần chạy.
Ngày 251: Deadlock
Mục tiêu: Hiểu 4 điều kiện cần để deadlock xảy ra.
Lý thuyết: Coffman conditions (Mutual Exclusion, Hold and Wait, No Preemption, Circular Wait).
Thực hành: Viết cố tình 1 chương trình deadlock (2 thread, 2 lock, lock theo thứ tự ngược nhau), dùng debugger xác nhận cả 2 thread đang bị block.
Ngày 252: Chiến lược phòng tránh Deadlock
Mục tiêu: Có công cụ thực tế để tránh deadlock trong code thật.
Lý thuyết: Lock ordering (luôn lock theo 1 thứ tự cố định), lock timeout (
tryLock), giảm phạm vi giữ lock.Thực hành: Sửa ví dụ deadlock Ngày 251 bằng lock ordering, verify không còn deadlock.
Ngày 253: Livelock & Starvation
Mục tiêu: Phân biệt 2 vấn đề dễ nhầm với deadlock.
Lý thuyết: Livelock (thread liên tục đổi trạng thái để tránh nhau nhưng không tiến triển), Starvation (1 thread không bao giờ được cấp tài nguyên do thread khác luôn ưu tiên hơn).
Thực hành: Viết ví dụ minh hoạ livelock (2 thread "nhường" nhau vô hạn), giải thích khác biệt với deadlock.
Ngày 254: Memory Visibility
Mục tiêu: Hiểu vì sao 1 thread có thể không thấy giá trị mới nhất do thread khác ghi.
Lý thuyết: CPU cache per-core, compiler reordering - nếu không có synchronization, không có gì đảm bảo thread khác thấy write kịp thời.
Thực hành: Viết ví dụ kinh điển: 1 thread set flag
true, thread khác loop chờ flag mà không dùngvolatile/synchronized, minh hoạ nguy cơ vòng lặp vô hạn (compiler tối ưu đọc từ register).
Ngày 255: Happens-Before - Java Memory Model
Mục tiêu: Hiểu quy tắc chính thức đảm bảo memory visibility trong Java.
Lý thuyết: Happens-before relationship, các nguồn tạo happens-before (
synchronized,volatile,Thread.start()/join()).Thực hành: Sửa ví dụ Ngày 254 (phiên bản Java) bằng
volatile, giải thích vì sao nó tạo happens-before.
Ngày 256: Happens-Before - Liên hệ C++ Memory Model
Mục tiêu: Thấy khái niệm tương đương ở C++ đã gặp Ngày 247.
Lý thuyết:
memory_order_acquire/releasechính là cách C++ biểu diễn happens-before một cách tường minh, chi tiết hơn Java.Thực hành: Lập bảng so sánh cơ chế đảm bảo visibility giữa Java (
volatile/synchronized) và C++ (memory_order).
Ngày 257: Lab - Phát hiện Race Condition bằng công cụ
Mục tiêu: Học cách phát hiện bug concurrency tự động thay vì chỉ đọc code.
Lý thuyết: ThreadSanitizer (C++), jcstress (Java) - công cụ chuyên phát hiện race condition mà test thông thường khó bắt được.
Thực hành: Chạy ThreadSanitizer hoặc jcstress trên 1 đoạn code cố tình có race condition, đọc báo cáo lỗi được sinh ra.
Nhóm 6: Project - Concurrent Task Scheduler (Ngày 258–266)
Ngày 258: Thiết kế kiến trúc Task Scheduler
Mục tiêu: Lên thiết kế tổng thể trước khi code.
Lý thuyết: Scheduler cần: task queue, worker pool, priority handling, retry, graceful shutdown.
Thực hành: Vẽ sơ đồ kiến trúc, chọn ngôn ngữ chính cho project (khuyến nghị Java vì có sẵn
java.util.concurrentphong phú).
Ngày 259: Task Queue Thread-Safe
Mục tiêu: Xây thành phần lưu trữ task trung tâm.
Lý thuyết: Ôn lại
BlockingQueue(Java) hoặc tự viết bằngmutex+condition_variable(C++).Thực hành: Cài đặt
TaskQueuehỗ trợ nhiều producer đẩy task, nhiều consumer lấy task an toàn.
Ngày 260: Worker Pool
Mục tiêu: Nhiều worker xử lý task song song từ queue.
Lý thuyết: Ôn lại Thread Pool đã xây Ngày 249 (nếu dùng C++) hoặc
ExecutorService(nếu dùng Java).Thực hành: Cài đặt N worker liên tục lấy task từ
TaskQueuevà thực thi, verify task được xử lý đúng, không bị lấy trùng bởi 2 worker.
Ngày 261: Task Priority
Mục tiêu: Hỗ trợ task quan trọng được xử lý trước.
Lý thuyết:
PriorityBlockingQueue(Java) hoặcpriority_queue+ đồng bộ hoá thủ công (C++).Thực hành: Thêm priority vào
Task, verify worker luôn lấy task priority cao nhất trước.
Ngày 262: Task Scheduling theo thời gian
Mục tiêu: Hỗ trợ task chạy trễ hoặc lặp lại định kỳ.
Lý thuyết: Delayed task (chạy sau X giây), periodic task (chạy lặp lại mỗi X giây) - tương tự
ScheduledExecutorService.Thực hành: Thêm khả năng schedule task chạy sau 1 khoảng delay, và task lặp lại định kỳ.
Ngày 263: Xử lý lỗi & Retry
Mục tiêu: Scheduler không được "chết" vì 1 task lỗi.
Lý thuyết: Retry với exponential backoff, giới hạn số lần retry, dead-letter (task thất bại vĩnh viễn cần lưu lại để xem xét).
Thực hành: Thêm cơ chế retry cho task thất bại, verify sau N lần retry thất bại thì task được đưa vào danh sách "failed" thay vì retry vô hạn.
Ngày 264: Graceful Shutdown
Mục tiêu: Dừng scheduler an toàn, không làm mất dữ liệu.
Lý thuyết: Graceful shutdown cần: ngừng nhận task mới, đợi task đang chạy hoàn thành (hoặc timeout), không kill thread giữa chừng.
Thực hành: Cài đặt
shutdown()cho scheduler, verify task đang chạy được hoàn thành trước khi chương trình thoát.
Ngày 265: Test cho Scheduler
Mục tiêu: Verify hành vi concurrency đúng, không chỉ đúng ở single-thread.
Lý thuyết: Ôn lại kỹ thuật test concurrency (chạy lại nhiều lần, dùng ThreadSanitizer/jcstress nếu cần, test race condition có chủ đích).
Thực hành: Viết test cho scheduler: nhiều producer đẩy task đồng thời, verify không mất task; test priority; test retry; test graceful shutdown.
Ngày 266: Review & Retrospective Giai đoạn 5
Mục tiêu: Tổng kết toàn bộ Concurrency.
Lý thuyết: Nhìn lại toàn bộ 3 mô hình (thread/process/async) và internals (race condition, deadlock, memory visibility) đã áp dụng vào Scheduler như thế nào.
Thực hành: Viết báo cáo retrospective, đánh giá những quyết định thiết kế concurrency đã đưa ra trong project, chỉ ra điểm có thể cải thiện thêm.