Apa gunanya DTO daripada Entity?

18

Saya sedang mengerjakan aplikasi RCP, saya baru di aplikasi ini.

Spring bean digunakan untuk menulis logika bisnis untuk menyelamatkan / mengambil entitas.

Namun, alih-alih mengirim entitas langsung ke klien, kami mengonversi ke DTO dan menambah klien. Saat menyimpan, kami kembali mengonversi DTO ke entitas dan menyimpan.

Apa manfaat dari konversi ini? Bisakah seseorang menjelaskan?

Naveen Kocherla
sumber
What's the benefit of these conversions?decoupling model data ketekunan dari model data (representasi) yang ditawarkan kepada konsumen. Manfaat decoupling telah banyak dibahas dalam SE Namun, tujuan di bawah DTO adalah untuk mengumpulkan dalam satu tanggapan sebanyak info yang dianggap perlu bagi klien untuk menyimpan panggilan ke server. Apa yang membuat komunikasi client-server lebih lancar.
Laiv
Contoh Anda bagus. Ketika Anda adalah klien (tampilan ...) sulit untuk diubah, tetapi masalah terbesar adalah ketika sistem sudah memiliki integrasi pihak ke-3, yang tidak mungkin diubah (kontrak, biaya ...). Jika sistem Anda akan memiliki integrasi pihak ketiga, gunakan DTO.
Lucas Gonçalves

Jawaban:

44

Setiap kali pengembang bertanya "apa gunanya melakukan ini?", Apa yang sebenarnya mereka maksudkan adalah "Saya tidak melihat kasus penggunaan di mana melakukan ini memberikan manfaat". Untuk itu, izinkan saya menunjukkan kepada Anda beberapa contoh.


Semua contoh akan didasarkan pada model data sederhana ini:

Sebuah Personentitas memiliki lima sifat:Id, FirstName, LastName, Age, CityId

Dan Anda dapat mengasumsikan bahwa aplikasi menggunakan data ini dalam berbagai cara (laporan, formulir, munculan, ...).

Seluruh aplikasi sudah ada. Semua yang saya sebutkan adalah perubahan basis kode yang ada. Ini penting untuk diingat.


Contoh 1 - Mengubah struktur data yang mendasarinya - Tanpa DTO

Persyaratan telah berubah. Usia orang tersebut perlu diambil secara dinamis dari database pemerintah (mari kita asumsikan berdasarkan nama depan dan belakang mereka).

Karena Anda tidak perlu menyimpan Agenilai secara lokal lagi, oleh karena itu perlu dihapus dari Personentitas. Penting di sini untuk menyadari bahwa entitas mewakili data database , dan tidak lebih. Jika tidak ada dalam database, itu tidak ada dalam entitas.
Ketika Anda mengambil usia dari layanan web pemerintah, itu akan disimpan di objek (atau int) yang berbeda.

Tapi frontend Anda masih menampilkan usia. Semua tampilan telah diatur untuk menggunakan Person.Ageproperti, yang sekarang tidak ada lagi. Masalah muncul dengan sendirinya: Semua pandangan yang merujuk pada Ageseseorang perlu diperbaiki .


Contoh 2 - Mengubah struktur data yang mendasarinya - Dengan DTO

Dalam sistem lama, ada juga PersonDTOentitas dengan lima sifat yang sama: Id, FirstName, LastName, Age, CityId. Setelah mengambil a Person, lapisan layanan mengubahnya menjadi PersonDTOdan kemudian mengembalikannya.

Tapi sekarang, persyaratannya sudah berubah. Usia orang tersebut perlu diambil secara dinamis dari database pemerintah (mari kita asumsikan berdasarkan nama depan dan belakang mereka).

Karena Anda tidak perlu menyimpan Agenilai secara lokal lagi, oleh karena itu perlu dihapus dari Personentitas. Penting di sini untuk menyadari bahwa entitas mewakili data database , dan tidak lebih. Jika tidak ada dalam database, itu tidak ada dalam entitas.

Namun, karena Anda memiliki perantara PersonDTO, penting untuk melihat bahwa kelas ini dapat menjaga dengan Ageproperti. Lapisan layanan akan mengambil Person, mengonversinya menjadi PersonDTO, kemudian akan mengambil usia orang itu dari layanan web pemerintah, akan menyimpan nilai itu PersonDTO.Age, dan melewati objek itu.

