Entity, area mannequin và DTO – sao nhiều quá vậy?

Bài viết hôm nay khá hay và cũng là chủ đề quan yếu trong Spring Boot. Cụ thể chúng ta cùng tìm hiểu xem information sẽ biến đổi như thế nào lúc đi qua những layer khác nhau. Và những khái niệm Entity, Area mannequin và DTO là gì nhé.

1. Kiến trúc tổng quan Spring Boot

1.1. Kiến trúc supply code và kiến trúc dữ liệu

Trong những phần trước, chúng ta đã biết được mọi ứng dụng Spring Boot đều tuân theo 2 mô hình cơ bản:

  • Mô hình MVC
  • Mô hình 3 lớp (3 tier)

Và do ấy, chúng ta hài hòa lại được ứng dụng hoàn chỉnh có cấu trúc như sau.

Sơ đồ trên dùng để tổ chức supply code trong chương trình. Nhờ có ấy chúng ta chia thành những Controller, Service, Repository tương ứng sở hữu những layer. Tuy nhiên, ví dụ xét về mặt tổ chức information, thì sơ đồ sẽ phát triển thành như sau.

Mô hình này cũng gồm có 3 lớp, trong ấy tên những layer được đổi thành những thành phần tương ứng trong Spring Boot.

Theo ấy, tương ứng sở hữu từng layer thì information sẽ có dạng khác nhau. Nói bí quyết khác, từng layer chỉ nên xử lý 1 số loại information nhất định. Từng dạng information sẽ có nhiệm vụ, phần đích khác nhau. Tất nhiên trong code cũng được chia ra tương ứng.

Dí dụ trong sơ đồ thì Controller ko nên đụng tới information dạng area mannequin hoặc entity, chỉ được phép nhận và trả về DTO.

1.2. Tại sao nên chia nhiều dạng information

Do tuân theo nguyên tắc SoC – separation of considerations – chia tách những mối chú ý trong thiết kế phần mềm. Cụ thể, chúng ta đã chia bé ứng dụng Spring Boot ra như sau.

Spring Boot = Presentation layer + Service layer + Knowledge entry layer

Ấy là việc chia bé supply code theo SoC. Tuy nhiên, tại mức thấp hơn thì SoC mô tả qua nguyên lý trước tiên của SOLID (Single duty – nguyên lý đơn nhiệm), nghĩa là từng class chỉ nên thực hành 1 nhiệm vụ duy nhất.

Do ấy, trước đây information chỉ có 1 dạng, nhưng có nhiều layer, từng layer hành xử khác nhau sở hữu information nên information đã thực hành nhiều nhiệm vụ. Điều này vi phạm vào Single duty, nên chúng ta cần chia bé thành nhiều dạng information.

1 nguyên nhân nữa là ví dụ information chỉ có 1 dạng thì sẽ bị leak (lộ) những dữ liệu nhạy cảm. Lấy thí dụ chức năng kiếm tìm bạn bè của Fb, đúng ra chỉ trên trả về information chỉ có những information cơ bản (avatar, tên,…). Trường hợp chỉ có 1 dạng information thì toàn bộ thông tin sẽ được trả về. Mặc dầu consumer chỉ hiển thị những information cần thiết, nhưng việc trả về toàn bộ thì kẻ xấu có thể lợi dụng để chôm những information nhạy cảm.

Xem Thêm  Thảo mai là gì? Những điều ko cần ai cũng biết về thảo mai

Vì thế, phân tách information thành những dạng biệt lập cũng là 1 bí quyết để nâng cao cường bảo mật cho ứng dụng.

2. Những dạng information

2.1. 2 loại information

Theo sơ đồ trên, information trong ứng dụng Spring Boot chia thành 2 loại chính:

  • Public: nghĩa là để trao đổi, chia sẻ sở hữu bên bên cạnh qua REST API hoặc giao tiếp sở hữu những service khác trong microservice. Knowledge lúc này tại dạng DTO.
  • Non-public: những information dùng trong nội bộ ứng dụng, bên bên cạnh ko nên biết. Knowledge lúc này thuộc diện những Area mannequin hoặc Entity.

