Đây là một trong những phần thực tiễn và “thức tỉnh” nhất của toàn bộ nội dung DDD — vì nó trả lời câu hỏi “DDD áp dụng được không trong dự án lộn xộn?” Câu trả lời là hoàn toàn có thể, và thậm chí còn nên áp dụng, miễn là từng bước một và đúng nơi đúng chỗ.
💤 1. Ảo tưởng Domain-Driven Design “hoàn hảo” & thực tế
Viễn cảnh “trong mơ”:
- Bạn bắt đầu một greenfield project (dự án mới hoàn toàn).
- Mọi người trong team đều hiểu rõ DDD, nói chuyện bằng ubiquitous language.
- Các bounded context rõ ràng, tách biệt hợp lý.
- Mọi quyết định thiết kế chiến thuật (tactical design) đều bám sát logic business.
- Codebase sạch sẽ, dễ hiểu, dễ mở rộng.
“Now wake up.” 😅
— Vlad Khononov
Hiện thực phần mềm:
- Phần lớn thời gian, bạn không làm greenfield mà là brownfield project – những hệ thống đã có, đã chạy thật, nhưng…
- Chúng đang chứa đầy:
- Legacy code
- Technical debt
- Big Ball of Mud
- Bạn không thể rewrite toàn bộ, và team bạn không phải ai cũng là DDD black belt.
🧠 2. Ngộ nhận phổ biến về DDD
Hiểu lầm | Thực tế |
---|---|
DDD chỉ dành cho dự án mới (greenfield) | ❌ Sai. DDD cực kỳ hữu dụng trong brownfield để dọn rác. |
Phải áp dụng tất cả các pattern mới gọi là DDD | ❌ Sai. Dùng từng phần cũng đã có giá trị. |
DDD là chuyện lớn, phải có buy-in từ sếp mới làm được | ❌ Không cần. Bạn có thể dùng ngay trong team nhỏ, hoặc chính trong code bạn viết. |
DDD không phải là tất cả hoặc không gì cả
— Vlad Khononov
🎯 3. Tại sao DDD đặc biệt hữu ích cho dự án legacy?
Vì những hệ thống ấy:
- Đã chứng minh có business value
- Nhưng hiện tại rối như canh hẹ
- Cần “làm lại” từng phần, không cần rewrite toàn bộ
DDD giúp:
- Xác định phần nào là core nên đầu tư
- Tách bounded context để giảm độ rối
- Áp dụng tactical pattern phù hợp độ phức tạp
- Khôi phục lại domain knowledge bị mất
🧭 Phân tích chiến lược: xác định business domain và subdomain types trong hệ thống hiện tại
🧭 1. Bắt đầu từ chiến lược kinh doanh
Trước khi nhảy vào refactor hay tách module, hãy bước lùi lại một bước và hiểu tổ chức bạn đang phục vụ:
- Công ty này đang kinh doanh gì?
- Khách hàng chính là ai?
- Công ty cạnh tranh với ai?
- Giá trị mà công ty cung cấp là gì?
- Điều gì làm công ty này khác biệt với đối thủ?
🎯 Trả lời được những câu hỏi này sẽ giúp bạn xác định subdomain loại nào là core — vì nó liên quan đến chiến lược cạnh tranh của tổ chức.
🧱 2. Phân tích cấu trúc tổ chức & xác định Subdomain
📊 Gợi ý từ sơ đồ tổ chức:
- Các phòng ban trong công ty thường phản ánh các subdomain nghiệp vụ.
- Hỏi kỹ:
- Mỗi bộ phận làm gì?
- Họ phối hợp với ai?
- Họ tạo giá trị gì?
🧬 3. Phân biệt các loại Subdomain
Loại Subdomain | Dấu hiệu nhận biết |
---|---|
Core | – Là “secret sauce” |
- Gắn liền với IP, thuật toán riêng
- Hệ thống tệ hại nhưng không ai dám đụng
- Không có sản phẩm off-the-shelf nào thay thế được
| Generic | – Dùng giải pháp có sẵn (SaaS, open-source, package…)
– Không tạo khác biệt so với đối thủ
| Supporting | – Không có giải pháp thay thế phù hợp
– Không tạo lợi thế cạnh tranh trực tiếp
– Code ít thay đổi, ít ai phàn nàn
💡 Đừng cố tìm hết mọi core subdomain. Chỉ cần xác định được những cái liên quan đến hệ thống bạn đang làm là đủ.
🧩 3. Khám phá thiết kế hiện tại
✅ Bắt đầu từ “high-level components”:
- Chưa cần là bounded context đúng nghĩa, chỉ cần:
- Module tách biệt
- Team làm riêng
- Có thể triển khai, kiểm thử riêng
📦 Kiểm tra:
- Mỗi module chứa subdomain nào?
- Dùng pattern nào: transaction script, active record, domain model…?
- Có đang dùng over-engineered solution không?
- Có module nào đáng lẽ nên đơn giản hơn?
🗺️ 5. Vẽ context map tạm thời
Xem hệ thống hiện tại như 1 tập các bounded context tạm thời, và:
- Vẽ ra mối quan hệ giữa các context
- Xác định pattern tích hợp giữa chúng (shared kernel, conformist, ACL…)
👉 Đây là bước để tìm ra:
- Các design decision chiến lược đang sai
- Các mô hình kỳ quặc bị rò rỉ từ hệ thống khác
- Team đang “chen chúc” làm cùng 1 module
🧠 Nhận diện mất mát domain knowledge
- Đặc biệt với core subdomain → càng dễ mất kiến thức
- Không ai còn hiểu code
- Đụng vào là sợ vỡ toàn hệ thống
💡 Giải pháp: Tổ chức EventStorming để:
- Khôi phục lại domain knowledge
- Tạo ra mô hình chung (ubiquitous language)
🔨 Chiến lược hiện đại hóa hệ thống – từ module sang bounded context
🛠️ 1. “Rewrite toàn bộ” – ý tưởng nguy hiểm
❌ Đừng cố rewrite hệ thống từ đầu!
✔️ Thay vào đó: “Think big, start small.”
Tác giả nhấn mạnh:
- “Big rewrites” thường thất bại vì:
- Mất quá nhiều thời gian
- Tốn chi phí
- Khó kiểm soát rủi ro
- Quản lý không thích vì: chưa xong đã cạn tiền
🧱 2. Bắt đầu từ ranh giới logic (logical boundaries)
👉 Không cần tách thành microservice vội.
🎯 Mục tiêu ban đầu:
- Cấu trúc lại codebase theo các subdomain
- Mỗi subdomain → module riêng, namespace riêng, package riêng
📌 Ví dụ:
Before:
app/
controllers/
services/
repositories/
utils/
After:
inventory/
api/
service/
model/
checkout/
api/
service/
model/
📈 Lợi ích:
- Dễ hiểu logic business nằm ở đâu
- Có thể tách dần ra bounded context vật lý (sau này nếu cần)

