Trong bài viết trước, chúng ta đã cùng nhau tìm hiểu về Bounded Context và học cách xử lý các domain phức tạp. Cách tốt nhất là chia các domain thành các subdomain và map chúng với các Bounded Context khác nhau nơi mà mỗi object entity/value object nghiệp vụ có một ý nghĩa nhất định trong một context (ngữ cảnh), nên tất cả các bên liên quan đến nghiệp vụ như là Product owner, lập trình viên, kiến trúc sư, nhà tại trợ đều hiểu context và coi entity với tên thích hợp. Không nên nhầm lẫn về tên khi chúng ta trình bày các thuật ngữ cơ bản dựa trên context. Ubiquitous language (UL) tạo ngôn ngữ chung giữa các bên liên quan đến nghiệp vụ.
Theo Bounded Context, chúng ta định nghĩa một mô hình nghiệp vụ (business model) riêng, tạo các context khác nhau dựa trên các domain nghiệp vụ, nhưng luôn luôn có một chức năng trải dài trên nhiều entity nghiệp vụ, và những entity đó nằm trong các Bounded Context / Domain khác nhau, nên nó vô cùng quan trọng để hiểu được mối quan hệ giữa các Bounded Context, để kiến trúc giải pháp nghiệp vụ Context Map là một kỹ thuật mà qua đó chúng ta có thể hình dung được mối quan hệ giữa các context khác nhau và kiến trúc Integration lựa chọn là pattern tích hợp tốt nhất để giao tiếp giữa các context khác.
Tại sao Context Map là vô cùng quan trọng khi thiết kế các giải pháp?
Theo biểu đồ kiến trúc UML có thể hiểu cách các phần trao đổi với các phần khác, giúp mang đến cho kiến trúc một cái nhìn về cách giao tiếp giữa các context khác nhau, điều đó tốt nhưng Context Map bước vào trước biểu đồ UML, nó giúp hình dung bản chất của mối quan hệ và dựa trên bản chất, các kiến trúc sư có thể quyết định loại giải pháp kỹ thuật nào sẽ được áp dụng.
Cách tốt nhất giúp hình dung Context Map là về bản chất của mối quan hệ, không chỉ coi rằng mối quan hệ là upstream hay downstream, Publisher hoặc Subscriber, mà còn cho biết các team khác nhau phụ thuộc vào team khác như thế nào, mô típ, chính sách tất cả mọi thứ. Nên dựa trên tất cả những điều đó giờ đây kiến trúc sư ở một vị trí để quyết định giải pháp tối ưu để giảm thiểu rủi ro khi tích hợp với các context khác.
Trong kỷ nguyên Microservice, Context Map là người chơi chính, bởi vì trước khi thiết kế toàn diện kiến trúc Microservice nơi tất cả các team đều sở hữu một Microservice, nó là quan trọng để hiểu cách một team phụ thuộc vào team khác, những team ở vị trí quan trọng, những team chỉ tìm kiếm sự giúp đỡ, sau đó bạn có thể thiết kế một giải pháp một cách tốt nhất có thể.
Hãy cùng nghĩ về một ứng dụng gia sư sinh viên online, là ứng dụng đã được phát triển hoàn thiện với hơn 50 Microservice, được triển khai lên môi trường production, nên cần hơn 50 team tham gia và phát triển một tính năng đăng ký online cho sinh viên, nhiều context bị ảnh hưởng, nên chúng ta có thể hiểu thực hiện tính năng đó nhiều nhóm sẽ tham gia, vậy mối liên quan giữa các nhóm là gì, khi thiết kế tính năng này sẽ xoay quanh dịch vụ nào, dữ liệu nào là cần thiết nhất thì rõ ràng dịch vụ đó là ở vị trí quan trọng, như thể team đó chưa sẵn sàng thì các team khác không thể làm gì, nên tất cả các team điều chỉnh theo team đó, chúng ta phải đồng bộ backlog sản phẩm ở đó với team đó. Vì vậy, ở đây quy định bên trong xuất hiện, và nếu dữ liệu dịch vụ đến từ team bên ngoài không nằm trong tổ chức thì giải pháp phức tạp hơn vì bạn không thể ép buộc chúng, cách duy nhất là gửi yêu cầu và chời đợi có thay đổi, do đó dựa trên những kịch bản khác nhau, chính sách Context Map sẽ có giải pháp khác nhau
Sau đây là một số giải pháp quan trọng
Shared Kernel
Shared Kernel nói về mối quan hệ đối tác nơi 2 hoặc nhiều team chia sẻ mô hình dữ liệu / value object chung, nó giảm việc trùng lặp code vì các context khác nhau sử dụng chung mô hình dữ liệu, nhưng mô hình chung / value object đó là rất nhạy cảm, bất kỳ thay đổi lớn / nhỏ nào nên được sự đồng ý của tất cả các bên nếu không nó sẽ phá vỡ code của bên khác, vì vậy có nhiều nhu cầu trao đổi và đồng bộ hoá hơn giữa các team đó chấp nhận một team cần thay đổi trong mô hình chung, nhưng nếu team khác chưa sẵn sàng thì team tiên phong phải đợi người khác sẵn sàng hoặc bên liên quan phải thay đổi những code không cần thiết mặc dù điều đó không giúp gì cho họ, nhưng phải đồng bộ hoá với bên liên quan, các trạng thái khác nhau của vấn đề đan xen lẫn nhau khi duy trì mối quan hệ giữa các bên liên quan. Vì vậy hãy chọn pattern này khi các mô hình chung của bạn không thay đổi hoặc chỉ thay đổi một lần trong thời kỳ.
Ví dụ, giả sử chúng ta phát triển một module Analytical dùng để phân tích khoá học được lựa chọn nhiều nhất bởi sinh viên, sinh viên nào được chọn nhiều hơn năm khoá học vv… để module đó hoạt động với Student model, Course model nên chúng ta có thể coi Analytical module có thể chia sẻ Registration module, và chúng cũng chấp nhận bất kỳ thay đổi nào của Student module.
Customer / Supplier
Nói chung đây là mối quan hệ chung giữa các context, trong đó một bên sử dụng context hay có thể hiểu là phụ thuộc vào context khác. Context sinh ra dữ liệu được coi là upstream, và context sử dụng dữ liệu được coi là downstream. Khi chúng ta hình dung mối quan hệ này về mặt chính sách, chúng ta hình dung được phân chia quyền chi phối có nhiều sắc thái.
Như sau
Upstream như leader
Trong kiểu quan hệ này, team upstream là ở trong vị trí cao hơn, và sẽ không quan tâm đến downstream, vì chúng sinh ra dữ liệu, và dowstream chỉ nhận thông tin dữ liệu đó từ upstream team, chúng luôn luôn phải thay đổi model của mình dựa trên cấu trúc dữ liệu sinh ra bởi upstream
Trong mối quan hệ ứng dụng Student Registration giữa ứng dụng Payment và Notification, ứng dụng là kiểu upstream và downstream nơi mà ứng dụng Payment quyết định thông tin nào trong cấu trúc chúng cung cấp và Notification module sử dụng cấu trúc dữ liệu đó
Downstream như leader
Trong một vài trường hợp, mối quan hệ là ngược lại mặc dù upstream sản sinh ra dữ liệu, nó phải theo cấu trúc dữ liệu của downstream, trong kịch bản này downstream sẽ nằm ở vị trí quan trọng hơn.
Giả sử trong hệ thống đăng ký sinh viên, chúng ta cần gửi 16 form cho chính phủ như là người nộp thuế thì module payment phải gửi 16 form dữ liệu cho chính phủ bằng API, nhưng API của chính phủ sẽ có quy định nhất định và cấu trúc dữ liệu cho việc gửi 16 form, nên mặc dù API của chính phủ là downstream nhưng nó có toàn quyền kiểm soát. Module Payment phải nên truyền xuống downstream theo cách như vậy để có thể đảm bảo quy định của downstream.
Mối quan hệ customer-supplier hoạt động tốt nhất khi cả upstream và downstream bên thứ 3 được điều chỉnh để làm việc tốt với những gì 2 bên đã thoả thuận dựa trên interface và những thay đổi trong cấu trúc, trong trường hợp có bất kỳ thay đổi nào trong giao kèo, cả hai bên sẽ cần trao đổi để đồng nhất các ưu tiên trong backlog (các ticket để làm) và thoả thuận dựa trên những thay đổi. Nếu một bên không quan tâm đến bên còn lại thì hợp đồng sẽ bị phá vỡ và nó gây khó khăn cho việc bảo trì mối quan hệ customer-supplier
Conformist
Thỉnh thoảng có mối quan hệ giữa 2 bên theo cách mà team downstream luôn phụ thuộc vào upstream team và họ không thể thực hiện thoả thuận hỗ trợ từ upstream về các yêu cầu. Upstream không được điều chỉnh với downstream và không quan tâm rằng họ có thể tự do thay đổi endpoint đã phát hành hay giao kèo tại bất cứ thời điểm nào và không nhận bất kỳ yêu cầu nào từ downstream. Nó xảy ra khi team upstream là hệ thống bên ngoài hay dưới hệ thống quản lý cấp bậc khác nhau, và nhiều hệ thống downstream được đăng ký với nó, nên nó không thể bố trí ưu tiên cho bất kỳ downstream nào, đúng hơn là tất cả các hệ thống downstream phải được điều chỉnh với upstream liên quan và cấu trúc dữ liệu. Nếu cấu trúc dữ liệu hoặc các giao ước upstream thay đổi, downstream phải có trách nhiệm thay đổi theo.
Giả sử nếu ứng dụng đăng ký sinh viên online, chúng ta có một module hướng dẫn miễn phí nơi sinh viên hoặc các ứng dụng khác có thể sử dụng hướng dẫn miễn phí hoặc nhúng vào ứng dụng của họ, vì vậy ở đây module hướng dẫn miễn phí hoạt động như một upstream và không phụ thuộc vào bất kỳ bên thứ 3 nào đang sử dụng những hướng dẫn miễn phí này, chúng ta không thể ưu tiên hay có bất cứ giao kèo cho bất cứ bên nào. Nếu chúng ta thay đổi giao kèo hoặc cấu trúc dữ liệu thì các bên thứ 3 phải có nhiệm vụ thay đổi ứng dụng của họ sao cho phù hợp để sử dụng các hướng dẫn. Các bên thứ 3 hoạt động như conformist (tuân theo)
Anti Corruption Layer
Khi hai hệ thống tương tác với nhau nếu chúng ta sử dụng dữ liệu trực tiếp từ upstream, chúng ta có thể nhận dữ liệu lỗi từ upstream, như là cấu trúc dữ liệu bị thiếu khi truyền xuống downstream, do đó nó cũng ảnh hưởng đến downstream vì nó đang cố mô phỏng lại dữ liệu upstream. Do đó, nó là ý tưởng không tồi khi chúng ta sử dụng dữ liệu từ bên thứ 3 bằng cách sử dụng một lớp chuyển đổi nơi dữ liệu của upstream được chuyển đổi sang cấu trúc dữ liệu downstream trước khi cho vào downstream, bằng cách này chúng ta có thể tránh được dữ liệu lỗi từ upstream, nếu các giao ước với upstream thay đổi nó không ảnh hưởng đến bên trong downstream, chỉ ảnh hưởng đến lớp chuyển đổi, mục đích để đối phó lại những thay đổi của upstream và chuyển đổi nó sang cấu trúc dữ liệu của downstream. Kỹ thuật này được gọi là Anti-corruption layer. Anti-corruption layer bảo vệ hệ thống downstream trước những thay đổi của upstream.
Trong ứng dụng của chúng ta, module Notification có thể thực hiện một lớp ACL (Anti-corruption laye) khi sử dụng dữ liệu từ module Payment, do đó nếu cấu trúc dữ liệu module payment thay đổi thì chỉ lớp ACL thay đổi
Open Host
Trong một vài trường hợp, API domain cần được truy cập bởi nhiều dịch vụ như là module hướng dẫn các nhà xuất bản miễn phí, có rất nhiều các domain bên trong hoặc bên ngoài muốn sử dụng dịch vụ này, nên như là một upstream nó nên được lưu trữ như một dịch vụ (host) và duy trì một giao thức và dịch vụ ràng buộc như là REST và cấu trúc JSON, nên hệ thống khác có thể sử dụng dịch vụ này.
Published Language
Thường thì 2 hoặc nhiều hệ thống sẽ thực hiện gửi và nhận thông tin với nhau, trong trường hợp này, một ngôn ngữ chung cần để biến đổi dữ liệu từ một hệ thống sang các hệ thống khác như JSON, XML, chúng ta gọi cấu trúc đó làm Published language
Sau đây là một cái nhìn toàn diện về hệ thống đăng ký sinh viên online sử dụng Context Map