Những dạng information có thể có nhiều tên gọi khác nhau, nhưng chung quy lại vẫn thuộc 2 phần như trên. Do ấy, lúc ứng dụng vào kiến trúc Spring Boot thì chúng ta sẽ cân nhắc xem loại information nào yêu thích sở hữu layer nào (phần 2.2).

Từ 2 loại public và non-public trên, chúng ta có 3 dạng information:

  • DTO (Knowledge switch object): là những class đóng gói information để chuyển giữa consumer – server hoặc giữa những service trong microservice. Phần đích tạo ra DTO là để giảm bớt lượng information ko cần thiết nên chuyển đi, và cũng nâng cao cường độ bảo mật.
  • Area mannequin: là những class đại diện cho những area, hiểu là những đối tượng thuộc enterprise như Consumer, Report, Division,… chẳng hạn. Trong ứng dụng thực, những class đại diện cho kết quả tính toán, những class làm cho tham số đầu vào cho service tính toán,… được coi là area mannequin.
  • Entity: cũng là area mannequin nhưng tương ứng sở hữu desk trong DB, có thể map vào DB được. Lưu ý chỉ có entity new có thể đại diện cho information trong DB.

Những dạng information có hậu tố tương ứng, trừ entity. Dí dụ entity Consumer ko có hậu tố, ví dụ là area mannequin thì là UserModel, hoặc sở hữu DTO thì là UserDto,… cũng vậy.

2.2. Nguyên tắc chọn information tương ứng sở hữu layer

Properly mình cũng ko biết gọi nó như thế nào nữa. Nói tóm lại, từng layer trong mô hình 3 lớp sẽ thực hành xử lý, nhận, trả về dữ liệu thuộc những loại xác định.

Xem Thêm  RAPE LÀ GÌ. PHÂN BIỆT RAPE VÀ SEXUAL ASSAULT. RAPE CULTURE

Vận dụng vào mô hình 3 lớp trong sơ đồ, thì chúng ta rút ra được nguyên tắc thiết kế chung:

  • Internet layer: chỉ nên xử lý DTO, đồng nghĩa sở hữu việc những Controller chỉ nên nhận và trả về dữ liệu là DTO.
  • Service layer: nhận vào DTO (từ controller gửi qua) hoặc Area mannequin (từ những service nội bộ khác). Dữ liệu được xử lý (có thể tương tác sở hữu DB), cuối cùng được Service trả về Internet layer dưới dạng DTO.
  • Repository layer: chỉ thực hiện trên Entity, vì ấy là đối tượng thích hợp, có thể mapping vào DB.

Đối sở hữu những thành phần khác của Spring Boot mà ko thuộc layer nào, thì:

  • Customized Repository: đây là layer ko thông qua repository mà thực hiện quản lý sở hữu database. Do ấy, lớp này được hành xử như Service.

2.3. Mannequin mapping

Lúc information đi qua những layer khác nhau, nó biến đổi thành những dạng khác nhau. Dí dụ DTO từ controller đi vào service, thì nó sẽ được map thành area mannequin hoặc entity, rồi lúc vào Repository phải} nên phát triển thành Entity. Và ngược lại cũng đúng.

Việc convert giữa những dạng information, thí dụ DTO thành Entity, DTO thành area mannequin, area mannequin thành entity hoặc ngược lại, được gọi là mannequin mapping.

Thực hành mannequin mapping thường là dùng thư viện như ModelMapper (bí quyết dùng sẽ có trong bài tiếp theo). Tuy nhiên, đơn giản nhất thì có thể viết code copy thuần như sau.

@Getter public class UserDto { String title; String age; public void loadFromEntity(Consumer entity) { sentayho.com.vn = sentayho.com.vname(); sentayho.com.vn = sentayho.com.vnge(); } } @Getter public class Consumer { String title; String age; String crush; public void loadFromDto(UserDto dto) { sentayho.com.vn = sentayho.com.vname(); sentayho.com.vn = sentayho.com.vnge(); } }