Bagian penting di sini adalah bahwa siapa pun yang menggunakan lapisan layanan tidak melihat perbedaan antara sistem lama dan baru . Ini termasuk frontend Anda. Dalam sistem yang lama, ia menerima PersonDTOobjek penuh . Dan dalam sistem baru, masih menerima PersonDTOobjek penuh . Tampilan tidak perlu diperbarui .

Inilah yang kami maksudkan ketika kami menggunakan pemisahan frase kekhawatiran : Ada dua keprihatinan yang berbeda (menyimpan data dalam database, menyajikan data ke frontend) dan mereka masing-masing memerlukan tipe data yang berbeda. Bahkan jika kedua tipe data tersebut mengandung data yang sama sekarang, itu mungkin berubah di masa depan.
Dalam contoh yang diberikan, Ageada perbedaan antara dua tipe data: Person(entitas basis data) tidak memerlukan Age, tetapi PersonDTO(tipe data frontend) memang membutuhkannya.
Dengan memisahkan masalah (= membuat tipe data terpisah) dari awal, basis kode jauh lebih tangguh terhadap perubahan yang dilakukan pada model data.

Anda mungkin berpendapat bahwa memiliki objek DTO, ketika kolom baru ditambahkan ke database, berarti Anda harus melakukan pekerjaan ganda, menambahkan properti di entitas dan DTO. Secara teknis itu benar. Dibutuhkan sedikit usaha ekstra untuk mempertahankan dua kelas, bukan satu.

Namun, Anda perlu membandingkan upaya yang diperlukan. Ketika satu atau lebih kolom baru ditambahkan, salin / tempel beberapa properti tidak butuh waktu lama. Ketika model data berubah secara struktural, harus mengubah frontend, mungkin dengan cara yang hanya menyebabkan bug saat runtime (dan bukan pada waktu kompilasi), membutuhkan usaha yang jauh lebih banyak, dan itu mengharuskan pengembang (s) untuk mencari bug.


Saya bisa memberi Anda lebih banyak contoh tetapi prinsipnya akan selalu sama.

Untuk meringkas

  • Tanggung jawab terpisah (keprihatinan) perlu bekerja secara terpisah satu sama lain. Mereka tidak boleh berbagi sumber daya apa pun seperti kelas data (misalnya Person)
  • Hanya karena suatu entitas dan DTO-nya memiliki sifat yang sama, tidak berarti Anda harus menggabungkannya ke entitas yang sama. Jangan memotong sudut.
    • Sebagai contoh yang lebih mencolok, katakanlah basis data kami berisi negara, lagu, dan orang-orang. Semua entitas ini memiliki a Name. Tetapi hanya karena mereka semua memiliki Nameproperti, tidak berarti bahwa kita harus membuat mereka mewarisi dari EntityWithNamekelas dasar bersama . Properti yang berbeda Nametidak memiliki hubungan yang berarti.
    • Jika salah satu properti pernah berubah (mis. Lagu Namediganti namanya menjadi Title, atau seseorang mendapat FirstNameand LastName), mereka harus mengeluarkan lebih banyak upaya untuk membatalkan warisan yang bahkan tidak Anda perlukan .
    • Meskipun tidak mencolok, argumen Anda bahwa Anda tidak memerlukan DTO ketika Anda memiliki entitas adalah sama. Anda sedang melihat sekarang , tetapi Anda tidak mempersiapkan perubahan di masa depan. JIKA entitas dan DTO persis sama, dan JIKA Anda dapat menjamin bahwa tidak akan pernah ada perubahan pada model data; maka Anda benar bahwa Anda dapat menghilangkan DTO. Tetapi masalahnya adalah Anda tidak pernah bisa menjamin bahwa model data tidak akan pernah berubah.
  • Latihan yang baik tidak selalu membuahkan hasil segera. Mungkin mulai terbayar di masa depan, ketika Anda perlu mengunjungi kembali aplikasi lama.
  • Pembunuh utama dari basis kode yang ada adalah membiarkan penurunan kualitas kode, terus membuatnya lebih sulit untuk mempertahankan basis kode, sampai berkembang menjadi kekacauan yang tidak berguna dari kode spaghetti yang tidak dapat dipelihara.
  • Praktik yang baik, seperti menerapkan pemisahan kekhawatiran dari akses ke, bertujuan untuk menghindari kemiringan pemeliharaan yang buruk, untuk menjaga basis kode dapat dipertahankan selama mungkin.

Sebagai aturan praktis untuk mempertimbangkan memisahkan masalah, pikirkan seperti ini:

Misalkan setiap masalah (UI, database, logika) ditangani oleh orang yang berbeda di lokasi yang berbeda. Mereka hanya dapat berkomunikasi melalui email.

