Khám Phá Tri Thức Miền
(Discovering Domain Knowledge)
"Thứ được đưa lên môi trường thực tế (production) chính là sự (hiểu lầm) của các nhà phát triển, chứ không phải tri thức của các chuyên gia miền."— Alberto Brandolini [1]
Trong chương trước, chúng ta đã bắt đầu khám phá các miền nghiệp vụ. Bạn đã học cách nhận diện miền nghiệp vụ của một công ty — tức lĩnh vực hoạt động của nó — và phân tích chiến lược cạnh tranh của công ty đó trên thương trường: đó là việc xác định ranh giới và phân loại các miền con (subdomains).
Chương này tiếp tục chủ đề phân tích miền nghiệp vụ nhưng ở một chiều không gian khác: chiều sâu (depth). Chương này tập trung vào những gì diễn ra bên trong một miền con: chức năng kinh doanh và logic nghiệp vụ nội tại của nó. Bạn sẽ được học công cụ cốt lõi của Thiết kế Hướng Miền (DDD) phục vụ việc giao tiếp hiệu quả và chia sẻ tri thức: Ngôn ngữ chung phổ quát (Ubiquitous Language). Ở phần này, chúng ta sẽ sử dụng nó để tìm hiểu cặn kẽ những chi tiết tinh vi của miền nghiệp vụ. Về sau trong cuốn sách, chúng ta sẽ tận dụng chính ngôn ngữ này để mô hình hóa và triển khai logic nghiệp vụ vào mã nguồn phần mềm.
Các Vấn Đề Kinh Doanh (Business Problems)
Các hệ thống phần mềm mà chúng ta đang xây dựng bản chất là những giải pháp cho các vấn đề kinh doanh (business problems). Trong ngữ cảnh này, từ "vấn đề" (problem) không giống như một bài toán số học hay một câu đố mẹo mà bạn có thể giải xong một lần là hoàn thành mãi mãi.
Trong ngữ cảnh của các miền nghiệp vụ, "vấn đề" mang một ý nghĩa rộng lớn hơn nhiều. Một vấn đề kinh doanh có thể là những thách thức liên quan đến:
- Tối ưu hóa các luồng công việc và quy trình nghiệp vụ (optimizing workflows and processes).
- Giảm thiểu tối đa lao động thủ công tốn kém (minimizing manual labor).
- Quản trị và phân bổ hiệu quả các nguồn lực (managing resources).
- Hỗ trợ đưa ra các quyết định kinh doanh chính xác (supporting decisions).
- Quản lý và khai thác dữ liệu (managing data), cùng rất nhiều khía cạnh vận hành khác.
Các vấn đề kinh doanh xuất hiện ở cả hai cấp độ: cấp độ miền nghiệp vụ tổng thể (business domain) và cấp độ miền con (subdomain). Mục tiêu của cả công ty là cung cấp một giải pháp cho các vấn đề của khách hàng.
Quay trở lại ví dụ về công ty FedEx trong Chương 1: Khách hàng của công ty này có nhu cầu vận chuyển bưu kiện trong những khung thời gian nghiêm ngặt, vì vậy FedEx tối ưu hóa toàn diện quy trình vận chuyển để giải quyết bài toán đó.
Trong khi đó, các miền con (subdomains) là những miền vấn đề ở mức độ chi tiết hơn (finer-grained problem domains) với mục tiêu cung cấp giải pháp cho những năng lực kinh doanh cụ thể:
- Một miền con quản trị tri thức (knowledge management subdomain) tối ưu hóa quy trình lưu trữ và truy xuất thông tin.
- Một miền con quyết toán (clearing subdomain) tối ưu hóa quy trình thực thi các giao dịch tài chính an toàn.
- Một miền con kế toán (accounting subdomain) theo dõi chính xác các dòng tiền và nguồn vốn của công ty.
Khám Phá Tri Thức (Knowledge Discovery)
Để thiết kế nên một giải pháp phần mềm hiệu quả, chúng ta bắt buộc phải nắm bắt được ít nhất là những tri thức nền tảng của miền nghiệp vụ. Như chúng ta đã thảo luận trong Chương 1, tri thức này thuộc quyền sở hữu của các chuyên gia miền (domain experts): công việc và trách nhiệm của họ là chuyên môn hóa và thấu hiểu mọi ngóc ngách tinh vi của miền kinh doanh đó.
Chúng ta tuyệt nhiên không nên, và cũng không thể nào trở thành chuyên gia miền. Tuy nhiên, điều tối quan trọng là chúng ta phải hiểu được các chuyên gia miền và sử dụng chính xác các thuật ngữ kinh doanh mà họ sử dụng.
Để hoạt động thực sự hiệu quả, phần mềm phải mô phỏng lại đúng mô hình tư duy (mental models) của chuyên gia miền về vấn đề cần giải quyết. Nếu thiếu đi sự thấu hiểu về bài toán kinh doanh và những lý do ẩn sau các yêu cầu nghiệp vụ, giải pháp của chúng ta sẽ bị hạn chế ở mức đơn thuần là "dịch máy móc" các tài liệu yêu cầu thành mã nguồn.
Điều gì sẽ xảy ra nếu tài liệu yêu cầu bỏ sót một trường hợp biên (edge case) hiểm hóc? Hay nếu tài liệu thất bại trong việc mô tả đúng một khái niệm nghiệp vụ cốt lõi, khiến chúng ta bị giới hạn năng lực trong việc thiết kế một kiến trúc có thể hỗ trợ các yêu cầu kinh doanh trong tương lai?
Đúng như Alberto Brandolini đã đúc kết sâu sắc: "Phát triển phần mềm là một quá trình học hỏi; mã nguồn hoạt động được chỉ là một tác dụng phụ (software development is a learning process; working code is a side effect)." Sự thành bại của một dự án phần mềm phụ thuộc hoàn toàn vào hiệu quả chia sẻ tri thức giữa các chuyên gia miền và các kỹ sư phần mềm. Chúng ta bắt buộc phải hiểu thấu đáo vấn đề thì mới có thể giải quyết được nó.
Và để chia sẻ tri thức hiệu quả giữa chuyên gia miền và kỹ sư phần mềm, chúng ta cần một phương thức giao tiếp hiệu quả. Hãy cùng nhìn nhận những rào cản phổ biến đối với việc giao tiếp trong các dự án phần mềm hiện nay.
Giao Tiếp Trong Dự Án (Communication)
Có thể khẳng định chắc chắn rằng hầu hết mọi dự án phần mềm đều đòi hỏi sự cộng tác mật thiết giữa nhiều bên liên quan thuộc các vai trò khác nhau: chuyên gia miền (domain experts), chủ sở hữu sản phẩm (product owners - PO), kỹ sư phần mềm (engineers), nhà thiết kế UI/UX, quản lý dự án (project managers - PM), chuyên viên kiểm thử (testers / QA), chuyên viên phân tích nghiệp vụ (business analysts - BA), và nhiều vai trò khác.
Như trong bất kỳ nỗ lực cộng tác tập thể nào, kết quả đầu ra phụ thuộc hoàn toàn vào việc tất cả các bên có thể làm việc ăn khớp với nhau tốt đến mức nào. Nghiên cứu thực nghiệm về các yếu tố quyết định sự thành bại của các dự án phần mềm đã chứng minh rằng: giao tiếp hiệu quả là điều kiện tiên quyết cho việc chia sẻ tri thức và thành công của dự án [2].
Thế nhưng, bất chấp tầm quan trọng sống còn đó, giao tiếp hiệu quả lại là điều hiếm khi được chứng kiến trong các dự án phần mềm thực tế.
Thông thường, những người làm kinh doanh và các kỹ sư phần mềm hoàn toàn không có bất kỳ sự tương tác trực tiếp nào với nhau. Thay vào đó, tri thức miền bị "đẩy xuống" (pushed down) từ các chuyên gia miền tới các kỹ sư. Nó được chuyển giao thông qua những người đóng vai trò trung gian, hay những "thông dịch viên" — chẳng hạn như chuyên viên phân tích nghiệp vụ/hệ thống, chủ sản phẩm, và quản lý dự án. Luồng chia sẻ tri thức phổ biến này được minh họa trong Hình 2-1.
Trong vòng đời phát triển phần mềm truyền thống, tri thức nghiệp vụ được "dịch" sang một hình thức thân thiện với kỹ sư hơn, được gọi là mô hình phân tích (analysis model). Mô hình này thực chất chỉ là một bản mô tả các yêu cầu của hệ thống (system requirements) chứ không phải là sự thấu hiểu thực sự về miền nghiệp vụ ẩn sau nó. Mặc dù ý định ban đầu có thể là tốt, nhưng sự trung gian này lại cực kỳ nguy hại cho việc chia sẻ tri thức.
Trong bất kỳ quá trình dịch thuật trung gian nào, thông tin chắc chắn sẽ bị thất thoát (information is lost). Trong trường hợp này, tri thức miền vốn là điều cốt tử để giải quyết bài toán kinh doanh đã bị rơi rụng trên đường truyền đến tay các kỹ sư phần mềm.
Và đây thậm chí chưa phải là lần "dịch thuật" duy nhất trong một dự án điển hình! Mô hình phân tích tiếp tục được dịch sang mô hình thiết kế phần mềm (software design model) — thể hiện qua tài liệu thiết kế phần mềm (Software Design Document - SDD). Rồi tài liệu thiết kế đó lại tiếp tục được dịch sang mô hình triển khai (implementation model), tức chính là các dòng mã nguồn (source code).
Và như một lẽ thường tình, các tài liệu văn bản sẽ trở nên lỗi thời rất nhanh chóng. Khi đó, chính mã nguồn lại bị dùng làm công cụ để truyền đạt tri thức miền kinh doanh cho những kỹ sư phần mềm nhận trách nhiệm bảo trì dự án sau này. Hình 2-2 minh họa chuỗi biến đổi mô hình liên tục cần thiết để tri thức miền được hiện thực hóa thành code.
Căn Bệnh "Trò Chơi Truyền Tin" (The Telephone Game)
Một quy trình phát triển phần mềm trung gian như vậy giống hệt như trò chơi dân gian của trẻ con mang tên Trò chơi truyền tin (Telephone Game) [3]: Các người chơi xếp thành một hàng dài, người đầu tiên nghĩ ra một thông điệp rồi thì thầm vào tai người thứ hai. Người thứ hai lại thì thầm thông điệp mình nghe được vào tai người thứ ba, và cứ thế tiếp diễn. Người cuối cùng sẽ nói to thông điệp mình nghe được cho cả nhóm. Người đầu tiên sau đó so sánh thông điệp gốc với phiên bản cuối cùng. Mặc dù mục tiêu là truyền tải cùng một thông điệp, nhưng thông điệp ấy thường bị méo mó, tam sao thất bản, và người cuối cùng nhận được một nội dung khác biệt một trời một vực so với bản gốc!
Trong phần mềm, sự bóp méo thông tin này dẫn đến việc các kỹ sư phần mềm:
- Triển khai sai giải pháp (implementing the wrong solution) cho một bài toán đúng, HOẶC
- Triển khai giải pháp đúng cho một bài toán hoàn toàn sai (the right solution but to the wrong problems).
Trong cả hai trường hợp, kết cục cuối cùng đều giống hệt nhau: một dự án phần mềm thất bại thảm hại.
Thiết kế Hướng Miền (DDD) đề xuất một con đường tốt đẹp hơn nhiều để đưa tri thức từ các chuyên gia miền đến với các kỹ sư phần mềm: bằng cách sử dụng một Ngôn ngữ chung phổ quát (Ubiquitous Language).
Ngôn Ngữ Chung Phổ Quát Là Gì? (What Is a Ubiquitous Language?)
Việc sử dụng một ngôn ngữ chung phổ quát (ubiquitous language) là phương pháp thực hành mang tính chất nền tảng số một của Thiết kế Hướng Miền. Ý tưởng đằng sau nó cực kỳ giản dị và trực diện:
Nếu các bên cần giao tiếp với nhau một cách hiệu quả, thì thay vì phụ thuộc vào các khâu dịch thuật trung gian đầy rủi ro, tất cả mọi người bắt buộc phải nói cùng một ngôn ngữ.
Mặc dù khái niệm này thoạt nghe hoàn toàn là lẽ thường tình (common sense), nhưng đúng như đại văn hào Voltaire từng nói: "Lẽ thường lại không hề bình thường chút nào" (Common sense is not so common). Vòng đời phát triển phần mềm truyền thống bao hàm những khâu dịch thuật liên tiếp:
- Tri thức miền biến thành mô hình phân tích (Analysis model)
- Mô hình phân tích biến thành các bản đặc tả yêu cầu (Requirements)
- Các bản yêu cầu biến thành thiết kế hệ thống (System design)
- Thiết kế hệ thống biến thành mã nguồn (Source code)
Thay vì liên tục dịch qua dịch lại tri thức miền qua từng nấc trung gian, Thiết kế Hướng Miền kêu gọi việc vun đắp và sử dụng một ngôn ngữ duy nhất xuyên suốt để mô tả miền nghiệp vụ: Ngôn ngữ chung phổ quát (Ubiquitous Language).
Tất cả các bên liên quan tham gia vào dự án — từ kỹ sư phần mềm, chủ sản phẩm (PO), chuyên gia miền, nhà thiết kế UI/UX — đều phải sử dụng ngôn ngữ chung này khi thảo luận về miền nghiệp vụ. Điều quan trọng nhất là: các chuyên gia miền phải cảm thấy hoàn toàn tự nhiên và thoải mái khi sử dụng ngôn ngữ chung này để tư duy và lập luận về nghiệp vụ của họ; bởi vì ngôn ngữ này đại diện cho cả miền nghiệp vụ lẫn mô hình tư duy thực tế của các chuyên gia.
Chỉ thông qua việc sử dụng liên tục, bền bỉ ngôn ngữ chung phổ quát và các thuật ngữ chuẩn xác của nó, sự hiểu biết đồng thuận (shared understanding) giữa tất cả các thành viên trong dự án mới có thể được vun trồng và phát triển vững chắc.
Ngôn Ngữ Của Nghiệp Vụ (Language of the Business)
Cần phải nhấn mạnh một cách dứt khoát rằng: Ngôn ngữ chung phổ quát chính là NGÔN NGỮ CỦA NGHIỆP VỤ (Language of the Business). Do đó, nó chỉ được phép bao gồm các thuật ngữ liên quan đến miền kinh doanh mà thôi.
Kịch Bản Nghiệp Vụ vs Ngôn Từ Kỹ Thuật (Scenarios)
Giả sử chúng ta đang xây dựng một hệ thống quản lý chiến dịch quảng cáo trực tuyến (advertising campaign management system). Hãy đặt lên bàn cân hai cách diễn đạt sau:
- "Một chiến dịch quảng cáo có thể hiển thị nhiều tài nguyên sáng tạo (creative materials) khác nhau."
- "Một chiến dịch chỉ có thể được phát hành (published) nếu có ít nhất một vị trí hiển thị (placement) của nó đang kích hoạt."
- "Hoa hồng bán hàng (sales commissions) được hạch toán sau khi các giao dịch được phê duyệt."
→ Những câu nói này phản ánh chính xác lăng kính tư duy của chuyên gia miền. Mọi bên liên quan đều thấu hiểu ngay tức khắc.
- "Thẻ iframe quảng cáo hiển thị một tệp tin HTML."
- "Một campaign chỉ có thể publish nếu nó có ít nhất một bản ghi liên kết trong bảng active-placements."
- "Hoa hồng bán hàng dựa trên việc join các bản ghi tương quan giữa bảng transactions và bảng approved-sales."
→ Những câu nói này thuần tính kỹ thuật cài đặt. Chuyên gia kinh doanh sẽ hoàn toàn mù mờ và không thể xác minh được tính đúng đắn của logic.
Nếu các kỹ sư phần mềm chỉ làm quen với góc nhìn kỹ thuật hướng giải pháp (solution-oriented view) như ở cột bên phải, họ sẽ không bao giờ có thể hiểu trọn vẹn bản chất của logic nghiệp vụ hoặc lý do sâu xa vì sao hệ thống lại phải vận hành như vậy. Điều này sẽ bóp nghẹt năng lực của họ trong việc mô hình hóa và hiện thực hóa một giải pháp phần mềm thực sự hiệu quả.
Tính Nhất Quán (Consistency)
Ngôn ngữ chung phổ quát bắt buộc phải chuẩn xác (precise) và nhất quán (consistent). Nó phải xóa bỏ hoàn toàn nhu cầu phải suy đoán vô căn cứ, và phải làm cho mọi logic của miền nghiệp vụ trở nên hiển ngôn, tường minh (explicit).
Bởi vì sự mơ hồ mập mờ chính là kẻ thù phá hủy giao tiếp, mỗi thuật ngữ trong ngôn ngữ chung phổ quát phải có một và chỉ một ý nghĩa duy nhất. Hãy cùng xem xét hai cạm bẫy ngôn từ thường gặp và cách khắc phục:
1. Các Thuật Ngữ Mơ Hồ, Đa Nghĩa (Ambiguous Terms)
Giả sử trong một miền nghiệp vụ, từ "policy" (chính sách / điều khoản) lại mang nhiều tầng ý nghĩa khác nhau: đối với bộ phận pháp chế, nó có nghĩa là một quy tắc tuân thủ pháp lý (regulatory rule); trong khi đối với bộ phận kinh doanh bảo hiểm, nó lại có nghĩa là một hợp đồng bảo hiểm ký với khách hàng (insurance contract).
Khi hai con người trò chuyện trực tiếp với nhau, họ có thể ngầm hiểu được ý nghĩa chính xác dựa vào ngữ cảnh giao tiếp. Tuy nhiên, phần mềm máy tính thì không có năng lực tự đối phó với sự mơ hồ. Việc cố gắng mô hình hóa một thực thể "Policy" chung chạ trong mã nguồn sẽ trở nên vô cùng cồng kềnh, rối rắm và đầy rẫy lỗi tiềm tàng.
Ngôn ngữ chung phổ quát đòi hỏi mỗi thuật ngữ chỉ được mang một ý nghĩa duy nhất. Do đó, từ "policy" phải được bóc tách và mô hình hóa tường minh thành hai thuật ngữ độc lập: quy tắc tuân thủ (regulatory rule) và hợp đồng bảo hiểm (insurance contract).
2. Các Thuật Ngữ Đồng Nghĩa (Synonymous Terms)
Hai thuật ngữ khác nhau không được phép sử dụng thay thế lẫn nhau trong một ngôn ngữ chung phổ quát.
Ví dụ: Trong rất nhiều hệ thống, người ta hay dùng từ chung chung là user (người dùng). Tuy nhiên, nếu quan sát kỹ cách dùng từ của các chuyên gia miền, bạn sẽ nhận ra rằng họ thường xuyên dùng lẫn lộn giữa: user, visitor (khách truy cập), administrator (quản trị viên), account (tài khoản), v.v.
Các thuật ngữ đồng nghĩa thoạt nhìn có vẻ vô hại. Thế nhưng trong hầu hết các trường hợp, chúng thực chất đang biểu thị cho những khái niệm nghiệp vụ hoàn toàn khác nhau. Trong ví dụ này, dù cả "visitor" và "account" về mặt kỹ thuật đều là những người dùng hệ thống; nhưng trong thực tế nghiệp vụ:
- Một visitor là người dùng chưa đăng ký; dữ liệu hành vi của họ chủ yếu được sử dụng cho mục đích phân tích thị trường (analytics).
- Trong khi một account đại diện cho một người dùng đã đăng ký chính thức, trực tiếp tương tác và sử dụng các chức năng cốt lõi của hệ thống.
Cách tiếp cận đúng đắn là phải sử dụng tường minh từng thuật ngữ trong đúng ngữ cảnh cụ thể của nó. Việc thấu hiểu sự khác biệt bản chất giữa các thuật ngữ cho phép chúng ta xây dựng nên những mô hình và mã nguồn cài đặt đơn giản hơn, trong sáng hơn và chính xác hơn rất nhiều.
Mô Hình Của Miền Nghiệp Vụ (Model of the Business Domain)
Bây giờ, hãy cùng xem xét ngôn ngữ chung phổ quát dưới một lăng kính cốt lõi khác của DDD: nghệ thuật mô hình hóa (modeling).
Mô Hình Là Gì? (What Is a Model?)
"Mô hình là một sự biểu diễn đơn giản hóa của một sự vật hoặc hiện tượng, cố ý nhấn mạnh vào một số khía cạnh nhất định trong khi bỏ qua các khía cạnh khác. Đó là sự trừu tượng hóa nhằm phục vụ một mục đích sử dụng cụ thể."— Rebecca Wirfs-Brock [4]
Một mô hình không phải là một bản sao chép y nguyên thế giới thực, mà là một cấu trúc do con người kiến tạo nên để giúp chúng ta hiểu và xử lý các hệ thống phức tạp trong thế giới thực.
Một ví dụ kinh điển nhất cho khái niệm mô hình chính là bản đồ (map). Bất kỳ tấm bản đồ nào cũng đều là một mô hình: bao gồm bản đồ giao thông đường bộ, bản đồ địa hình đồi núi, bản đồ múi giờ thế giới, bản đồ hàng hải, bản đồ hàng không, và bản đồ các tuyến tàu điện ngầm — như được minh họa trong Hình 2-3.
Không một tấm bản đồ nào trong số này đại diện cho toàn bộ mọi chi tiết của hành tinh chúng ta. Thay vào đó, mỗi tấm bản đồ chỉ chứa đựng vừa đủ lượng thông tin cần thiết để phục vụ cho mục đích cụ thể của nó — tức bài toán cụ thể mà nó được sinh ra để giải quyết.
Mô Hình Hóa Hiệu Quả (Effective Modeling)
Mọi mô hình sinh ra đều có một mục đích, và một mô hình hiệu quả chỉ chứa đựng những chi tiết cần thiết để hoàn thành mục đích đó.
Ví dụ, bạn sẽ không bao giờ thấy các ga tàu điện ngầm hiển thị trên một tấm bản đồ thế giới. Mặt khác, bạn không thể sử dụng sơ đồ tàu điện ngầm để đo đạc cự ly khoảng cách địa lý thực tế giữa hai địa điểm. Mỗi tấm bản đồ chỉ cung cấp chính xác những thông tin mà nó được kỳ vọng sẽ cung cấp.
Điểm mấu chốt này rất đáng được nhắc lại nhiều lần: Một mô hình hữu ích KHÔNG PHẢI là một bản sao chép thực tế. Thay vào đó, mô hình sinh ra là để giải quyết một bài toán cụ thể mà phần mềm hướng tới. Trong những chương tiếp theo, bạn sẽ thấy rõ ngôn ngữ chung phổ quát định hướng các quyết định thiết kế và lập trình ở mức độ chi tiết sâu sắc như thế nào.
Giao tiếp hiệu quả giữa đội ngũ kỹ thuật và chuyên gia miền có ý nghĩa sống còn. Tầm quan trọng của giao tiếp tăng tỷ lệ thuận với độ phức tạp của miền nghiệp vụ. Miền nghiệp vụ càng phức tạp, việc mô hình hóa và triển khai logic của nó vào mã nguồn càng cam go. Thậm chí chỉ một hiểu lầm nhỏ về miền nghiệp vụ hoặc các nguyên lý nền tảng của nó cũng sẽ vô tình dẫn đến việc tạo ra một hệ thống đầy rẫy lỗi nghiêm trọng. Con đường đáng tin cậy duy nhất để kiểm chứng sự hiểu biết của chúng ta là thường xuyên trò chuyện với các chuyên gia miền, và làm điều đó bằng chính ngôn ngữ mà họ hiểu: Ngôn ngữ của nghiệp vụ.
Nỗ Lực Liên Tục (Continuous Effort)
Việc hình thành một ngôn ngữ chung phổ quát đòi hỏi sự tương tác trực tiếp, thường xuyên với những người nắm giữ tri thức tự nhiên: các chuyên gia miền. Chỉ có tương tác với các chuyên gia miền thực thụ mới có thể vạch trần những chỗ sai lệch, những giả định ngộ nhận, hoặc sự hiểu sai tổng thể về bài toán kinh doanh.
Mọi thành viên tham gia dự án phải kiên trì sử dụng ngôn ngữ chung phổ quát trong tất cả các cuộc trao đổi liên quan đến dự án nhằm lan tỏa tri thức và xây dựng một sự hiểu biết đồng thuận. Ngôn ngữ này phải được củng cố liên tục xuyên suốt dự án: từ các bản mô tả yêu cầu, kịch bản kiểm thử, tài liệu kỹ thuật, và ngay cả trong chính mã nguồn phần mềm cũng phải nói lên ngôn ngữ này.
Quan trọng nhất, việc vun đắp ngôn ngữ chung là một quá trình liên tục không ngừng nghỉ (ongoing process). Nó phải liên tục được kiểm chứng và tiến hóa. Việc sử dụng ngôn ngữ hàng ngày theo thời gian sẽ làm hé lộ những hiểu biết sâu sắc hơn về miền kinh doanh. Khi những bước đột phá tri thức (breakthroughs) như vậy xảy ra, ngôn ngữ chung phổ quát bắt buộc phải tiến hóa để bắt kịp với tri thức miền mới được phát hiện.
Các Công Cụ Hỗ Trợ (Tools)
Có những công cụ và công nghệ có thể hỗ trợ đắc lực cho quy trình ghi nhận và quản lý ngôn ngữ chung phổ quát trong dự án:
1. Bảng Thuật Ngữ Dạng Wiki (Wiki-based Glossary)
Một trang Wiki nội bộ (như Confluence, Notion, GitHub Wiki) có thể được dùng làm Bảng giải nghĩa thuật ngữ (Glossary) để ghi chép và lưu trữ ngôn ngữ chung. Bảng thuật ngữ này giúp ích rất nhiều cho quá trình hòa nhập (onboarding) của các thành viên mới, đóng vai trò là nơi tra cứu tin cậy về các khái niệm nghiệp vụ của dự án.
Điều cốt yếu là việc bảo trì bảng thuật ngữ này phải là nỗ lực chung của toàn bộ tập thể. Bất cứ khi nào ngôn ngữ chung có sự thay đổi hay xuất hiện khái niệm mới, tất cả các thành viên trong nhóm đều được khuyến khích chủ động cập nhật bảng thuật ngữ. Điều này hoàn toàn trái ngược với cách làm quan liêu tập quyền, nơi chỉ có trưởng nhóm (team lead) hay kiến trúc sư mới có quyền chỉnh sửa.
Mặc dù bảng thuật ngữ rất hữu ích, nhưng nó có một giới hạn cố hữu: Bảng thuật ngữ chỉ phát huy tác dụng tốt nhất đối với các "DANH TỪ" (tên gọi các thực thể, quy trình, vai trò...). Dù danh từ rất quan trọng, nhưng việc nắm bắt "HÀNH VI" (behavior) mới là yếu tố quyết định.
Hành vi không đơn thuần là danh sách các động từ gắn liền với danh từ, mà chính là logic nghiệp vụ thực tế, với các quy tắc, các giả định và các điều kiện bất biến (invariants) đi kèm. Những khái niệm hành vi sống động như vậy rất khó để diễn giải trọn vẹn trong một bảng thuật ngữ tĩnh. Do đó, bảng thuật ngữ nên được kết hợp song hành với các công cụ bắt giữ hành vi tốt hơn: chẳng hạn như các trường hợp sử dụng (Use Cases) hoặc các bài kiểm thử bằng ngôn ngữ Gherkin.
2. Kiểm Thử Tự Động Bằng Ngôn Ngữ Gherkin (BDD)
Các bài kiểm thử tự động được viết bằng ngôn ngữ Gherkin (cú pháp Given-When-Then trong Cucumber/SpecFlow) không chỉ là công cụ tuyệt vời để thể hiện ngôn ngữ chung phổ quát, mà còn là chiếc cầu nối kỳ diệu xóa nhòa khoảng cách giữa chuyên gia miền và kỹ sư phần mềm.
Các chuyên gia miền có thể đọc trực tiếp các kịch bản kiểm thử này bằng ngôn ngữ tự nhiên và xác minh xem hành vi dự kiến của hệ thống đã chuẩn xác hay chưa. Hãy xem xét ví dụ sau được viết bằng Gherkin cho hệ thống WolfDesk:
Given Khách hàng Vincent Jules gửi một ca hỗ trợ mới với nội dung:
"""
Tôi cần trợ giúp cấu hình dịch vụ AWS Infinidash
"""
When Phiếu hỗ trợ này được phân công cho nhân viên Mr. Wolf
Then Nhân viên hỗ trợ sẽ nhận được một thông báo về phiếu hỗ trợ mới này
Việc quản lý một bộ kiểm thử bằng Gherkin đôi khi có thể gặp nhiều thách thức, đặc biệt là ở giai đoạn đầu của dự án. Tuy nhiên, nó hoàn toàn xứng đáng với công sức bỏ ra đối với các miền nghiệp vụ có độ phức tạp cao.
[5] Lưu ý từ tác giả: Nhưng xin bạn đừng bao giờ rơi vào cái bẫy ảo tưởng rằng các chuyên gia miền sẽ tự tay ngồi viết các kịch bản kiểm thử Gherkin này! Đó là nhiệm vụ cộng tác của kỹ sư và kiểm thử viên dựa trên lời kể của chuyên gia miền.
3. Công Cụ Phân Tích Mã Tĩnh (Static Code Analysis)
Cuối cùng, hiện nay còn có cả những công cụ phân tích mã tĩnh có khả năng kiểm tra việc sử dụng các thuật ngữ của ngôn ngữ chung phổ quát ngay trong mã nguồn. Một ví dụ tiêu biểu cho nhóm công cụ này là NDepend.
Mặc dù các công cụ kể trên rất hữu ích, nhưng chúng chỉ đóng vai trò thứ yếu so với việc thực sự sử dụng ngôn ngữ chung trong các tương tác hàng ngày giữa con người với con người. Hãy sử dụng các công cụ để hỗ trợ quản lý ngôn ngữ chung, nhưng đừng bao giờ mong đợi rằng tài liệu hay công cụ có thể thay thế được sự giao tiếp trực tiếp. Đúng như Tuyên ngôn Agile (Agile Manifesto) đã khẳng định: "Cá nhân và sự tương tác hơn là quy trình và công cụ (Individuals and interactions over processes and tools)."
Những Thách Thức Trong Thực Tế (Challenges)
Về mặt lý thuyết, việc vun đắp một ngôn ngữ chung phổ quát nghe có vẻ là một quy trình đơn giản và thẳng thắn. Nhưng trong thực tế triển khai, nó hoàn toàn không hề đơn giản.
1. Khơi Gợi Tri Thức Ngầm (Tacit Knowledge)
Con đường đáng tin cậy duy nhất để thu thập tri thức miền là trò chuyện với các chuyên gia miền. Thế nhưng, điều trớ trêu là những tri thức quan trọng nhất thường là "tri thức ngầm" (tacit knowledge). Đó là những tri thức không hề được ghi chép thành văn bản hay quy chuẩn hóa ở đâu cả, mà nó chỉ tồn tại âm thầm trong trực giác và thói quen suy nghĩ của các chuyên gia miền. Cách duy nhất để tiếp cận được tầng tri thức này là phải liên tục đặt ra những câu hỏi sắc bén.
2. Đồng Sáng Tạo Mô Hình (Co-creating the Model)
Khi bạn tích lũy đủ kinh nghiệm trong thực hành DDD, bạn sẽ nhận ra một điều kỳ diệu: quy trình này thường không đơn thuần chỉ là "đi khám phá những tri thức đã có sẵn", mà thực chất là quá trình ĐỒNG SÁNG TẠO NÊN MÔ HÌNH (co-creating the model) cùng với các chuyên gia miền.
Bản thân sự hiểu biết của các chuyên gia miền đôi khi cũng tồn tại những sự mơ hồ, nhập nhằng, và thậm chí là những "vùng trắng" (white spots) chưa từng được nghĩ tới: ví dụ họ thường chỉ định nghĩa các kịch bản suôn sẻ trong điều kiện lý tưởng ("happy path"), nhưng lại hoàn toàn chưa tính đến các trường hợp biên (edge cases) có thể phá vỡ những giả định thông thường.
Hơn nữa, bạn sẽ bắt gặp những khái niệm nghiệp vụ vốn dĩ chưa từng có một định nghĩa rõ ràng. Việc đặt các câu hỏi truy vấn về bản chất của miền nghiệp vụ thường sẽ kéo những xung đột ngầm định và những vùng trắng đó ra ánh sáng một cách hiển ngôn. Hiện tượng này đặc biệt phổ biến đối với các miền con cốt lõi (core subdomains). Trong tình huống đó, quá trình học hỏi là sự tương hỗ hai chiều: chính bạn cũng đang giúp các chuyên gia miền hiểu sâu sắc hơn về lĩnh vực của chính họ!
3. Áp Dụng Vào Dự Án Đang Chạy (Brownfield Projects)
Khi đưa các phương pháp thực hành Thiết kế Hướng Miền vào một dự án đã tồn tại từ trước (brownfield project), bạn sẽ thấy ở đó đã có sẵn một thứ ngôn ngữ được các bên liên quan sử dụng. Tuy nhiên, vì ngôn ngữ đó không được định hướng bởi các nguyên lý DDD, nó chưa chắc đã phản ánh đúng miền nghiệp vụ. Ví dụ, nó có thể bị nhiễm nặng các thuật ngữ kỹ thuật, chẳng hạn như gọi tên nghiệp vụ bằng chính tên của các bảng trong cơ sở dữ liệu.
Thay đổi một ngôn ngữ đã ăn sâu bám rễ trong một tổ chức là điều không hề dễ dàng. Công cụ quan trọng nhất trong tình huống này là sự kiên nhẫn (patience). Trước hết, bạn cần đảm bảo rằng ngôn ngữ chuẩn xác được áp dụng nghiêm ngặt ở những nơi mà bạn có toàn quyền kiểm soát: đó là trong các tài liệu kỹ thuật mới và trong chính mã nguồn phần mềm.
4. Câu Hỏi Về Ngôn Ngữ: Tiếng Anh Hay Tiếng Bản Địa?
Một câu hỏi về ngôn ngữ chung mà tôi thường xuyên nhận được tại các hội nghị công nghệ là: "Chúng tôi nên sử dụng ngôn ngữ nào nếu công ty hoạt động ở một quốc gia không nói tiếng Anh (như tại Việt Nam, Pháp, Nhật Bản, Đức...)?"
Lời khuyên của tôi là: Bạn có thể thảo luận nghiệp vụ bằng ngôn ngữ bản địa của mình, nhưng hãy cố gắng chuẩn hóa ít nhất là các DANH TỪ tiếng Anh khi đặt tên cho các thực thể và khái niệm của miền nghiệp vụ.
Điều này sẽ giúp cho việc ánh xạ trực tiếp các thuật ngữ nghiệp vụ đó vào mã nguồn phần mềm trở nên trôi chảy, tự nhiên và đồng nhất hơn rất nhiều, tránh được tình trạng nửa nạc nửa mỡ hoặc phải dịch ngược từ tiếng bản địa sang tiếng Anh khi viết code.
Kết Luận (Conclusion)
Giao tiếp hiệu quả và chia sẻ tri thức thông suốt là yếu tố mang tính quyết định sự thành bại của một dự án phần mềm. Các kỹ sư phần mềm bắt buộc phải thấu hiểu miền nghiệp vụ thì mới có thể thiết kế và xây dựng nên một giải pháp đúng đắn.
Ngôn ngữ chung phổ quát (Ubiquitous Language) của Thiết kế Hướng Miền chính là công cụ mạnh mẽ nhất để bắc nhịp cầu tri thức giữa các chuyên gia miền và các kỹ sư phần mềm. Nó thúc đẩy giao tiếp bằng cách vun đắp một ngôn ngữ chung duy nhất, được sử dụng nhất quán bởi tất cả các bên liên quan xuyên suốt dự án: trong các cuộc đối thoại, tài liệu, kịch bản kiểm thử, sơ đồ kiến trúc, và ngay trong từng dòng mã nguồn.
- Để đảm bảo giao tiếp hiệu quả, ngôn ngữ chung phải xóa bỏ mọi sự mơ hồ và các giả định ngầm định. Tất cả các thuật ngữ phải nhất quán: không có thuật ngữ đa nghĩa mơ hồ (ambiguous) và không có thuật ngữ đồng nghĩa dùng lẫn lộn (synonymous).
- Vun đắp ngôn ngữ chung là một quá trình tiến hóa liên tục. Khi dự án phát triển, những hiểu biết sâu sắc hơn về nghiệp vụ sẽ được khám phá, và ngôn ngữ chung phải được cập nhật tương ứng.
- Các công cụ như Bảng thuật ngữ dạng Wiki và Kiểm thử tự động bằng Gherkin hỗ trợ đắc lực cho việc ghi chép và lưu giữ ngôn ngữ. Tuy nhiên, điều kiện tiên quyết số một vẫn là sự sử dụng thực tế: ngôn ngữ phải được nói ra và sử dụng nhất quán trong mọi tương tác hàng ngày của dự án.
Bài Tập Thực Hành & Trắc Nghiệm Tương Tác Chương 2
Hãy kiểm tra mức độ nắm vững các nguyên lý của Chương 2. Nhấp chọn đáp án trắc nghiệm để nhận phản hồi tức thì và phần giải thích chi tiết từ Phụ lục B (Appendix B) của cuốn sách.
Giải thích từ tác giả (Phụ lục B): Mọi bên liên quan tham gia vào dự án — từ chuyên gia miền, kỹ sư phần mềm, quản lý sản phẩm, cho đến chuyên viên kiểm thử và người dùng — đều nên đóng góp tri thức và sự thấu hiểu của mình về miền nghiệp vụ vào ngôn ngữ chung.
Giải thích từ tác giả (Phụ lục B): Ngôn ngữ chung phổ quát phải được sử dụng trong mọi hình thức giao tiếp liên quan đến dự án: từ các cuộc đối thoại hàng ngày, tài liệu đặc tả, kịch bản kiểm thử, và đặc biệt là chính mã nguồn phần mềm cũng phải "nói" ngôn ngữ chung phổ quát này.
Qua phần mô tả của công ty WolfDesk, chúng ta có thể nhận diện rõ ràng các thuật ngữ nghiệp vụ cốt lõi sau:
- Tenant (Khách hàng doanh nghiệp): Khách hàng của WolfDesk là các tenant thuê sử dụng dịch vụ.
- Onboarding process (Quy trình tiếp nhận): Để bắt đầu sử dụng hệ thống, các tenant trải qua một quy trình onboarding nhanh chóng.
- Charging model / Charging period (Mô hình thu phí / Kỳ tính cước): Dựa trên số lượng ticket được mở trong một kỳ tính phí.
- Ticket lifecycle management algorithm (Thuật toán quản lý vòng đời ticket): Đảm bảo các ticket không còn hoạt động sẽ được tự động đóng lại.
- Fraud detection algorithm (Thuật toán phát hiện gian lận): Ngăn chặn tenant lạm dụng mô hình kinh doanh bằng cách gộp nhiều chủ đề vào một ticket.
- Support autopilot (Tính năng hỗ trợ lái tự động): Cố gắng tự động tìm kiếm giải pháp cho các ticket mới dựa trên lịch sử dữ liệu.
- Support category & Product (Danh mục hỗ trợ & Sản phẩm): Một ticket thuộc về một category nhất định và liên kết với một product mà tenant hỗ trợ.
- Support agent & Shift schedule (Nhân viên hỗ trợ & Lịch ca trực): Nhân viên hỗ trợ chỉ xử lý ticket trong giờ làm việc được xác định bởi lịch ca trực của họ.
a. Hãy thử liệt kê các khái niệm của miền nghiệp vụ mà bạn có thể dùng trong các cuộc trao đổi với chuyên gia miền.
b. Hãy thử nhận diện những ví dụ về sự thiếu nhất quán trong thuật ngữ: những khái niệm nghiệp vụ có nhiều nghĩa khác nhau, hoặc cùng một khái niệm nhưng bị gọi bằng nhiều thuật ngữ khác nhau.
c. Bạn đã từng bao giờ chứng kiến sự kém hiệu quả hoặc thất bại trong phát triển phần mềm bắt nguồn từ việc giao tiếp kém hay chưa?
Giả sử bạn đang làm việc trong một dự án và nhận thấy rằng: các chuyên gia miền đến từ những đơn vị tổ chức khác nhau lại cùng sử dụng chung một từ — ví dụ từ "policy" — để mô tả những khái niệm hoàn toàn không liên quan gì đến nhau của miền nghiệp vụ.
Ngôn ngữ chung thu được lúc này tuy bám sát mô hình tư duy của từng chuyên gia miền nhưng lại thất bại trong việc đáp ứng yêu cầu: "mỗi thuật ngữ chỉ được mang một ý nghĩa duy nhất".
Trước khi bạn lật mở Chương 3, bạn sẽ giải quyết tình huống hóc búa này như thế nào?
Nếu cố gắng ép buộc toàn bộ một doanh nghiệp rộng lớn phải dùng chung một mô hình dữ liệu và định nghĩa duy nhất cho mọi từ ngữ, mô hình đó sẽ nhanh chóng trở nên cồng kềnh, mâu thuẫn và vỡ trận.
Giải pháp mang tính cách mạng của Thiết kế Hướng Miền (DDD) cho tình huống nan giải này chính là: phân chia hệ thống thành các Ngữ cảnh Giới hạn (Bounded Contexts). Trong mỗi Bounded Context cụ thể, từ ngữ sẽ mang một ý nghĩa độc lập, sắc nét và hoàn toàn nhất quán. Chúng ta sẽ cùng nhau khám phá chi tiết mẫu hình Bounded Context này ngay trong Chương 3: Quản trị Độ phức tạp của Miền (Managing Domain Complexity)!