Apakah Injeksi Ketergantungan layak dilakukan di luar UnitTesting

17

Mengingat konstruktor yang tidak akan pernah, harus menggunakan implementasi berbeda dari beberapa objek yang diinisialisasi, apakah masih praktis untuk menggunakan DI? Bagaimanapun, kita mungkin masih ingin unit test.

Kelas yang bersangkutan menginisialisasi beberapa kelas lain di konstruktornya dan kelas yang digunakannya cukup spesifik. Itu tidak akan pernah menggunakan implementasi lain. Apakah kita dibenarkan untuk menghindari mencoba memprogram ke antarmuka?

Seph
sumber
3
CIUMAN - selalu merupakan pendekatan terbaik.
Reactgular
5
Menurut pendapat saya pertanyaan ini lebih spesifik daripada duplikat yang diusulkan. desain-untuk-masa-depan-perubahan-atau-selesaikan-masalah-di-tangan , Oleh karena itu saya memilih untuk tidak menutup ini
k3b
1
Bukankah testabilitas cukup alasan?
ConditionRacer
Tidak benar-benar terdengar seperti duplikat sama seperti menjawab sendiri. Jika itu tidak akan pernah terjadi, mendesain untuk itu tidak merancang untuk perubahan di masa depan. Bahkan para astronot arsitektur hanya mendesain perubahan yang tidak akan pernah terjadi karena penilaian buruk.
Steve314

Jawaban:

13

Itu tergantung pada seberapa yakin Anda bahwa "tidak pernah," benar (selama aplikasi Anda akan digunakan).

Secara umum:

  • Jangan memodifikasi desain Anda hanya untuk pengujian. Tes unit ada untuk melayani Anda, bukan sebaliknya.
  • Jangan ulangi dirimu sendiri. Membuat antarmuka yang hanya akan memiliki satu pewaris tidak berguna.
  • Jika kelas tidak dapat diuji, kemungkinan tidak fleksibel / dapat dikembangkan untuk kasus penggunaan nyata. Terkadang itu bagus - Anda tidak membutuhkan fleksibilitas itu, tetapi kesederhanaan / keandalan / pemeliharaan / kinerja / apa pun yang lebih penting.
  • Jika Anda tidak tahu, kode ke antarmuka. Persyaratan berubah.
Telastyn
sumber
12
Hampir memberi Anda -1 untuk "jangan memodifikasi desain Anda hanya untuk testabilitas". Untuk mendapatkan testabilitas adalah IMHO salah satu alasan utama untuk mengubah desain! Tapi poin Anda yang lain ok.
Doc Brown
5
@docBrown - (dan lain-lain) saya berbeda di sini dari banyak, dan mungkin bahkan mayoritas. ~ 95% dari waktu, membuat hal-hal dapat diuji juga membuatnya fleksibel atau dapat dikembangkan. Anda harus memiliki itu dalam desain Anda (atau menambahkannya ke desain Anda) sebagian besar waktu - testability terkutuk. Yang lain ~ 5% memiliki persyaratan aneh yang mencegah fleksibilitas semacam ini dalam mendukung hal lain, atau sangat penting / tidak berubah sehingga Anda akan mengetahuinya dengan cepat jika rusak, bahkan tanpa tes khusus.
Telastyn
4
mungkin yakin, tetapi pernyataan pertama Anda di atas dapat disalahartikan terlalu mudah sebagai "biarkan kode yang dirancang dengan buruk seperti ketika Anda hanya kekhawatiran adalah testability".
Doc Brown
1
Mengapa Anda mengatakan "Membuat antarmuka yang hanya akan memiliki satu pewaris tidak berguna."? Antarmuka dapat berfungsi sebagai kontrak.
kaptan
2
@kaptan - karena objek konkret dapat bekerja sama baiknya dengan kontrak. Membuat dua hanya berarti Anda perlu menulis kode dua kali (dan memodifikasi kode dua kali ketika itu berubah). Memang, sebagian besar antarmuka akan memiliki beberapa implementasi (non-tes) atau Anda perlu mempersiapkan kemungkinan itu. Tetapi untuk kasus langka di mana semua yang Anda butuhkan adalah objek tertutup sederhana, gunakan saja secara langsung.
Telastyn
12

Apakah kita dibenarkan untuk menghindari mencoba memprogram ke antarmuka?

Sementara keuntungan dari pengkodean terhadap antarmuka cukup jelas, Anda harus bertanya pada diri sendiri apa sebenarnya yang didapat dengan tidak melakukannya.

Pertanyaan selanjutnya adalah: apakah bagian dari tanggung jawab kelas yang bersangkutan untuk memilih implementasi atau tidak? Itu mungkin atau mungkin tidak demikian dan Anda harus bertindak sesuai.