Dalam basis kode yang terpisah, perubahan ke masalah tertentu hanya perlu ditangani oleh satu orang:

  • Mengubah antarmuka pengguna hanya melibatkan dev UI.
  • Mengubah metode penyimpanan data hanya melibatkan pengembang basis data.
  • Mengubah logika bisnis hanya melibatkan pengembang bisnis.

Jika semua pengembang ini menggunakan Personentitas yang sama , dan perubahan kecil dilakukan pada entitas, semua orang harus terlibat dalam proses.

Tetapi dengan menggunakan kelas data terpisah untuk setiap lapisan, masalah itu tidak lazim:

  • Selama dev database dapat mengembalikan PersonDTOobjek yang valid , dev bisnis dan UI tidak peduli bahwa ia mengubah cara data disimpan / diambil.
  • Selama bisnis dev menyimpan data dalam database, dan menyediakan data yang dibutuhkan ke frontend, database dan pengembang UI tidak peduli jika dia memutuskan untuk menyusun kembali aturan bisnisnya.
  • Selama UI dapat dirancang berbasis di sekitar `PersonViewModel, maka pengembang UI dapat membangun UI sesuka mereka. Database dan pengembang bisnis tidak peduli bagaimana hal itu dilakukan, karena itu tidak mempengaruhi mereka.

Ungkapan kunci di sini adalah karena itu tidak mempengaruhi mereka . Menerapkan pemisahan keprihatinan yang baik berupaya meminimalkan pengaruh (dan karena itu harus melibatkan) pihak lain.

Tentu saja, beberapa perubahan besar tidak dapat dihindari termasuk lebih dari satu orang, misalnya ketika entitas yang sama sekali baru ditambahkan ke database. Tetapi jangan meremehkan jumlah perubahan kecil yang harus Anda lakukan selama masa aplikasi. Perubahan besar adalah minoritas numerik.

Flater
sumber
Jawaban komprehensif, Terima kasih. Saya punya pertanyaan; Hargai jika Anda menjawab: 1 - Koreksi saya, jika saya salah. Obyek Bisnis atau Obyek Tampilan adalah untuk mentransfer data antara Lapisan Presentasi dan Lapisan Bisnis dan Objek Entitas adalah untuk mentransfer data antara Lapisan Bisnis dan Lapisan Akses Data . dan DTO dapat digunakan sebagai BO bodoh. 2 - Asumsikan bahwa dua tampilan memerlukan info yang berbeda dari sebuah perusahaan, maka kita memerlukan dua companyDTO yang berbeda?
Arash
1
@Arash (1) "DTO" benar-benar definisi menangkap semua untuk setiap kelas data yang digunakan untuk bertukar antara dua lapisan. Objek bisnis dan objek tampilan keduanya DTO. (2) Itu sangat tergantung pada banyak hal. Membuat dto baru untuk setiap kumpulan bidang yang Anda butuhkan adalah tugas yang rumit. Tidak ada yang salah dengan mengembalikan sebuah DTO perusahaan penuh (jika masuk akal) dan kemudian membiarkan pandangan memilih bidang yang diminati. Masalahnya adalah menemukan keseimbangan antara menerapkan pemisahan kekhawatiran yang memadai dan menghindari rekayasa berlebihan dan pengulangan tanpa tujuan.
Flater
Nah, itu masuk akal bagi saya. Terima kasih banyak. Flater.
Arash
Satu pertanyaan lagi. Anda mengatakan "objek bisnis dan objek tampilan". Saya pikir keduanya sama. Ketika saya mencari, saya menyadari bahwa Objek Bisnis memiliki makna umum untuk dibandingkan dengan Obyek Tampilan . Tetapi Obyek Bisnis harus berasal dari use case dan Obyek Entitas harus berasal dari Model Data oleh karena itu mereka berbeda, apakah saya benar? bisakah Anda menjelaskannya sedikit?
Arash
@Arash: Perbedaan antara apa yang Anda sebut "objek bisnis" dan "objek tampilan" adalah konteks . Bagi kita manusia, perbedaan itu penting untuk memahami segala sesuatunya dengan benar. Tetapi kompiler (dan dengan ekstensi bahasa itu sendiri) tidak melihat perbedaan teknis di antara mereka. Ketika saya mengatakan mereka sama, maksud saya dari sudut pandang teknis. Keduanya hanya kelas dengan properti yang dimaksudkan untuk menyimpan data dan diedarkan. Dalam hal itu, tidak ada perbedaan di antara mereka.
Flater