Trong phát triển phần mềm, việc tạo ra các đối tượng dữ liệu chuyên biệt để quản lý tương tác với các phần cụ thể của cơ sở dữ liệu từ lâu đã là nền tảng của kiến trúc ứng dụng. Các framework như Django và vô số ORM đã thể chế hóa mô hình này, hứa hẹn một sự trừu tượng hóa sạch sẽ cho các tầng lưu trữ. Tuy nhiên, ngày càng có nhiều lập trình viên đang đặt câu hỏi liệu cách tiếp cận một cỡ vừa cho tất cả này có đang tạo ra nhiều vấn đề hơn là giải pháp hay không, đặc biệt là khi các ứng dụng mở rộng và phát triển. Các cuộc thảo luận trong cộng đồng tiết lộ rằng những gì từng được coi là phương pháp hay nhất giờ đây ngày càng bị xem là nguồn gốc của sự phức tạp và cứng nhắc.
Sự Bùng Nổ Tổ Hợp Của Các Ngữ Cảnh
Một điểm tranh cãi trung tâm xoay quanh thách thức khi sử dụng cùng một đối tượng dữ liệu ở các phần khác nhau của một ứng dụng. Một đối tượng User chẳng hạn, có thể được sử dụng cho cả việc xác thực và quản lý hồ sơ. Dữ liệu cần thiết để đăng nhập—có lẽ chỉ là email và mật khẩu—chỉ là một tập hợp con nhỏ của hồ sơ người dùng đầy đủ. Việc bắt hàm đăng nhập phải chấp nhận một đối tượng User nguyên khối đồng nghĩa với việc nó phải mang theo toàn bộ dữ liệu người dùng, mà hầu hết trong số đó không liên quan đến nhiệm vụ của nó. Điều này biến việc tái cấu trúc thành một cơn ác mộng, vì bất kỳ thay đổi nào đối với đối tượng User đều đòi hỏi phải xem xét tất cả các cách sử dụng của nó, ngay cả những cách hoàn toàn không liên quan đến thay đổi đó. Một phương án thay thế—tạo ra nhiều đối tượng nhỏ hơn, cụ thể theo ngữ cảnh—có thể tránh được điều này nhưng lại dẫn đến sự gia tăng số lượng lớp, điều có thể khiến mã nguồn trở nên lộn xộn và lặp đi lặp lại.
Đó là lý do tại sao việc tái cấu trúc các hệ thống lớn được lập trình theo phong cách này lại khó đến vậy. Tác giả đã quan sát thấy sự bùng nổ tổ hợp của các dữ kiện!
Tâm trạng này vang vọng một nhận thức rộng hơn: việc cố gắng nắm bắt tập hợp vô hạn các dữ kiện về một khái niệm trong thế giới thực như một Người dùng trong một lớp duy nhất là một nỗ lực cơ bản có sai sót. Các ngữ cảnh ứng dụng khác nhau đòi hỏi các góc nhìn khác nhau về cùng một dữ liệu cơ bản, và một đối tượng đơn lẻ, chuẩn mực thường không thể phục vụ hiệu quả cho tất cả các mục đích này mà không trở nên cồng kềnh và khó bảo trì.
Những Phê Bình Phổ Biến về Universal Data Objects:
- Bùng Nổ Tổ Hợp: Một object đơn lẻ không thể biểu diễn hiệu quả tất cả các góc nhìn có thể có của một thực thể trên các ngữ cảnh ứng dụng khác nhau.
- Khó Khăn Trong Refactoring: Những thay đổi đối với một data object trung tâm đòi hỏi phải xem xét tất cả các cách sử dụng của nó, kể cả những cách không liên quan.
- Chi Phí Phát Triển Cao: Việc tuân thủ nghiêm ngặt các object theo ngữ cảnh cụ thể (như trong DDD) có thể làm chậm tốc độ phát triển do tăng việc mapping và quản lý file.
- Cứng Nhắc Về Kiến Trúc: Pattern này có thể đẩy các mô hình truy cập dữ liệu khác nhau (ví dụ: đọc nhất quán so với đọc nhất quán cuối cùng) vào một interface duy nhất, vụng về.
Sự Đánh Đổi Trong Công Cụ và Tốc Độ Phát Triển Của Nhóm
Cuộc tranh luận cũng mở rộng đến những sự đánh đổi thực tế liên quan đến việc tuân thủ nghiêm ngặt các mẫu như Domain-Driven Design (DDD). Mặc dù việc tạo các Data Transfer Object (DTO) riêng biệt cho các ngữ cảnh khác nhau có thể cải thiện độ chính xác và sự tách biệt về mối quan tâm, nhưng nó đi kèm với một cái giá cụ thể. Nhiều đối tượng hơn đồng nghĩa với nhiều mã ánh xạ hơn, nhiều tệp hơn và nhiều tên hơn để quản lý. Ở các ngôn ngữ như Java, điều này có thể làm chậm đáng kể tốc độ phát triển, dẫn đến sự thất vọng khi những thay đổi đơn giản tạo ra một loạt các tệp mới. Một số nhà phát triển báo cáo rằng sau một thời gian ban đầu nhiệt tình, các nhóm thường lặng lẽ phản đối các quy tắc nghiêm ngặt của DDD thuần túy, thấy rằng chi phí quá lớn so với tốc độ kinh doanh. Điều này đã khiến nhiều người tìm kiếm một giải pháp trung gian, áp dụng các nguyên tắc này một cách có chọn lọc ở những nơi chúng mang lại giá trị cao nhất, chẳng hạn như trong các lĩnh vực nhạy cảm về bảo mật như xác thực, thay vì áp dụng phổ quát trên toàn bộ codebase.
Các Mẫu Kiến Trúc Thay Thế và Sự Thay Đổi Tư Duy
Để đối phó với những thách thức này, các nhà phát triển đang khám phá các mẫu kiến trúc thay thế. Một số ủng hộ một cách tiếp cận thiên về chức năng hơn, nơi các truy vấn cụ thể trả về các kiểu khớp chính xác với hình dạng của kết quả, thay vì ép kết quả vào các đối tượng thực thể được định nghĩa trước. Các công cụ như jOOQ, công cụ tạo mã an toàn kiểu từ lược đồ cơ sở dữ liệu, được ca ngợi vì cho phép phong cách này mà không có hành vi ma thuật của một số ORM. Điều này phù hợp với một sự thay đổi tư duy rộng hơn, được các ngôn ngữ như Clojure ủng hộ, hướng tới việc mô hình hóa dữ liệu như các bản đồ chung, đơn giản và viết các hàm hoạt động trên chúng. Những người ủng hộ lập luận rằng khi kết hợp với các lược đồ xác thực, cách tiếp cận này có thể đưa ra các đảm bảo về cấu trúc đồng thời tránh được sự bùng nổ tổ hợp của các hệ thống phân cấp lớp, cung cấp một nền tảng linh hoạt hơn cho các hệ thống thông tin phức tạp.
Các Phương Pháp Thay Thế Được Đề Cập:
- Đối Tượng Theo Ngữ Cảnh Cụ Thể (DTOs): Tạo các đối tượng riêng biệt cho các trường hợp sử dụng khác nhau (ví dụ:
LoginPayload,UserProfile). - Truy Vấn Hướng Hàm: Xây dựng các truy vấn trả về kết quả theo một cấu trúc cụ thể, thay vì ép buộc chúng vào các đối tượng thực thể. Các công cụ như jOOQ hỗ trợ điều này.
- Lập Trình Hướng Dữ Liệu: Sử dụng các cấu trúc dữ liệu đơn giản, tổng quát (như maps) và xác thực chúng bằng schemas (ví dụ: Clojure với spec/malli).
Sức Mạnh Của Quy Ước và Nguyên Tắc Ít Bất Ngờ Nhất
Bất chấp những lời chỉ trích, mô hình đối tượng dữ liệu vẫn ăn sâu bám rễ vì một lý do chính đáng: đó là những gì hầu hết các nhà phát triển mong đợi. Việc đưa các thành viên mới vào nhóm sẽ dễ dàng hơn khi một codebase tuân theo các quy ước quen thuộc. Nguyên tắc ít bất ngờ nhất là một động lực mạnh mẽ trong phát triển phần mềm, làm giảm tải nhận thức và san bằng con đường dẫn đến năng suất. Hơn nữa, sự trỗi dậy của các công cụ lập trình có sự hỗ trợ của AI, hay còn gọi là vibe coding, củng cố giá trị của các mẫu phổ biến, vì các mô hình ngôn ngữ lớn thường được đào tạo trên mã sử dụng các cách tiếp cận tiêu chuẩn này. Việc đi chệch khỏi quy chuẩn có thể làm giảm hiệu quả của sự trợ giúp tự động và làm phức tạp việc bảo trì lâu dài, đây là một lập luận phản bác mạnh mẽ đối với một sự thay đổi kiến trúc toàn diện.
Cuộc thảo luận xung quanh các đối tượng dữ liệu còn lâu mới kết thúc. Nó đại diện cho một sự căng thẳng kinh điển trong kỹ thuật phần mềm giữa sự trừu tượng hóa sạch sẽ của một mô hình phổ quát và thực tế phức tạp của các yêu cầu phát triển. Khi các hệ thống phát triển, sự tiện lợi ban đầu của một đối tượng dữ liệu một cỡ vừa cho tất cả có thể nhường chỗ cho sự phức tạp đáng kể. Xu hướng hiện tại không phải là từ bỏ hoàn toàn mô hình này, mà là hướng tới một cách áp dụng nó có sắc thái hơn và nhận thức rõ hơn về ngữ cảnh, thừa nhận rằng giải pháp thực tế nhất thường nằm ở sự cân bằng chu đáo giữa sự thuần khiết về kiến trúc và nhu cầu phát triển thực tế.
Tham khảo: On having a data object