Code như trên lúc dùng sẽ trông như này.

// Trong controller, convert từ DTO > entity Consumer consumer = new Consumer(); sentayho.com.vnFromDto(userDto); // Hoặc trả về cũng tương tự động, từ Entity > DTO Consumer consumer = sentayho.com.vnser(username); userDto userDto = new UserDto(); sentayho.com.vnFromEntity(consumer); return userDto;

Bí quyết khác đơn giản hơn là thay thế vì viết methodology copy thì copy trong constructor luôn. Do ấy, code convert sẽ ngắn hơn.

Consumer consumer = new Consumer(userDto); // DTO > entity UserDto userDto = new UserDto(consumer); // Entity > DTO

3. Thực tế như thế nào?

Lúc ứng dụng vào thực tế, có muôn hình vạn trạng trường hợp xảy ra. Ko chỉ đơn giản theo mẫu sau.

Controller nhận DTO > Service chuyển DTO thành mannequin hoặc entity, rồi xử lý > Repository nhận Entity đưa vào DB

Repository lấy từ DB ra Entity > Service xử lý sao ấy rồi thành DTO > Controller và trả về DTO

Mà còn có những trường hợp khác như:

  • Controller ko nhận DTO mà nhận vào tham số primitive như int, float,…
  • Nhận vào 1 Checklist DTO
  • Trả về 1 Checklist DTO
Xem Thêm  Hyperlink Tải Outlast 2 Full Việt Hóa new nhất hiện nay tại đây

Do ấy, trong thực tế người ta có thể thay thế đổi cho yêu thích sở hữu dự án.

Dí dụ chuẩn là Service sẽ thực hành mapping sang DTO và ngược lại, controller chỉ nhận DTO. Nhưng đôi lúc để giảm tải cho service thì việc mapping này sẽ do controller đảm nhiệm (tuy vậy controller có thể bị phình lớn, trong lúc đúng ra nên giữ controller mỏng – ít code nhất có thể).

Nhưng dù bí quyết nào đi nữa, thì nguyên tắc chung là việc mapping luôn được thực hành tại rìa của code (edge). Nghĩa là ví dụ mapping trong service thì việc chuyển đổi nên luôn nằm tại đầu, hoặc tại cuối cùng methodology lúc chúng được xử lý.

Bên cạnh ra, để giảm boilerplate code, chúng ta thường giảm sự chặt chẽ xuống 1 chút ví dụ ko cần thiết. Dí dụ như:

  • Đôi lúc ko cần area mannequin, Service có thể chuyển thẳng DTO thành entity.
  • Service cũng có thể trả về Entity hoặc Mannequin, ví dụ chúng quá đơn giản và ko chứa information nhạy cảm. Lúc này ko cần DTO mà controller trả về Entity hoặc Mannequin luôn để đỡ rối (dù rằng vì phạm nguyên tắc lúc public 2 thằng này, nhưng cũng nên cân nhắc).

Có nhiều ý kiến tranh cãi về việc dùng DTO, coi ấy như là 1 anti sample. Cá nhân mình ko thấy vậy, nhiều lúc DTO vẫn khá hữu dụng, và có thể tùy thuộc} biến để yêu thích và hiệu quả hơn.

Bài viết tới đây cũng dài rồi. Nói thực đây là bài mình tốn công nhất, do nên đụng tới khá nhiều về structure. New hôm qua mình còn lôi cả mission cũ ra để refactor lại cho đúng chuẩn, để nắm rõ hơn về kiến trúc mình sắp trình bày và những aspect impact có thể xảy ra.

Bài viết có tham khảo tại nguồn sentayho.com.vn/software-development/design/understanding-spring-web-application-architecture-the-classic-way/ mà mình cảm thấy hay nhất. Trong hyperlink trên còn có phần kết và bình luận, người sử dụng có thể đọc thêm.

À quên ví dụ bạn cảm thấy bài viết hay và hữu ích, hãy upvote và clip để tiếp thêm động lực cho mình nhé. Bye bye