Banyak orang membangun satu implementasi. DI putus asa? Gunakan pencari lokasi layanan?

14

Katakanlah kita memiliki 1001 klien yang membangun dependensi mereka secara langsung daripada menerima suntikan. Refactoring the 1001 bukanlah pilihan menurut bos kami. Kami sebenarnya bahkan tidak diizinkan mengakses sumbernya, hanya file kelas.

Apa yang seharusnya kita lakukan adalah "memodernisasi" sistem yang dilalui oleh 1001 klien ini. Kita dapat memperbaiki itu sesuka kita. Ketergantungan adalah bagian dari sistem itu. Dan beberapa dependensi yang seharusnya kita ubah untuk memiliki implementasi baru.

Apa yang ingin kami lakukan adalah memiliki kemampuan untuk mengkonfigurasi implementasi dependensi yang berbeda untuk memuaskan banyak klien ini. Sayangnya, DI tampaknya bukan pilihan karena klien tidak menerima suntikan dengan konstruktor atau setter.

Opsi:

1) Refactor implementasi layanan yang digunakan klien sehingga ia melakukan apa yang dibutuhkan klien sekarang. Bang kita sudah selesai. Tidak fleksibel. Tidak rumit.

2) Refactor implementasi sehingga mendelegasikan pekerjaannya ke ketergantungan lain yang diperoleh melalui pabrik. Sekarang kita dapat mengontrol implementasi mana yang mereka gunakan dengan refactoring pabrik.

3) Refactor implementasi sehingga mendelegasikan pekerjaannya ke ketergantungan lain yang diperolehnya melalui pencari layanan. Sekarang kita dapat mengontrol implementasi mana yang mereka semua gunakan dengan mengkonfigurasi locator layanan yang mungkin hanya berupa hashmapstring ke objek dengan sedikit casting yang terjadi.

4) Sesuatu yang bahkan belum kupikirkan.

Objektif:

Minimalkan kerusakan desain yang disebabkan oleh menyeret kode klien yang dirancang dengan buruk ke masa depan tanpa menambah kompleksitas yang tidak ada gunanya.

Klien seharusnya tidak mengetahui atau mengendalikan implementasi dependensi mereka tetapi mereka bersikeras untuk membangunnya bersama new. Kami tidak bisa mengendalikan, newtetapi kami mengontrol kelas yang mereka bangun.

Pertanyaan saya:

Apa yang gagal saya pertimbangkan?


Pertanyaan dari Doc Brown

apakah Anda benar-benar membutuhkan kemungkinan untuk mengkonfigurasi antar implementasi yang berbeda? Untuk tujuan apa?

Kelincahan. Banyak yang tidak diketahui. Manajemen menginginkan potensi perubahan. Kehilangan ketergantungan hanya pada dunia luar. Juga menguji.

apakah Anda memerlukan mekanik waktu berjalan, atau hanya kompilasi waktu mekanik untuk beralih di antara implementasi yang berbeda? Mengapa?

Mekanika waktu kompilasi kemungkinan cukup. Kecuali untuk pengujian.

granularity mana yang Anda perlukan untuk beralih antar implementasi? Semua sekaligus? Per modul (masing-masing berisi sekelompok kelas)? Per kelas?

Dari 1001 hanya satu yang dijalankan melalui sistem pada satu waktu. Mengubah apa yang digunakan semua klien sekaligus kemungkinan besar tidak masalah. Kontrol individu terhadap ketergantungan sepertinya penting.

siapa yang perlu mengendalikan sakelar? Hanya tim pengembang Anda? Administrator? Setiap klien sendiri? Atau pengembang pemeliharaan untuk kode klien? Jadi seberapa mudah / kuat / tidak mudah mekanik perlu?

Dev untuk pengujian. Administrator sebagai perubahan dependensi perangkat keras eksternal. Perlu mudah untuk menguji dan mengonfigurasi.


Tujuan kami adalah untuk menunjukkan bahwa sistem dapat dibuat kembali dengan cepat dan dimodernisasi.


kasus penggunaan aktual untuk sakelar implementasi?

Salah satunya adalah, beberapa data akan disediakan oleh perangkat lunak sampai solusi perangkat keras siap.

candied_orange
sumber
1
Saya tidak merasa Anda akan mencapai banyak hal dengan menyimpan pabrik atau pelacak di negara global. Kenapa mengganggu? Apakah Anda akan menguji klien menggantikan ketergantungan?
Basilevs
Pertimbangkan untuk menggunakan pemuat kelas khusus.
Basilevs
Karena penasaran, apa yang dilakukan sistem ini?
Perdana

Jawaban:

7

Yah, saya tidak yakin saya memahami detail teknis dan perbedaan yang tepat dari solusi yang didukung sepenuhnya, tetapi IMHO Anda harus terlebih dahulu mencari tahu jenis fleksibilitas yang Anda butuhkan.

Pertanyaan yang harus Anda tanyakan pada diri sendiri adalah:

  • apakah Anda benar-benar membutuhkan kemungkinan untuk mengkonfigurasi antar implementasi yang berbeda? Untuk tujuan apa?

  • apakah Anda memerlukan mekanik waktu berjalan, atau hanya kompilasi waktu mekanik untuk beralih di antara implementasi yang berbeda? Mengapa?

  • granularity mana yang Anda perlukan untuk beralih antar implementasi? Semua sekaligus? Per modul (masing-masing berisi sekelompok kelas)? Per kelas?

  • siapa yang perlu mengendalikan sakelar? Hanya tim pengembang Anda? Administrator? Setiap klien sendiri? Atau pengembang pemeliharaan untuk kode klien? Jadi seberapa mudah / kuat / tidak mudah mekanik perlu?

