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 Person
entitas 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 Age
nilai secara lokal lagi, oleh karena itu perlu dihapus dari Person
entitas. 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.Age
properti, yang sekarang tidak ada lagi. Masalah muncul dengan sendirinya: Semua pandangan yang merujuk pada Age
seseorang perlu diperbaiki .
Contoh 2 - Mengubah struktur data yang mendasarinya - Dengan DTO
Dalam sistem lama, ada juga PersonDTO
entitas dengan lima sifat yang sama: Id, FirstName, LastName, Age, CityId
. Setelah mengambil a Person
, lapisan layanan mengubahnya menjadi PersonDTO
dan 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 Age
nilai secara lokal lagi, oleh karena itu perlu dihapus dari Person
entitas. 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 Age
properti. 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 PersonDTO
objek penuh . Dan dalam sistem baru, masih menerima PersonDTO
objek 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, Age
ada 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 Name
properti, tidak berarti bahwa kita harus membuat mereka mewarisi dari EntityWithName
kelas dasar bersama . Properti yang berbeda Name
tidak memiliki hubungan yang berarti.
- Jika salah satu properti pernah berubah (mis. Lagu
Name
diganti namanya menjadi Title
, atau seseorang mendapat FirstName
and 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 Person
entitas 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
PersonDTO
objek 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.
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.