Công nghệ - 10/11/2025 15:00:24
Anh em đang dùng 1 class User (Entity) cho TẤT CẢ các tác vụ?
- Nhận data từ client? (RequestModel)
- Trả data về API? (ResponseModel)
- Trực tiếp binding ra View? (ViewModel)
Dùng chung Entity cho DTO, RequestModel, ViewModel... Tiện lợi hay thảm họa?
Trong suốt đời coder của mình, tôi nhận thấy một sai lầm "kinh điển" mà rất nhiều lập trình viên, từ junior đến cả senior, vẫn thường mắc phải: đánh đồng Entity, DTO, ViewModel và các RequestModel.... và sẽ đặc biệt gặp khó khăn khi tối ưu hệ thống.
Anh em có thể nghĩ: "Cũng chỉ là class để chứa data thôi mà, dùng chung cho tiện? Đỡ viết nhiều code". Không. Đây không chỉ là vấn đề về "tên gọi" (naming convention). Đây là vấnd đề về kiến trúc, bảo mật và hiệu năng.
Hôm nay chúng ta cùng nhau mổ xẻ một phần vấn đề này nhé.
Câu trả lời nằm gọn trong một nguyên tắc: Separation of Concerns (SoC) - Tách biệt các mối quan tâm. Dữ liệu phải được "cô lập" và "biến đổi" (transform) khi đi qua các ranh giới (boundaries) của hệ thống.
Cụ thể Mỗi lớp (layer) trong ứng dụng của bạn có một nhiệm vụ riêng:
Mỗi "Model" bạn tạo ra là "người vận chuyển" dữ liệu giữa các lớp này. Bạn cứ tưởng tượng bạn đặt hàng và chuyển một kiện hoa quả từ Long An đến Pháp, nếu bạn dùng chung một kiểu vận chuyển, một người vận chuyển thì chi phí sẽ tăng đáng kể. Nhà cung cấp vận chuyển (shipping provider) sẽ gom nhiều kiện hàng, phân loại hàng và lựa chọn phương tiện vận chuyển phù hợp để giảm chi phí. Hàng hoa quả mà để chung với hàng đông lạnh và vận chuyển bằng ô tô thì thảm họa sẽ xảy ra.
Để mô hình hóa logic nghiệp vụ (Business Logic) và trạng thái (State) của miền (Domain).
Nhiệm vụ: Đây không phải là một class "câm" chỉ có get/set. Một Entity đúng nghĩa (theo triết lý Domain-Driven Design - DDD) phải chứa cả dữ liệu VÀ các hành vi (methods) xử lý trên dữ liệu đó.
Vận chuyển dữ liệu "an toàn" qua các ranh giới (boundaries), đặc biệt là giữa các lớp (Service Layer ↔ Controller) hoặc giữa các hệ thống (Microservices).
Nhiệm vụ: flatten các Entity phức tạp, che giấu các trường nhạy cảm, và tối ưu payload.
Đặc điểm: dumb, chỉ có get/set, không hành vi, không logic.
Nơi ở: Thường nằm ở Application Layer (Service Layer)
Ví dụ: User Entity có 50 trường (cả HashedPassword), nhưng UserDto chỉ có 5 trường (Id, FullName, Email) để trả về cho API.
Phục vụ DUY NHẤT cho một View (trang web, màn hình app) cụ thể.
Nhiệm vụ: "Biên kịch" lại dữ liệu (thường là từ DTO) thành thứ mà View có thể hiển thị ngay lập tức.
Đặc điểm: Chứa các thuộc tính đã được định dạng (format), các logic chỉ dành cho UI (ví dụ: bool ShowAdminButton), và các dữ liệu hỗ trợ UI (List<SelectListItem>).
Nơi ở: Thường nằm ở Presentation Layer (Controller/UI).
Lưu ý: Trong API-first (nhằm hỗ trợ cho React, Vue, Angular hay Mobile app), ViewModel gần như biến mất phía server. Vai trò của nó được "chuyển" cho DTO (hoặc ResponseModel) đảm nhận, và logic "ViewModel" sẽ nằm ở client (ví dụ: trong React State).
Mục đích: "Nắm bắt" (capture) và Validate dữ liệu đầu vào từ một HTTP Request.
Nhiệm vụ: Đại diện cho ý định (intent) của người dùng. "Tôi muốn tạo sản phẩm với các thông tin này...".
Đặc điểm: Chứa đầy đủ Data Annotations ([Required], [StringLength], [Range]). Cấu trúc phải khớp với JSON/Form mà client gửi lên.
Định nghĩa "Hợp đồng" công khai của API, quy định dữ liệu mà API hứa sẽ trả về cho client.
Nhiệm vụ: Đại diện cho cấu trúc dữ liệu chính xác và cuối cùng mà client (app mobile, web React/Vue...) nhận được từ một endpoint cụ thể.
Đặc điểm: Chỉ chứa các trường dữ liệu "công khai", được gọt giũa để phù hợp yêu cầu của từng endpoint và phải rất ổn định, ít thay đổi. Nếu thay đổi, thường phải qua versioning.
Code thôi mà phải sinh ra lắm nguyên tắc để hành nhau làm gì nhỉ :D Nhưng việc phân tách rõ ràng các loại Model này không phải là "vẽ vời" cho phức tạp. Đó là yêu cầu bắt buộcđể xây dựng một hệ thống enterprise đó.
Một hệ thống "sạch" là một hệ thống mà mỗi đối tượng đều có một và chỉ một lý do để thay đổi (Single Responsibility Principle).
Việc ngại gõ thêm vài class Model và viết Mapper hôm nay sẽ cứu bạn khỏi việc thức đêm debug cả tuần trong tương lai =))))
Happy coding (Y)
/Son Do - I share real-world lessons, team building & developer growth.
#dotnet #aspnetcore #softwarearchitecture #cleancode#systemdesign #optimization #dto #viewmodel #entity #developer #techlead
Công nghệ - 19/08/2025 21:13:07
Tìm hiểu cách xây dựng hệ thống phát hiện ngôn ngữ ký hiệu theo thời gian thực bằng AI, sử dụng DETR để tăng cường khả năng tiếp cận và đổi mới. Kết nối lời nói và cử chỉ.
Công nghệ - 18/08/2025 13:38:25
Tối ưu hóa các hệ thống RAG bằng cách tận dụng siêu dữ liệu để truy xuất thông tin chính xác và nhanh chóng hơn, giải quyết các thách thức về dữ liệu dư thừa hoặc lỗi thời với công cụ LangExtract nguồn mở. Khám phá cách LangExtract sử dụng các mô hình ngôn ngữ tiên tiến để trích xuất và cấu trúc siêu dữ liệu, tạo ra một quy trình truy xuất hợp lý và hiệu quả.
Công nghệ - 01/08/2025 07:00:00
Gỡ lỗi LLM rất quan trọng vì quy trình làm việc của chúng phức tạp và liên quan đến nhiều phần như chuỗi, lời nhắc, API, công cụ, trình truy xuất, v.v.
Công nghệ - 19/06/2025 03:05:09
Code xong chạy được là chưa đủ – phải biết khi nào nó "chết" nữa chứ 😅
Bạn đang triển khai ứng dụng trên Kubernetes, Docker hay môi trường production nào? Và bạn từng "toát mồ hôi" vì service chết mà không ai báo?
Công nghệ - 16/07/2025 13:41:17
Công nghệ - 27/06/2025 03:15:44
Công nghệ - 11/12/2025 15:05:29
[Góc chuyện nghề] bán account game để đi học nghệ - bạn dám không?
Làm nghề 20 năm, gặp nhiều sinh viên, nhưng chiều qua tôi khá bất ngờ với một cậu em tên Quang. Em Quang muốn theo nghề BA và mong muốn lương 20 triệu sau khi làm việc 1.5 năm tới 2 năm trong nghề.
Công nghệ - 22/09/2025 08:59:20
Dừng ngay việc dùng DateTime.Now trong APIs, đó là ổ lỗi tiềm ẩn trong hệ thống của bạn
⏱️ Tôi từng nghĩ DateTime.Now là một thứ vô hại, đơn giản và tiện lợi, cho đến khi gặp những vấn đề về múi giờ. Những lỗi "tưởng chừng nhỏ" này lại chính là nguồn cơn của sự thất vọng và tốn kém thời gian cho nhiều đội ngũ phát triển.
Công nghệ - 14/03/2025 04:30:32