Pada akhirnya, selalu ada potensi untuk kendala konyol yang muncul tiba-tiba. Anda mungkin ingin menjalankan bagian kode yang sama secara bersamaan, dan kemungkinan menyuntikkan implementasi dapat membantu sinkronisasi. Atau setelah membuat profil aplikasi Anda, Anda mungkin menemukan Anda menginginkan strategi alokasi yang berbeda dari instantiasi biasa. Atau masalah lintas sektoral muncul dan Anda tidak memiliki dukungan AOP. Siapa tahu?

YAGNI menyarankan bahwa ketika menulis kode, penting untuk tidak menambahkan sesuatu yang berlebihan. Salah satu hal yang cenderung ditambahkan oleh programmer ke kode mereka tanpa menyadarinya, adalah asumsi yang berlebihan. Seperti "metode ini mungkin berguna" atau "ini tidak akan pernah berubah". Keduanya menambah kekacauan pada desain Anda.

back2dos
sumber
2
+1 untuk mengutip YAGNI di sini sebagai argumen untuk DI, bukan menentangnya.
Doc Brown
4
@DocBrown: Menimbang bahwa YAGNI dapat digunakan di sini, juga membenarkan tidak menggunakan DI. Saya pikir itu lebih dari argumen terhadap YAGNI menjadi ukuran yang berguna untuk apa pun.
Steven Evers
1
+1 untuk asumsi berlebihan yang dimasukkan dalam YAGNI, yang telah memukul kepala kami beberapa kali
Izkata
@SteveEvers: Saya pikir menggunakan YAGNI untuk membenarkan mengabaikan prinsip inversi ketergantungan menghalangi kurangnya pemahaman tentang YAGNI atau DIP atau bahkan mungkin beberapa prinsip pemrograman dan penalaran yang lebih mendasar. Anda hanya harus mengabaikan DIP jika perlu - suatu keadaan di mana YAGNI tidak dapat diterapkan sesuai sifatnya.
back2dos
@ back2dos: Anggapan bahwa DI berguna karena 'mungkin-persyaratan' dan "siapa yang tahu?" Justru kereta pemikiran bahwa YAGNI dimaksudkan untuk berperang, sebaliknya Anda menggunakannya sebagai pembenaran untuk peralatan tambahan dan infrastruktur.
Steven Evers
7

Itu tergantung pada berbagai parameter tetapi berikut adalah beberapa alasan mengapa Anda masih ingin menggunakan DI:

  • pengujian adalah alasan yang cukup bagus dalam dirinya sendiri saya percaya
  • kelas yang diperlukan oleh objek Anda dapat digunakan di tempat lain - jika Anda menyuntikkannya, ini memungkinkan Anda mengumpulkan sumber daya (misalnya jika kelas yang dimaksud adalah koneksi thread atau basis data - Anda tidak ingin masing-masing kelas membuat yang baru koneksi)
  • jika menginisialisasi objek-objek lain dapat gagal, kode lebih tinggi dari tumpukan mungkin akan lebih baik dalam menangani masalah daripada kelas Anda yang kemudian mungkin hanya akan meneruskan kesalahan

Intinya: Anda mungkin dapat hidup tanpa DI dalam kasus itu tetapi ada kemungkinan bahwa menggunakan DI akan berakhir dengan kode yang lebih bersih.

assylias
sumber
3

Ketika Anda merancang suatu program atau fitur, bagian dari proses berpikir harus bagaimana Anda akan mengujinya. Ketergantungan Injeksi adalah salah satu alat pengujian, dan harus dianggap sebagai bagian dari campuran.

Manfaat tambahan dari Dependency Injection dan menggunakan antarmuka, bukan kelas juga bermanfaat ketika aplikasi diperluas, tetapi mereka juga dapat dipasang kembali ke kode sumber nanti dengan mudah dan aman menggunakan pencarian dan penggantian. - bahkan pada proyek yang sangat besar.

Michael Shaw
sumber
2
 > Dependency Injection worth it **outside** of UnitTesting?
 > Are we justified in avoiding trying to program to an interface?

Banyak jawaban untuk pertanyaan ini dapat diperdebatkan sebagai "Anda mungkin membutuhkannya karena .." sebagai YAGNI jika Anda tidak ingin melakukan unittesting.

Jika Anda menanyakan alasan apa di samping unittests, Anda perlu memprogram ke antarmuka

Ya , Ketergantungan Injeksi sepadan di luar UnitTesting jika Anda memerlukan inversi kontrol . Sebagai contoh jika satu implementasi modul memerlukan modul lain yang tidak dapat diakses di lapisannya.

Contoh: jika Anda memiliki modul gui=> businesslayer=> driver=> common.

Dalam skenario ini businesslayerbisa digunakan drivertetapi drivertidak bisa digunakan businesslayer.