Dengan memikirkan jawaban atas pertanyaan-pertanyaan ini, pilih solusi paling sederhana yang dapat Anda pikirkan yang memberikan Anda fleksibilitas yang dibutuhkan. Jangan menerapkan fleksibilitas apa pun yang Anda tidak yakin tentang "berjaga-jaga" jika itu berarti upaya tambahan.

Sebagai jawaban atas jawaban Anda: jika Anda memiliki setidaknya satu kasing nyata , gunakan kasing untuk memvalidasi keputusan desain Anda. Gunakan kasing itu untuk mencari tahu solusi apa yang paling cocok untuk Anda. Coba saja jika "pabrik" atau "pelacak layanan" memberi Anda apa yang Anda butuhkan, atau jika Anda membutuhkan sesuatu yang lain. Jika Anda berpikir kedua solusi sama-sama baik untuk kasus Anda, lempar dadu.

Doc Brown
sumber
Pertanyaan bagus! Silakan lihat pembaruan.
candied_orange
Diperbarui dengan use case aktual.
candied_orange
@CandiedOrange: Saya tidak bisa memberi Anda ikan, saya hanya bisa mencoba membantu Anda memancing sendiri :-)
Doc Brown
Dimengerti Saya hanya menatap air bertanya-tanya apakah saya perlu umpan yang lebih baik atau lubang pancing yang berbeda. Saya ingin melakukan DI yang tepat tetapi situasi ini tampaknya tidak memungkinkan untuk itu.
candied_orange
1
@CandiedOrange Jangan terpaku pada keinginan untuk melakukan DI karena itu "baik" atau "lebih baik" daripada yang lain. DI adalah salah satu solusi khusus untuk suatu masalah (atau terkadang beberapa). Tapi, itu tidak selalu merupakan solusi yang paling "pas". Jangan jatuh cinta padanya ... perlakukan seperti itu. Itu alat.
svidgen
2

Hanya untuk memastikan saya mendapatkan ini dengan benar. Anda memiliki beberapa layanan yang dibuat dari beberapa kelas, misalnya C1,...,Cndan sekelompok klien yang langsung menelepon new Ci(...). Jadi saya pikir saya setuju dengan struktur umum dari solusi Anda yaitu membuat layanan internal baru dengan beberapa kelas baru D1,...,Dnyang bagus dan modern dan menyuntikkan dependensi mereka (memungkinkan dependensi tersebut melalui stack) dan kemudian menulis ulang Ciuntuk melakukan apa-apa selain instantiate dan pindah ke Di. Pertanyaannya adalah bagaimana melakukannya dan Anda menyarankan beberapa cara masuk 2dan 3.

Untuk memberikan saran serupa ke 2. Anda dapat menggunakan injeksi dependensi di seluruh Didan secara internal dan kemudian membuat akar komposisi normal R(menggunakan kerangka kerja jika Anda menganggapnya sesuai) yang bertanggung jawab untuk menyusun objek grafik. Dorong di Rbelakang pabrik statis dan biarkan masing-masing Cimenyelesaikannya Di. Jadi misalnya Anda mungkin punya

public class OldClassI {
    private final NewClassI newImplementation;

    public OldClassI(Object parameter) {
        this.newImplementation = CompositionRoot.getInstance().getNewClassI(parameter);
    }
}

Pada dasarnya ini adalah solusi Anda 2, tetapi mengumpulkan semua pabrik Anda ke satu lokasi bersama dengan sisa injeksi ketergantungan.

walpen
sumber
Saya setuju dengan ini. Hanya tidak yakin bagaimana ini tidak sama dengan pencari lokasi dari opsi 3. Apakah Anda berharap untuk membuat instance baru dengan setiap panggilan getInstance()?
candied_orange
@CandiedOrange Ini mungkin hanya sebuah clash dalam penggunaan, bagi saya seorang pencari lokasi adalah sesuatu yang sangat spesifik yang pada dasarnya hanyalah sebuah hashmap dari tipe ke objek, sedangkan ini komposisi root hanyalah sebuah objek dengan sekelompok metode yang membangun objek lain.
walpen
1

Mulailah dengan implementasi sederhana, tidak mewah, dan tunggal.

Jika nanti Anda perlu membuat implementasi tambahan, itu adalah pertanyaan kapan keputusan implementasi terjadi.

Jika Anda membutuhkan fleksibilitas "waktu pemasangan" (setiap instalasi klien menggunakan implementasi statis tunggal), Anda masih tidak perlu melakukan hal-hal lain. Anda hanya menawarkan DLL atau SO yang berbeda (atau apa pun format lib Anda). Klien hanya perlu meletakkan yang benar di libfolder ...

Jika Anda membutuhkan fleksibilitas runtime, Anda hanya perlu adaptor tipis dan mekanisme pemilih implementasi. Apakah Anda menggunakan pabrik, pelacak, atau wadah IoC sebagian besar dapat diperdebatkan. Satu-satunya perbedaan signifikan antara adaptor dan pelacak adalah A) Penamaan dan B) Apakah objek yang dikembalikan adalah singleton atau instance khusus. Dan perbedaan besar antara wadah IoC dengan pabrik / pelacak adalah siapa yang memanggil siapa . (Seringkali masalah preferensi pribadi.)

svidgen
sumber