Đây là bài viết thứ 4 trong series kiến trúc xây dựng ứng dụng.
#1 Dựng package theo tính năng - package by feature là gì?
Trong kiến trúc đa tầng, lập trình viên sẽ viết code và liên kết chúng tương ứng với từng tầng của ứng dụng (Xem hình). Chúng ta có thể gọi cách tiếp cận đó là package by layer - dịch sơ là dựng package theo tầng (layer).
Vấn đề của cách tiếp cận này là sự ràng buộc giữa các tầng (cụ thể hơn là các package) quá chặt chẽ, dẫn đến vận hành, bảo trì và thay đổi các component gặp nhiều khó khăn. Đây không phải là điều chúng ta mong muốn. Mặt khác, nhiều người vẫn muốn chia tách các khía cạnh (concerns) của project một cách rạch ròi(presentation, application, domain và infrastructure).
Vậy làm thế nào để vừa chia tách được các khía cạnh theo từng tầng, vừa khống chế được sự ràng buộc giữa các tầng đó ở mức nhỏ nhất?
Đó là lúc Package by Feature - dựng package theo tính năng ra đời. Package by Feature bao gồm cả việc phân tầng và xử lý các ràng buộc một cách hợp lý. Cụ thể: theo tư tưởng này, việc phân tầng sẽ được tiến hành ở mức "thấp hơn" - mức class. Việc xử lý các ràng buộc được đẩy lên mức cao hơn class. Như vậy, các class liên quan tới cùng một tính năng sẽ nằm cùng nhau:
Khái niệm feature - tính năng ở đây mang nghĩa tổng quát, feature có thể chỉ là một use case đơn giản hoặc là cả một tập hợp các quy trình phục vụ cho một logic xử lý cụ thể.
#2 Bản chất
Các bạn có thể thấy package by feature xoay quanh 2 vấn đề chính:
1. Đảm bảo sự gắn kết
2. Giảm sự phụ thuộc
2 vấn đề này được áp dụng ở mức package.
Khi một project áp dụng package by feature, nó sẽ có cấu trúc package và module rất mạch lạc, người ngoài nhìn vào có thể hiểu ngay được.
Với kiến trúc đa tầng, độ gắn kết giữa các package khá thấp trong khi sự phụ thuộc thì lại rất cao. Thật vậy, với kiến trúc đa tầng, ta ít khi thay đổi công nghệ áp dụng hoặc cấu trúc của các tầng, trong khi đó lại thường xuyên thêm - bớt các tính năng đơn lẻ. Thêm nữa, hầu hết các class ở package này sẽ phụ thuộc ít nhất 1 class ở package khác - đó là bằng chứng cho sự phụ thuộc rất nặng đang tồn tại trong kiến trúc đa tầng.
Quay lại với package by feature, nó vừa đảm bảo được tính gắn kết bởi: ta có thể chỉnh sửa một tính năng(feature) bằng việc thay đổi trực tiếp các class liên quan tới nó (nằm trong một package); vừa hạn chế sự phụ thuộc nhiều nhất có thể (chỉ các tính năng mới phụ thuộc vào nhau, không phải các class).
Nếu như bạn thấy khó hiểu thì bạn chỉ cần hình dung rằng Package by Feature sẽ đem lại một điều tuyệt vời nhất: Bạn không cần đọc bất kỳ dòng code nào, chỉ cần nhìn vào cấu trúc của các package, bạn sẽ hiểu được project này đang làm gì.
#3 Áp dụng
Đúng như tên gọi, tư tưởng chính của package by feature là đặt mỗi tính năng trong một package khác nhau.
Khi mỗi package tương ứng với một tính năng thì ta không nên bỏ qua việc giới hạn quyền truy cập và thay đổi các thành phần trong package (sử dụng modifire public - private tùy nhu cầu). Đối với kiến trúc đa tầng - package by layer, ta không thể làm được điều này bởi luôn tồn tại ràng buộc giữa các class thuộc package khác nhau.
Ví dụ:
Tôi vẫn lấy ví dụ về Spring Pet Clinic.
Chỉ cần nhìn qua, bạn thấy ngay ứng dụng của chúng ta có 3 tính năng chính: quản lý owner-chủ vật nuôi, vets-bác sỹ thú y và visit-lượt khám-chữa-bệnh. Kèm theo đó là các class liên quan tới một tính năng sẽ được dồn vào chung package.
#4 Ưu điểm
- Dễ dàng nắm được thông tin project
- Giảm phụ thuộc, tăng sự gắn kết
- Phát huy đặc tính Encapsulation của lý thuyết OOP:
- Dễ mở rộng project
#5 Nhược điểm
- Kích thước "chuẩn" và phương pháp để định nghĩa các tính năng cho từng loại project chưa được đề cập
- Rắc rối khi chia tách tính năng cho các domain phức tạp
#6 Hoàn cảnh áp dụng
Với một số ưu điểm như trên, package by feature hoàn toàn có thể áp dụng ngay từ đầu cho các project vừa và nhỏ. Với các project có domain phức tạp, cần cân nhắc kỹ bởi việc định nghĩa các feature và chia tách các project đó theo từng feature không phải là chuyện đơn giản.
Bình luận