Jika drivermembutuhkan fungsionalitas tingkat yang lebih tinggi, Anda dapat mengimplementasikan fungsi ini di businesslayermana mengimplementasikan antarmuka dalam commonlapisan. driverhanya perlu tahu antarmuka di commonlapisan.

k3b
sumber
1

Ya, Anda - pertama, lupakan pengujian unit sebagai alasan untuk mendesain kode Anda di sekitar alat uji unit, itu tidak pernah merupakan ide yang baik untuk membengkokkan desain kode Anda agar sesuai dengan kendala buatan. Jika alat Anda memaksa Anda untuk melakukan ini, dapatkan alat yang lebih baik (mis. Microsoft Fakes / Moles yang memungkinkan Anda lebih banyak opsi untuk membuat objek tiruan).

Misalnya, apakah Anda akan membagi kelas menjadi hanya metode publik hanya karena alat uji tidak bekerja dengan metode pribadi? (Saya tahu kebijaksanaan yang berlaku adalah berpura-pura Anda tidak perlu menguji metode pribadi, tapi saya merasa ini adalah reaksi terhadap kesulitan dalam melakukannya dengan alat saat ini, bukan reaksi tulus untuk tidak perlu menguji privat).,

Semua dalam semua itu datang ke apa jenis TDDer Anda - "mockist" seperti Fowler menggambarkan mereka, perlu mengubah kode sesuai dengan alat yang mereka gunakan, sedangkan "klasik" penguji membuat tes yang lebih terintegrasi di alam (Yaitu menguji kelas sebagai satu unit, bukan masing-masing metode) sehingga ada sedikit kebutuhan untuk antarmuka, terutama jika Anda menggunakan alat yang dapat mengejek kelas beton.

gbjbaanb
sumber
3
Saya tidak berpikir kebijaksanaan yang berlaku bahwa metode pribadi tidak boleh diuji ada hubungannya dengan kesulitan mengujinya. Jika ada bug dalam metode pribadi, tetapi itu tidak mempengaruhi perilaku objek, maka itu tidak mempengaruhi apa pun. Jika ada bug dalam metode pribadi yang memengaruhi perilaku objek, maka ada tes yang gagal atau tidak ada pada setidaknya salah satu metode publik objek.
Michael Shaw
Itu tergantung pada apakah Anda menguji perilaku atau keadaan. Metode pribadi perlu diuji dalam beberapa cara, tentu saja, tetapi jika Anda adalah orang TDD klasik, Anda akan mengujinya dengan menguji kelas "secara keseluruhan", alat uji yang digunakan kebanyakan orang difokuskan pada pengujian setiap metode secara individual ... dan poin saya adalah yang terakhir secara efektif tidak menguji dengan benar karena mereka kehilangan kesempatan untuk melakukan tes penuh. Jadi saya setuju dengan Anda, sambil mencoba menyoroti bagaimana TDD telah ditumbangkan oleh berapa banyak (kebanyakan?) Orang melakukan pengujian unit hari ini.
gbjbaanb
1

Dependency Injection juga membuat jelas bahwa objek Anda HAS dependensi.

Ketika orang lain pergi menggunakan objek Anda secara naif (tanpa melihat konstruktor), mereka akan menemukan bahwa mereka perlu mengatur layanan, koneksi, dll. Itu tidak jelas karena mereka tidak harus menyerahkannya ke konstruktor . Melewati dependensi membuatnya lebih jelas apa yang dibutuhkan.

Anda juga berpotensi menyembunyikan fakta bahwa kelas Anda mungkin melanggar SRP. Jika Anda melewati banyak dependensi (lebih dari 3), kelas Anda mungkin melakukan terlalu banyak dan harus di-refactored. Tetapi jika Anda membuatnya di konstruktor, kode bau ini akan disembunyikan.

Schleis
sumber
0

Saya setuju dengan kedua kubu di sini dan masalah ini masih terbuka untuk diperdebatkan menurut pendapat saya. YAGNI menuntut saya untuk tidak mengubah kode saya agar sesuai dengan anggapan. Unit testing bukan masalah di sini karena saya sangat percaya bahwa ketergantungan tidak akan pernah berubah. Tetapi jika saya adalah Unit testing yang dimaksudkan untuk memulai, saya tidak akan pernah mencapai titik ini pula. Karena saya akhirnya akan berhasil masuk ke DI.

Izinkan saya menawarkan alternatif lain untuk skenario saya secara khusus

Dengan pola pabrik saya dapat melokalkan ketergantungan di satu tempat. Saat menguji saya bisa mengubah implementasi berdasarkan konteks, dan itu cukup bagus. Ini tidak bertentangan dengan YAGNI karena manfaat dari abstrak beberapa konstruksi kelas.

Seph
sumber