Tích Hợp Các Bounded Contexts
Integrating Bounded Contexts • Các mẫu hình quan hệ giữa các đội ngũ, quan hệ Upstream - Downstream và Bản đồ ngữ cảnh (Context Map)
Mẫu hình Bounded Context không chỉ bảo vệ tính nhất quán tuyệt đối của một Ngôn ngữ Chung Phổ quát, mà nó còn chính là chất xúc tác cho phép quá trình mô hình hóa diễn ra. Bạn không thể tạo dựng bất kỳ một mô hình nào nếu không chỉ rõ mục đích tồn tại — tức là ranh giới của nó.
Ranh giới phân chia phạm vi trách nhiệm của các ngôn ngữ. Một ngôn ngữ trong Bounded Context này mô hình hóa miền nghiệp vụ nhằm giải quyết một bài toán cụ thể. Một Bounded Context khác có thể đại diện cho chính những thực thể nghiệp vụ đó nhưng lại mô hình hóa chúng theo một lăng kính hoàn toàn khác để giải quyết một bài toán khác.
Hơn thế nữa, các mô hình nằm trong những Bounded Context khác nhau có thể được lập trình, tiến hóa và triển khai một cách hoàn toàn độc lập. Tuy nhiên, chính bản thân các Bounded Contexts lại không hề độc lập tuyệt đối với nhau!
1. Bản Chất Của Việc Tích Hợp & Các Hợp Đồng (Contracts)
Hệt như một cỗ máy hay một hệ thống không thể được cấu thành từ những linh kiện hoàn toàn biệt lập — các linh kiện bắt buộc phải tương tác, ăn khớp với nhau để đạt được mục tiêu chung của toàn hệ thống — các thành phần hiện thực hóa bên trong Bounded Contexts cũng vậy.
Mặc dù các Bounded Context có thể tiến hóa độc lập, nhưng chúng bắt buộc phải tích hợp với nhau để vận hành thông suốt cả một chu trình kinh doanh. Kết quả là, giữa các Bounded Context sẽ luôn luôn xuất hiện những điểm tiếp xúc (touchpoints). Trong thiết kế kiến trúc, các điểm tiếp xúc này được gọi là Hợp Đồng Tích Hợp (Contracts).
Nhu cầu về các hợp đồng bắt nguồn từ chính sự khác biệt trong mô hình và ngôn ngữ giữa các Bounded Contexts. Vì mỗi hợp đồng tác động trực tiếp lên nhiều hơn một bên liên quan, chúng cần phải được định nghĩa, đàm phán và điều phối hết sức chặt chẽ.
Thêm vào đó, theo đúng định nghĩa, hai Bounded Context sử dụng hai Ngôn ngữ Chung Phổ quát khác nhau. Vậy ngôn ngữ nào sẽ được dùng cho mục đích tích hợp? Câu trả lời cho câu hỏi này cần phải được đánh giá và giải quyết thấu đáo thông qua thiết kế của giải pháp.
Trong chương này, chúng ta sẽ cùng nghiên cứu các mẫu hình Domain-Driven Design dùng để xác định các mối quan hệ và phương thức tích hợp giữa các Bounded Contexts. Những mẫu hình này được dẫn dắt trực tiếp bởi bản chất cộng tác giữa các đội ngũ kỹ thuật phát triển các context đó.
Chúng ta sẽ chia các mẫu tích hợp này thành ba nhóm chính, mỗi nhóm đại diện cho một kiểu cộng tác giữa các đội:
- Nhóm Hợp tác (Cooperation): Dành cho các nhóm có sự gắn kết và giao tiếp mật thiết.
- Nhóm Khách hàng – Nhà cung cấp (Customer–Supplier): Dành cho các mối quan hệ có sự chênh lệch về vị thế và quyền kiểm soát giao diện.
- Nhóm Đường ai nấy đi (Separate Ways): Khi việc tích hợp tốn kém hơn việc nhân bản chức năng.
2. Nhóm Mẫu Hợp Tác (Cooperation Patterns)
Các mẫu hợp tác áp dụng cho những Bounded Context được phát triển bởi các đội ngũ có kênh giao tiếp đã được thiết lập chặt chẽ, thông suốt và tin cậy.
Trong trường hợp đơn giản nhất, đó là những Bounded Context được phát triển bởi cùng một đội ngũ duy nhất. Nhóm mẫu này cũng hoàn toàn áp dụng cho các đội khác nhau nhưng có mục tiêu phụ thuộc lẫn nhau — nơi thành công của đội này phụ thuộc trực tiếp vào thành công của đội kia và ngược lại. Tiêu chí cốt tử ở đây là chất lượng giao tiếp và tinh thần phối hợp giữa các nhóm.
Có hai mẫu hình DDD kinh điển thuộc nhóm hợp tác: Mẫu hình Đối tác (Partnership) và Hạt nhân Chia sẻ (Shared Kernel).
2.1. Mẫu hình Đối tác (Partnership Pattern)
Trong mô hình đối tác, việc tích hợp giữa các Bounded Context được điều phối một cách linh hoạt theo nhu cầu thực tế (ad hoc manner).
Một nhóm có thể thông báo cho nhóm thứ hai về một thay đổi sắp tới trong API, và nhóm thứ hai sẽ vui vẻ hợp tác, chủ động điều chỉnh theo — hoàn toàn không có xung đột quyền lực hay kịch tính nơi công sở (xem Hình 4-1).
Sự điều phối ở đây diễn ra theo cơ chế hai chiều (two-way). Không có bất kỳ đội nào áp đặt ngôn ngữ của mình lên đội kia để định nghĩa các hợp đồng tích hợp. Cả hai đội có thể cùng ngồi lại để dung hòa những điểm khác biệt và tìm ra giải pháp tối ưu nhất cho cả hai phía. Khi có sự cố tích hợp nảy sinh, cả hai bên cùng xắn tay áo giải quyết; không một đội nào có ý định cản trở hay làm chậm bước tiến của đối phương.
Để mô hình Đối tác thành công rực rỡ, tổ chức bắt buộc phải có văn hóa cộng tác trưởng thành, mức độ cam kết cao và tần suất đồng bộ giữa các đội diễn ra thường xuyên.
Về mặt kỹ thuật, hệ thống cần có hạ tầng Tích hợp Liên tục (Continuous Integration - CI) tự động chạy các bài kiểm thử tích hợp chéo giữa hai bên để giảm thiểu tối đa vòng lặp phản hồi (feedback loop).
Lưu ý: Mẫu Partnership thường không phù hợp với các đội ngũ phân tán theo vị trí địa lý khác múi giờ hoặc có sự chia rẽ về chính trị nội bộ, bởi sự lệch pha trong giao tiếp sẽ nhanh chóng biến nó thành cơn ác mộng đồng bộ.
2.2. Hạt nhân Chia sẻ (Shared Kernel Pattern)
Mặc dù Bounded Context về nguyên tắc là các ranh giới cô lập của mô hình, nhưng trong thực tế vẫn tồn tại những trường hợp mà cùng một mô hình của một subdomain (hoặc một phần của nó) được sử dụng chung và hiện thực hóa trong nhiều Bounded Contexts khác nhau.
Mô hình dùng chung này được gọi là Hạt nhân Chia sẻ (Shared Kernel). Nó phải được thiết kế dựa trên sự đồng thuận và đáp ứng nhu cầu của tất cả các Bounded Context tham gia. Hơn nữa, mô hình dùng chung này phải giữ được tính nhất quán tuyệt đối trên toàn bộ các context sử dụng nó.
Ví dụ điển hình: Hãy tưởng tượng một hệ thống doanh nghiệp sử dụng một mô hình quản lý phân quyền người dùng (permissions) được tùy biến riêng. Mỗi người dùng có thể được cấp quyền trực tiếp hoặc thừa kế từ các đơn vị tổ chức mà họ trực thuộc. Mỗi Bounded Context đều cần kiểm tra và cập nhật mô hình ủy quyền này, và bất kỳ thay đổi nào mà một context tạo ra đều phải có hiệu lực ngay lập tức với các Bounded Context khác (xem Hình 4-2).
2.3. Kỹ thuật triển khai & Điều kiện áp dụng Shared Kernel
Giới hạn phạm vi chia sẻ (Shared Scope)
Mô hình chồng lấn này làm khóa chặt vòng đời phát triển của các Bounded Context tham gia vào với nhau. Một thay đổi bất cẩn ở mô hình dùng chung sẽ lập tức gây ra hiệu ứng gãy vỡ dây chuyền (cascading effect) lên toàn bộ các context khác.
Vì vậy, nguyên tắc sống còn là: Phạm vi của Shared Kernel phải được thu hẹp tối đa, chỉ để lộ phần mô hình tối thiểu bắt buộc phải triển khai chung. Lý tưởng nhất, Shared Kernel chỉ nên chứa các hợp đồng tích hợp (DTOs, interfaces) và cấu trúc dữ liệu thuần túy dùng để trao đổi qua lại giữa các ranh giới.
Phương thức triển khai kỹ thuật
- Mô hình Monorepo: Nếu tổ chức dùng chung một kho mã nguồn lớn, Shared Kernel có thể là cùng các tệp mã nguồn được tham chiếu trực tiếp bởi nhiều Bounded Contexts.
- Thư viện liên kết (Shared Library / Package): Nếu các context nằm ở các repository riêng biệt, Shared Kernel được đóng gói thành một thư viện độc lập (vd: NuGet package, npm package, maven artifact) và được các context kéo về sử dụng.
Dù theo cách nào, mỗi thay đổi đối với Shared Kernel bắt buộc phải tự động kích hoạt toàn bộ bộ kiểm thử tích hợp (integration tests) của tất cả các Bounded Context liên quan. Nếu không truyền bá các thay đổi kịp thời, các context sẽ sử dụng các phiên bản cũ không tương thích, dẫn đến hỏng hóc dữ liệu nghiêm trọng ở môi trường chạy thực tế.
Tiêu chí quyết định duy nhất để bạn cân nhắc dùng Shared Kernel là: Chi phí của việc nhân bản mã nguồn (cost of duplication) có cao hơn chi phí của việc phối hợp (cost of coordination) hay không?
Shared Kernel tạo ra sự phụ thuộc cứng giữa các context. Do đó, nó chỉ nên được dùng khi công sức để tích hợp những thay đổi ở cả hai bên tốn kém hơn nhiều so với công sức họp hành và điều phối cùng viết chung một codebase.
Mô hình càng biến động thường xuyên (như trong Core Subdomains), chi phí tích hợp sẽ càng cao, và do đó Shared Kernel tự nhiên sẽ dễ xuất hiện ở các miền lõi hơn.
3. Nhóm Mẫu Khách Hàng – Nhà Cung Cấp (Customer–Supplier)
Nhóm mẫu cộng tác thứ hai cực kỳ phổ biến trong kiến trúc phần mềm doanh nghiệp là các mẫu Khách hàng – Nhà cung cấp (Customer–Supplier).
Như minh họa trong Hình 4-3, một trong hai Bounded Context — đóng vai trò là Nhà cung cấp (Supplier) — cung cấp một dịch vụ hoặc nguồn dữ liệu cho khách hàng của nó. Bên cung cấp dịch vụ được gọi là Thượng nguồn (Upstream - ký hiệu U), và bên khách hàng tiêu thụ dịch vụ được gọi là Hạ nguồn (Downstream - ký hiệu D).
3.1. Sự mất cân bằng quyền lực (Imbalance of Power)
Khác với trường hợp Hợp tác bình đẳng ở trên, ở mối quan hệ này, cả hai đội (thượng nguồn và hạ nguồn) đều có thể thành công một cách độc lập. Kết quả là trong đa số các trường hợp, chúng ta sẽ thấy xuất hiện một sự chênh lệch về quyền lực đàm phán: hoặc là đội Thượng nguồn, hoặc là đội Hạ nguồn sẽ nắm quyền quyết định và áp đặt hợp đồng tích hợp!
Dưới đây là 3 mẫu hình cốt lõi giải quyết sự khác biệt về quyền lực này:
3.2. Mẫu Tuân thủ (Conformist Pattern)
Trong nhiều trường hợp, cán cân quyền lực nghiêng hẳn về phía đội ngũ Thượng nguồn (Upstream). Đội Thượng nguồn không hề có động lực hay nghĩa vụ phải phục vụ các nhu cầu đặc thù của khách hàng hạ nguồn. Thay vào đó, họ chỉ đơn giản cung cấp một hợp đồng tích hợp được thiết kế theo đúng mô hình nội bộ của riêng họ theo phương châm: "Dùng thì dùng, không dùng thì thôi" (take it or leave it).
Sự mất cân bằng này thường xảy ra khi tích hợp với các nhà cung cấp bên ngoài (ví dụ: Google Maps API, Stripe, Salesforce, cổng thanh toán ngân hàng) hoặc do cơ cấu quyền lực chính trị trong các tập đoàn lớn.
Nếu đội Hạ nguồn quyết định chấp nhận hoàn toàn mô hình của Thượng nguồn, mối quan hệ này được gọi là Tuân thủ (Conformist). Đội hạ nguồn uốn mình theo mô hình của context thượng nguồn (xem Hình 4-4).
Quyết định từ bỏ quyền tự chủ này hoàn toàn có thể được biện minh một cách hợp lý: Ví dụ như hợp đồng của thượng nguồn đã là một chuẩn công nghiệp vững chắc (industry standard), hoặc mô hình đó đã quá đủ tốt và đáp ứng vừa vặn nhu cầu của nhóm hạ nguồn.
3.3. Lớp Chống Tha Hóa (Anticorruption Layer - ACL)
Điều gì xảy ra khi cán cân quyền lực vẫn nghiêng về phía Thượng nguồn, nhưng đội ngũ Hạ nguồn dứt khoát KHÔNG chấp nhận tuân thủ theo mô hình của Thượng nguồn?
Khi đó, Bounded Context hạ nguồn có thể thiết lập một lớp chuyển đổi chuyên trách nhằm phiên dịch mô hình của thượng nguồn sang mô hình được may đo riêng cho nhu cầu của hạ nguồn. Lớp phiên dịch bảo vệ này được gọi là Lớp Chống Tha Hóa (Anticorruption Layer - ACL) (xem Hình 4-5).
Mẫu hình Anticorruption Layer là giải pháp cứu cánh tối thượng cho các tình huống sau:
1. Hạ nguồn là một Core Subdomain
Mô hình của một miền cốt lõi (Core Subdomain) đòi hỏi sự chăm chút tinh xảo và tính biểu đạt cao nhất. Việc nhắm mắt tuân thủ theo mô hình thô kệch của nhà cung cấp sẽ làm tê liệt khả năng mô hình hóa bài toán nghiệp vụ lõi của công ty.
2. Mô hình Thượng nguồn lộn xộn, bất tiện
Nếu một Bounded Context nhượng bộ và tuân theo một mớ hỗn độn (a mess), nó sẽ nhanh chóng tự biến mình thành một mớ hỗn độn tương tự! Đây là kịch bản rất thường gặp khi buộc phải tích hợp với các hệ thống di sản (legacy systems) cũ kỹ.
3. Hợp đồng của Thượng nguồn thay đổi quá thường xuyên
Đội hạ nguồn cần một tấm khiên để bảo vệ mô hình của mình khỏi sự rung lắc liên tục từ thượng nguồn. Với ACL, mỗi khi nhà cung cấp đổi API, những thay đổi đó chỉ ảnh hưởng cục bộ bên trong thuật toán phiên dịch của ACL mà không hề làm lung lay mã nguồn nghiệp vụ cốt lõi bên trong.
Dưới lăng kính mô hình hóa, việc phiên dịch này giúp cô lập hoàn toàn hạ nguồn khỏi các khái niệm ngoại lai vô nghĩa đối với nó, giữ cho Ngôn ngữ Chung Phổ quát của hạ nguồn luôn trong sáng và tinh gọn.
3.4. Dịch vụ Chủ Mở (Open-Host Service - OHS) & Ngôn ngữ Xuất bản (Published Language)
Mẫu hình này giải quyết trường hợp ngược lại: Cán cân quyền lực nghiêng về phía người tiêu dùng (Consumers / Downstream). Nhà cung cấp dịch vụ Thượng nguồn rất coi trọng khách hàng và có mong muốn bảo vệ khách hàng của mình cũng như đem lại trải nghiệm dịch vụ tốt nhất có thể.
Để bảo vệ các khách hàng khỏi những biến động nội bộ trong mô hình cài đặt của mình, nhà cung cấp Thượng nguồn chủ động tách rời mô hình cài đặt nội bộ (implementation model) ra khỏi giao diện công khai (public interface). Sự tách rời này cho phép thượng nguồn tự do tiến hóa mô hình bên trong với tốc độ độc lập mà không làm đổ vỡ các client (xem Hình 4-6).
Giao diện công khai của thượng nguồn không nhất thiết phải tuân theo Ngôn ngữ Chung Phổ quát nội bộ của nó. Thay vào đó, nó được thiết kế để phơi bày một giao thức thuận tiện nhất cho các client tiêu thụ, được biểu đạt bằng một ngôn ngữ hướng tích hợp. Giao thức công khai đó được gọi là Ngôn ngữ Xuất bản (Published Language).
Theo một nghĩa nào đó, mẫu Open-Host Service chính là sự đảo ngược vị trí của mẫu Anticorruption Layer: Thay vì bắt từng khách hàng hạ nguồn phải tự viết tầng phiên dịch, chính nhà cung cấp dịch vụ Thượng nguồn đã chủ động gánh vác trách nhiệm phiên dịch mô hình nội bộ của mình sang một ngôn ngữ xuất bản thân thiện cho mọi người dùng chung.
Hơn thế nữa, sự tách rời này cho phép nhà cung cấp thượng nguồn đồng thời phơi bày nhiều phiên bản khác nhau của Published Language (ví dụ: v1, v2, v3), cho phép các khách hàng hạ nguồn chuyển đổi và nâng cấp dần dần mà không bị ép buộc (xem Hình 4-7).
4. Mẫu Đường Ai Nấy Đi (Separate Ways Pattern)
Lựa chọn cộng tác cuối cùng trong danh mục chính là: HOÀN TOÀN KHÔNG CỘNG TÁC GÌ CẢ (Separate Ways)!
Mẫu hình này xuất hiện khi các đội ngũ vì nhiều lý do khác nhau không muốn hoặc không thể cộng tác với nhau.
4.1. Các nguyên nhân chính dẫn đến giải pháp Separate Ways
1. Rào cản Giao tiếp & Chính trị
Khi quy mô doanh nghiệp quá đồ sộ hoặc các phòng ban có xung đột sâu sắc về lợi ích và chính trị, việc ngồi lại thống nhất API có thể mất hàng tháng trời tranh cãi vô bổ. Lúc này, việc mỗi bên tự viết lại chức năng đó (duplicate functionality) trong Bounded Context của mình lại rẻ hơn nhiều so với chi phí họp hành!
2. Bản chất của Miền con Chung (Generic Subdomain)
Nếu chức năng đó là một miền con chung và đã có sẵn giải pháp đóng gói gọn nhẹ (ví dụ: thư viện ghi log, mã hóa, xử lý ngày tháng), thì việc tích hợp cục bộ độc lập trong từng Bounded Context sẽ hợp lý hơn nhiều so với việc dựng một service tập trung. Chi phí gọi mạng và phụ thuộc service vượt xa lợi ích của việc tránh trùng lặp.
3. Sự khác biệt quá lớn về Mô hình
Mô hình giữa hai context có thể khác xa nhau đến mức một mối quan hệ Conformist là hoàn toàn bất khả thi, trong khi chi phí xây dựng và bảo trì một Lớp Chống Tha Hóa (ACL) phức tạp lại tốn kém hơn nhiều so với việc tự viết lấy chức năng đó từ đầu. Trong trường hợp này, tách ra đi đường riêng là quyết định kinh tế sáng suốt nhất.
4.2. Cảnh báo sống còn đối với Core Subdomain
TUYỆT ĐỐI TRÁNH mẫu Separate Ways khi tích hợp các Core Subdomains. Việc nhân bản một chức năng cốt lõi, phức tạp, biến động và mang tính cạnh tranh sống còn của doanh nghiệp ở nhiều nơi sẽ đi ngược lại hoàn toàn chiến lược kinh doanh của công ty và chắc chắn sẽ dẫn đến thảm họa dữ liệu bất nhất!
5. Bản Đồ Ngữ Cảnh (Context Map)
Sau khi chúng ta đã phân tích và xác định xong các mẫu tích hợp giữa các Bounded Contexts trong toàn bộ hệ thống, chúng ta có thể vẽ và trực quan hóa chúng lên một biểu đồ kiến trúc cấp cao gọi là Bản Đồ Ngữ Cảnh (Context Map) (xem Hình 4-8).
5.1. Giá trị chiến lược của Context Map trên nhiều bình diện
Context Map là một bản ký hiệu trực quan vô cùng đắt giá, cung cấp những hiểu biết chiến lược sâu sắc ở nhiều tầng thứ:
- Bức tranh kiến trúc mức cao (High-level design): Cung cấp cái nhìn toàn cảnh về tất cả các thành phần cấu thành hệ thống và các mô hình nghiệp vụ mà chúng hiện thực hóa.
- Mô hình giao tiếp giữa các đội ngũ (Communication patterns): Cho thấy rõ ràng những nhóm nào đang cộng tác mật thiết (Partnership, Shared Kernel) và những nhóm nào lựa chọn các kiểu tích hợp "ít thân mật hơn" (ACL, Conformist, Separate Ways).
- Bộc lộ các nút thắt tổ chức (Organizational issues): Context Map là chiếc gương phản chiếu các vấn đề con người và cơ cấu quyền lực! Ví dụ: Nếu tất cả các đội hạ nguồn đều phải tự xây dựng ACL khi tích hợp với một đội thượng nguồn cụ thể, hoặc nếu tất cả các mối quan hệ Separate Ways đều xoay quanh một nhóm duy nhất — điều đó ngầm cảnh báo về sự yếu kém trong giao tiếp hoặc thái độ bất hợp tác của nhóm đó!
5.2. Quản lý và bảo trì như mã nguồn (Context Mapper)
Lý tưởng nhất, Context Map nên được thiết lập ngay từ những ngày đầu tiên của dự án và được liên tục cập nhật mỗi khi có Bounded Context mới ra đời hoặc khi các mối quan hệ tích hợp hiện tại có sự biến chuyển.
Vì Context Map chứa đựng thông tin xuất phát từ công việc của rất nhiều đội ngũ, nên việc bảo trì nó phải là một nỗ lực chung có tính chia sẻ: mỗi đội có trách nhiệm tự cập nhật các kết nối tích hợp của chính context mình.
Hiện nay, Context Map hoàn toàn có thể được quản lý dưới dạng mã nguồn (Context Map as Code) bằng các công cụ chuyên dụng như Context Mapper, cho phép tạo biểu đồ và sinh tài liệu kiến trúc tự động từ các định nghĩa DSL.
5.3. Độ phức tạp trong thực tế (Complicated Context Maps)
Cần lưu ý rằng việc phác họa một Context Map trong thực tế có thể là một thử thách rất cam go. Khi các Bounded Context của một hệ thống bao hàm nhiều subdomains bên trong, có thể có nhiều mẫu tích hợp đồng thời cùng diễn ra giữa cùng một cặp Bounded Contexts!
Như minh họa trong Hình 4-9, giữa hai Bounded Contexts có thể cùng lúc xuất hiện cả mẫu Partnership và mẫu Anticorruption Layer. Thậm chí ngay cả khi Bounded Context chỉ giới hạn trong một subdomain duy nhất, vẫn có thể có nhiều mẫu tích hợp đan xen nếu các module bên trong đòi hỏi các chiến lược tương tác chuyên biệt.
6. Tổng Kết Phần I: Thiết Kế Chiến Lược (Conclusion)
Các Bounded Contexts không phải là những hòn đảo cô lập. Chúng bắt buộc phải tương tác và kết nối với nhau để kiến tạo nên một hệ thống doanh nghiệp hoàn chỉnh.
| Mẫu Tích Hợp | Bản Chất Quan Hệ | Khi Nào Nên Áp Dụng? |
|---|---|---|
| Partnership (Đối tác) | Cộng tác bình đẳng, phối hợp ad-hoc hai chiều không áp đặt | Các đội có sự tin cậy cao, chung mục tiêu thành công, giao tiếp thuận lợi |
| Shared Kernel (Hạt nhân chia sẻ) | Chia sẻ một phần mô hình chung, đồng sở hữu bởi nhiều context | Chi phí trùng lặp cao hơn chi phí phối hợp; các core subdomains biến động cao |
| Conformist (Tuân thủ) | Hạ nguồn chấp nhận hoàn toàn mô hình của Thượng nguồn | Thượng nguồn có quyền lực tuyệt đối, hợp đồng đã là chuẩn công nghiệp hoặc đủ tốt |
| Anticorruption Layer (Lớp chống tha hóa) | Hạ nguồn tự dựng tầng phiên dịch để bảo vệ mô hình nội bộ | Hạ nguồn là Core Subdomain, hoặc mô hình Thượng nguồn quá lộn xộn/thay đổi liên tục |
| Open-Host Service (Dịch vụ chủ mở) | Thượng nguồn cung cấp Published Language phục vụ nhiều client | Thượng nguồn phục vụ nhiều consumer, muốn tự do phát triển nội bộ không làm vỡ client |
| Separate Ways (Đường ai nấy đi) | Không tích hợp; nhân bản chức năng ở từng context riêng | Rào cản giao tiếp nặng nề; chức năng là Generic Subdomain; tuyệt đối tránh cho Core |
Đến đây, bạn đã hoàn thành trọn vẹn Phần I: Thiết Kế Chiến Lược (Strategic Design) của Domain-Driven Design! Bạn đã nắm vững các công cụ tư duy tầm vĩ mô: Phân tích miền nghiệp vụ (Chương 1), Khám phá tri thức với Ngôn ngữ chung phổ quát (Chương 2), Quản lý độ phức tạp với Bounded Contexts (Chương 3), và Tích hợp các Bounded Contexts với Context Map (Chương 4).
Từ chương tiếp theo, chúng ta sẽ chuyển hướng góc nhìn từ Chiến Lược (Strategy) sang Chiến Thuật (Tactics). Trong Phần II: Tactical Design, bạn sẽ học cách hiện thực hóa logic nghiệp vụ trong từng dòng code: Transaction Script, Active Record, Domain Model, Event Sourcing và các kiến trúc hiện đại!
7. Bài Tập & Trắc Nghiệm Đánh Giá Tri Thức (Exercises)
Hãy kiểm tra khả năng nắm bắt các mẫu tích hợp chiến lược thông qua các câu hỏi dưới đây. Lời giải chi tiết được đối chiếu chuẩn xác từ tài liệu chính thức của tác giả Vlad Khononov (Appendix B).
Giải thích chi tiết (Appendix B): Mẫu Separate Ways đồng nghĩa với việc nhân bản việc triển khai một chức năng trong nhiều Bounded Contexts. Việc nhân bản logic nghiệp vụ phức tạp, biến động liên tục và mang tính sống còn đối với sự cạnh tranh của doanh nghiệp (Core Subdomain) là điều phải tránh bằng mọi giá, vì nó phá vỡ hoàn toàn chiến lược tối ưu hóa nguồn lực cốt lõi của công ty.
Giải thích chi tiết (Appendix B): Một Core Subdomain là nơi chứa đựng lợi thế cạnh tranh của doanh nghiệp, đòi hỏi mô hình phải được bảo vệ nghiêm ngặt nhất. Do đó, nó có xu hướng cao nhất trong việc áp dụng ACL để tự bảo vệ mình khỏi những mô hình kém hiệu quả do các dịch vụ thượng nguồn phơi bày, hoặc để cách ly khỏi những biến động thay đổi liên tục trên giao diện công khai của thượng nguồn.
Giải thích chi tiết (Appendix B): Một Core Subdomain là nơi thay đổi thường xuyên nhất để thích ứng với thị trường. Bằng cách triển khai Open-Host Service, nó tách rời mô hình triển khai nội bộ khỏi giao diện công khai (Published Language). Sự tách rời này giúp đội ngũ phát triển core subdomain có thể thoải mái cải tiến, tối ưu hóa mô hình cốt lõi mà không làm ảnh hưởng hay gãy vỡ hàng loạt các consumer hạ nguồn đang sử dụng dịch vụ.
Giải thích chi tiết (Appendix B): Mẫu Shared Kernel là một ngoại lệ thực dụng đối với quy tắc quyền sở hữu của một nhóm duy nhất trên Bounded Context. Nó định nghĩa một phần nhỏ của mô hình được chia sẻ và có thể được tiến hóa đồng thời bởi nhiều Bounded Contexts (và nhiều nhóm khác nhau). Do đó, phần chia sẻ này cần luôn được kiểm soát chặt chẽ và giữ ở mức nhỏ nhất có thể.