🧪 3. Phân tách các bounded context chiến lược
“Strategic modernization = extract what matters first.”
✅ Khi nào nên chuyển từ logic boundary → physical boundary?
Câu hỏi chiến lược | Nếu trả lời “có” → nên tách |
---|---|
Nhiều team cùng sửa 1 codebase? | ✔️ Tách để tránh đụng độ |
Các module đang dùng mô hình xung đột? | ✔️ Tách để giảm cognitive load |
Context nào đang gây khó cho integration? | ✔️ Tách để dùng proper integration pattern |
👉 Cách tách: trích bounded context từ module → repository, service riêng, rồi triển khai riêng biệt (ví dụ microservice hoặc package riêng biệt).
🧬 4. Chọn lại integration pattern phù hợp sau khi tách
Sau khi tách xong context, hãy xem lại cách chúng giao tiếp:
Trường hợp | Gợi ý pattern |
---|---|
Module bị ảnh hưởng khi hệ thống upstream thay đổi | → Dùng Open Host Service |
Logic bị lan truyền từ hệ thống legacy | → Dùng Anticorruption Layer |
Hai team không còn cộng tác hiệu quả | → Tách và dùng Customer–Supplier |
Một context phụ không còn quan trọng | → Cho đi theo Separate Ways |
🏗️ Refactor Tactical Design – Từng Bước Từ Transaction Script Đến Event Sourcing
🧱 1. Tránh nhảy cóc: từ đơn giản lên phức tạp một cách có chiến lược
❌ Không nên refactor từ
transaction script
hoặcactive record
→ thẳng sangevent-sourced domain model
.
Vì sao?
Lý do | Diễn giải |
---|---|
💥 Rủi ro cao | Rất dễ sai trong việc chọn aggregate boundary |
📉 Khó kiểm soát | Event sourcing cần mô hình domain rất rõ và chuẩn |
🔧 Không cần thiết ngay | Có thể áp dụng dần, bắt đầu từ domain model truyền thống |
🧭 2. Quy trình từng bước để refactor tactical design
✅ Bước 1: Từ Transaction Script → Active Record
- Khi xử lý dữ liệu bắt đầu phức tạp
- Dữ liệu cần map tốt hơn với storage
📌 Hành động:
- Nhận diện các bảng dữ liệu phức tạp
- Tạo các lớp ActiveRecord tương ứng
✅ Bước 2: Active Record → Domain Model
- Khi logic bắt đầu nhiều điều kiện, rule, ràng buộc
- Nhiều duplication, dữ liệu dễ inconsistency
📌 Cách làm:
- Tìm value object có thể tái sử dụng
- Đóng setter lại (
private set
) để bắt lỗi tại compile time - Gom logic về trong entity → tránh logic nằm rải rác ngoài service
// Trước player.Points *= 1 + bonus/100.0; // Sau player.ApplyBonus(bonus);
✅ Bước 3: Domain Model → Event-Sourced Domain Model
- Khi cần:
- Trace hành vi theo thời gian
- Phục hồi lại lịch sử state
- Audit / Analytics nâng cao
📌 Việc cần làm:
- Thay đổi trạng thái bằng cách emit event, không set trực tiếp
- Thiết kế lại mô hình để hỗ trợ ghi nhớ event
🧪 3. Một số lưu ý khi áp dụng Event Sourcing
Tình huống | Giải pháp |
---|---|
Không có lịch sử quá khứ | 👉 Tạo event giả lập từ trạng thái hiện tại (Generated Transition) |
Không rõ logic đã diễn ra | 👉 Tạo Migration Event: MigratedFromLegacy |
Dữ liệu legacy và hiện đại dùng chung DB | 👉 Tạm thời chia sẻ DB nhưng cần kế hoạch tách sau |
🧱 4. Giới thiệu mô hình Strangler Pattern
🪴 Strangler Fig – mô hình cây strangler phát triển từ cành rồi “bóp chết” cây chủ.
🎯 Áp dụng để:
- Triển khai một bounded context mới
- Dùng facade layer để route request giữa hệ thống cũ và mới
- Khi đủ hoàn thiện → xóa hệ thống cũ
💡 Cả hệ thống cũ và mới tạm thời có thể dùng chung DB (vi phạm DDD rule), nhưng có kế hoạch tách sớm.
🌱 Áp dụng Domain-Driven Design kiểu thực dụng (Pragmatic DDD)
💡 1. DDD không phải “tôn giáo”, mà là hộp công cụ
“Bạn không cần phải dùng tất cả pattern trong DDD để gọi là đang làm DDD.”
Thực tế:
- Có thể bạn không áp dụng được Event Sourcing
- Có thể bạn chưa tách được bounded context vật lý
- Có thể bạn chưa được “sếp” cho phép refactor
🎯 Nhưng nếu bạn:
- Phân tích domain cẩn thận
- Lựa chọn mô hình phù hợp
- Quyết định thiết kế dựa trên logic nghiệp vụ
→ Chính là bạn đang làm DDD!
📌 2. DDD không chỉ là Value Object hay Aggregate
❌ Quan niệm sai:
“DDD = viết nhiều Aggregate + Value Object + Repository”
✅ Thực tế:
“DDD = Để Business Domain điều khiển các quyết định thiết kế phần mềm.”
→ Tư duy DDD không nằm ở code structure, mà ở:
- Cách bạn hiểu domain
- Cách bạn giao tiếp với domain expert
- Cách bạn đưa quyết định technical để phản ánh nhu cầu business
🧰 3. Áp dụng DDD vào công việc hằng ngày, không cần sếp duyệt
🎯 Tư duy “Undercover DDD”
Kỹ thuật | Mô tả |
---|---|
✅ Dùng ubiquitous language | Gọi tên biến, class theo đúng thuật ngữ nghiệp vụ |
✅ Hỏi domain expert thường xuyên | Tranh thủ trò chuyện lúc đi ăn, cà phê… |
✅ Sắp xếp code theo subdomain | Không trộn tất cả class vào cùng thư mục |
✅ Đặt tên chính xác | InvoiceSentEvent thay vì Event123 |
✅ Lặng lẽ áp dụng EventStorming mini | Có thể chỉ cần sketch nhanh trong 30’ cùng PO |
🧠 4. Lập luận đúng cách khi thảo luận với team
Khi thảo luận design, đừng nói:
❌ “DDD nói phải làm thế này.”
✅ “Nếu mình để nhiều entity trong aggregate thì khó kiểm soát consistency.”
✅ “Nếu tách thành value object thì dễ tái sử dụng và đảm bảo tính bất biến.”
💬 Đưa ra lập luận logic, thay vì trích dẫn sách vở.
📌 5. Các kỹ thuật thuyết phục nhẹ nhàng
🌱 “Jedi mind trick” cho Event Sourcing
- Đừng bắt đầu bằng: “Chúng ta cần Event Sourcing!”
- Hãy nói: “Nếu anh/chị muốn truy lại lý do vì sao đơn hàng này bị huỷ, mình cần lưu lại tất cả thay đổi trạng thái, chứ không chỉ trạng thái cuối cùng.”
→ Domain expert thường tự yêu cầu event sourcing sau khi hiểu giá trị nó mang lại.
“Bán” DDD cho team và tổ chức
– Undercover Domain-Driven Design
🛍️ 1. Câu hỏi phổ biến nhất khi nói về DDD
“Nghe hay thật đấy…
nhưng làm sao bán được DDD cho team và sếp?”
Tác giả thừa nhận:
- Việc thuyết phục người khác áp dụng DDD là rất khó
- Đặc biệt là khi DDD kéo theo sự thay đổi lớn trong cách làm việc và tổ chức team
🧠 2. Sự thật: mọi developer đều đang “bán” thứ gì đó
“Thiết kế phần mềm cũng là một hình thức bán hàng.”
— Tác giả
- Bạn đang bán ý tưởng
- Bạn đang bán giải pháp
- Bạn đang bán cách tiếp cận thiết kế hệ thống
🎯 Nếu bạn muốn người khác theo, bạn cần:
- Logic rõ ràng
- Thuyết phục dựa trên lợi ích cụ thể
- Giao tiếp phù hợp với từng đối tượng (dev, PO, manager…)
🕶️ 3. Undercover Domain-Driven Design – Cách lan tỏa DDD mà không cần label
“Hãy để DDD là công cụ nghề nghiệp của bạn, không cần là chính sách tổ chức.”
✅ Cách thực hiện:
Việc bạn làm | Ý nghĩa |
---|---|
Giao tiếp bằng ngôn ngữ nghiệp vụ | Dùng ubiquitous language một cách tự nhiên |
Gắn bó với domain expert | Không cần workshop hoành tráng, chỉ cần trò chuyện chân thành |
Refactor nhỏ để logic tập trung hơn | Gieo mầm tư duy “aggregate” mà không gọi tên |
Từ chối các tên gọi kiểu DataHelper , MainService | Thay bằng Order , InvoiceProcessor … |
Dùng EventStorming mini | Vẽ nhanh 15 phút trên giấy cũng được! |
🎯 4. Kỹ thuật giao tiếp: đừng nói DDD, hãy nói lợi ích
Thay vì nói:
❌ “Mình nên dùng aggregate vì sách DDD nói vậy…”
Hãy nói:
✅ “Nếu không giới hạn transactional boundary, mình có thể gặp lỗi race condition.”
✅ “Tách như thế này giúp giảm logic duplication và bảo vệ consistency.”
🌱 5. Trồng cây DDD một cách âm thầm
Giống như cấy một hạt giống:
- Đừng cố làm cả vườn một lúc
- Hãy bắt đầu từ:
- Một class có tên tốt hơn
- Một buổi hỏi domain expert
- Một refactor nhỏ để gom logic lại
💬 6. Khi cần advocate cho Event Sourcing
Thay vì:
❌ “Chúng ta nên dùng event sourcing!”
Hãy hỏi:
✅ “Có khi nào anh/chị cần xem lại chuỗi hành động dẫn đến đơn hàng bị huỷ không?”
✅ “Có cần kiểm tra xem khách hàng đã thay đổi email mấy lần không?”
🎯 Khi domain expert nhận ra giá trị từ “time-based modeling” → chính họ sẽ ủng hộ Event Sourcing.
📌 Kết
✅ Hiểu rõ mục tiêu chiến lược của tổ chức. Từ đó vạch ra lộ trình hiện đại hóa hợp lý.
✅ Không rewrite toàn bộ → rủi ro lớn, giá trị chưa chắc tương xứng.
✅ Không vội “đốt cháy giai đoạn”. Refactor theo từng bước an toàn, có kiểm soát.
✅ “DDD không phải là việc dùng aggregate. DDD là để domain quyết định cách bạn thiết kế phần mềm.”
✅ DDD không phải là mục tiêu. DDD là phương tiện để bạn xây hệ thống đúng – vì đúng với business.
Để lại một bình luận
Bạn phải đăng nhập để gửi bình luận.