Apakah yang disebut "masalah lintas sektoral" merupakan alasan yang valid untuk memecah SOLID / DI / IoC?

43

Rekan-rekan saya suka mengatakan "logging / caching / dll. Adalah masalah lintas sektoral" dan kemudian melanjutkan menggunakan singleton yang sesuai di mana-mana. Namun mereka menyukai IoC dan DI.

Apakah ini benar-benar alasan yang sah untuk melanggar prinsip SOLI D ?

Sarang
sumber
27
Saya telah menemukan bahwa prinsip-prinsip SOLID sebagian besar hanya berguna bagi mereka yang sudah memiliki pengalaman yang diperlukan untuk tidak mengikutinya.
svidgen
1
Saya telah menemukan istilah "perhatian lintas sektoral" menjadi istilah yang cukup spesifik (terkait dengan aspek-aspek) dan tidak harus identik dengan singleton. Logging dapat menjadi masalah lintas sektoral dalam arti bahwa Anda kadang-kadang ingin mencatat pesan umum di beberapa tempat dengan cara yang sama (misalnya mencatat setiap panggilan ke metode layanan dengan siapa yang membuat panggilan atau beberapa tipe audit logging lainnya). Namun, saya berpendapat bahwa penebangan (dalam arti umum) bukan masalah lintas sektoral hanya karena digunakan di mana-mana. Saya pikir ini lebih dari "keprihatinan di mana-mana" meskipun itu bukan istilah standar.
Laju
4
@viden prinsip SOLID juga berguna ketika mereka yang tidak mengenalnya meninjau kode Anda dan bertanya mengapa Anda melakukannya dengan cara itu. Senang bisa menunjuk pada sebuah prinsip dan berkata, "itu sebabnya"
candied_orange
1
Apakah Anda punya contoh mengapa menurut Anda logging adalah kasus khusus? Ini saluran yang cukup sederhana untuk mengarahkan ulang beberapa data, biasanya bagian dari kerangka X apa pun yang Anda gunakan.
ksiimson

Jawaban:

42

Tidak.

SOLID ada sebagai pedoman untuk memperhitungkan perubahan yang tak terhindarkan. Apakah Anda benar - benar tidak akan pernah mengubah perpustakaan logging Anda, atau target, atau pemfilteran, atau pemformatan, atau ...? Apakah Anda benar - benar tidak akan mengubah perpustakaan caching Anda, atau target, atau strategi, atau pelingkupan, atau ...?

Tentu saja kamu. Paling tidak , Anda akan ingin mengejek hal-hal ini dengan cara yang waras untuk mengisolasi mereka untuk pengujian. Dan jika Anda ingin mengisolasi mereka untuk pengujian, Anda kemungkinan akan mengalami alasan bisnis di mana Anda ingin mengisolasi mereka untuk alasan kehidupan nyata.

Dan Anda kemudian akan mendapatkan argumen bahwa logger itu sendiri akan menangani perubahan. "Oh, jika target / filtering / format / strategi berubah, maka kita hanya akan mengubah konfigurasi!" Itu sampah. Anda tidak hanya sekarang memiliki Obyek Tuhan yang menangani semua hal ini, Anda juga menulis kode Anda dalam XML (atau serupa) di mana Anda tidak mendapatkan analisis statis, Anda tidak mendapatkan kesalahan waktu kompilasi, dan Anda tidak Saya tidak benar-benar mendapatkan tes unit yang efektif.

Apakah ada kasus yang melanggar pedoman SOLID? Benar. Kadang-kadang hal - hal tidak akan berubah (tanpa memerlukan penulisan ulang penuh). Kadang-kadang sedikit pelanggaran terhadap LSP adalah solusi terbersih. Terkadang membuat antarmuka yang terisolasi tidak memberikan nilai.

Tetapi penebangan dan caching (dan masalah lintas sektoral lainnya) tidak demikian. Biasanya itu adalah contoh bagus dari masalah kopling dan desain yang Anda dapatkan ketika Anda mengabaikan pedoman.

Telastyn
sumber
22
Apa alternatif yang Anda miliki? Menyuntikkan ILogger ke setiap kelas yang Anda tulis? Menulis dekorator untuk setiap kelas yang membutuhkan logger?
Robert Harvey
16
Ya. Jika sesuatu adalah ketergantungan, buatlah ketergantungan . Dan jika itu berarti dependensi terlalu banyak, atau Anda melewati logger di suatu tempat itu seharusnya tidak pergi - bagus , sekarang Anda dapat memperbaiki desain Anda.
Telastyn
20
Masalah sebenarnya yang saya miliki dengan IOC dogmatis adalah bahwa hampir semua kode modern tergantung pada sesuatu yang tidak disuntikkan atau diabstraksi. Jika Anda menulis C #, misalnya, Anda tidak akan sering abstrak Stringatau Int32atau bahkan Listkeluar dari modul Anda. Hanya ada sejauh mana masuk akal dan waras untuk merencanakan perubahan. Dan, di luar tipe "inti" yang paling jelas, membedakan apa yang mungkin Anda ubah sebenarnya hanyalah masalah pengalaman dan penilaian.
svidgen
6
@viden - Saya harap Anda tidak membaca jawaban saya sebagai advokasi IOC dogmatis. Dan hanya karena kita tidak mengabstraksi tipe inti ini (dan hal-hal lain di mana dengan hati-hati) tidak berarti tidak apa-apa untuk memiliki Daftar global / String / Int / dll.
Telastyn
38

Iya

Ini adalah inti keseluruhan dari istilah "kepedulian lintas sektoral" - ini berarti sesuatu yang tidak sesuai dengan prinsip SOLID.

Di sinilah idealisme bertemu dengan kenyataan.

Orang-orang semi-baru untuk SOLID dan lintas sektoral sering mengalami tantangan mental ini. Tidak apa-apa, jangan panik. Berusaha keras untuk memasukkan semuanya ke dalam istilah SOLID, tetapi ada beberapa tempat seperti logging dan caching di mana SOLID tidak masuk akal. Cross-cutting adalah saudara laki-laki SOLID, mereka berjalan beriringan.

Klom Dark
sumber
9
Jawaban yang masuk akal, praktis, dan non-dogmatis.
user1936
11
Bisakah Anda memberi tahu kami mengapa kelima prinsip SOLID ini dilanggar oleh keprihatinan yang saling terkait? Saya memiliki masalah untuk memahami itu.
Doc Brown
4
Ya. Saya berpotensi memikirkan alasan bagus untuk "mematahkan" setiap prinsip secara individual; tetapi tidak ada satu alasan untuk mematahkan semua 5!
svidgen
1
Ini akan ideal bagi saya untuk tidak harus membenturkan kepala ke dinding setiap kali saya perlu mengejek logger / cache singleton untuk tes unit. Bayangkan bagaimana rasanya menguji unit aplikasi web tanpa HttpContextBase(yang diperkenalkan untuk alasan ini). Saya tahu pasti bahwa kenyataan saya akan benar-benar masam tanpa kelas ini.
devnull
2
@devnull mungkin itu masalahnya, alih-alih perhatiannya sendiri ...
Boris the Spider
25

Untuk logging saya pikir itu. Logging bersifat meresap dan umumnya tidak terkait dengan fungsionalitas layanan. Sudah umum dan dipahami dengan baik untuk menggunakan pola singleton kerangka logging. Jika tidak, Anda membuat dan menyuntikkan penebang di mana - mana dan Anda tidak menginginkannya.

Satu masalah dari atas adalah bahwa seseorang akan berkata 'tetapi bagaimana saya bisa menguji penebangan?' . Pikiran saya adalah bahwa saya biasanya tidak menguji logging, di luar menyatakan bahwa saya benar-benar dapat membaca file log dan memahaminya. Ketika saya melihat logging diuji, biasanya karena seseorang perlu menegaskan bahwa suatu kelas telah benar-benar melakukan sesuatu dan mereka menggunakan pesan log untuk mendapatkan umpan balik itu. Saya lebih suka mendaftarkan beberapa pendengar / pengamat di kelas itu dan menegaskan dalam tes saya bahwa yang dipanggil. Anda kemudian dapat memasukkan acara Anda masuk ke pengamat itu.

Saya pikir caching adalah skenario yang sama sekali berbeda.

Brian Agnew
sumber
3
Telah mencoba-coba sedikit di FP sekarang saya telah datang untuk menumbuhkan minat besar dalam menggunakan komposisi fungsi (mungkin monadik) untuk menanamkan hal-hal seperti logging, penanganan kesalahan dll dalam kasus penggunaan Anda tanpa memasukkan semua itu dalam logika bisnis inti ( lihat fsharpforfunandprofit.com/rop )
sara
5
Penebangan seharusnya tidak menyebar. Jika ya, maka Anda login terlalu banyak dan Anda hanya membuat kebisingan untuk diri sendiri ketika Anda benar-benar perlu melihat log itu. Dengan menyuntikkan ketergantungan logger, Anda dipaksa untuk berpikir apakah Anda benar-benar perlu mencatat sesuatu atau tidak.
RubberDuck
12
@RubberDuck - Katakan padaku bahwa "logging seharusnya tidak meresap" ketika saya mendapatkan laporan bug dari lapangan dan satu-satunya kemampuan debug saya harus mencari tahu apa yang terjadi adalah file log yang saya tidak ingin buat meresap. Setelah dipelajari, logging harus "meresap", sangat meresap.
Dunk
15
@RubberDuck: Dengan perangkat lunak server, logging adalah satu-satunya cara untuk bertahan hidup. Ini satu-satunya cara untuk mengetahui bug yang terjadi 12 jam yang lalu, bukan sekarang di laptop Anda sendiri. Jangan khawatir tentang kebisingan. Gunakan perangkat lunak manajemen log sehingga Anda dapat meminta log Anda (idealnya Anda juga harus mengatur alarm yang akan mengirim email kepada Anda pada log kesalahan)
slebetman
6
Staf pendukung kami menghubungi saya dan memberi tahu saya "pelanggan mengklik beberapa halaman dan muncul kesalahan." Saya bertanya kepada mereka apa kesalahannya, mereka tidak tahu. Saya bertanya apa yang diklik khusus pelanggan, mereka tidak tahu. Saya bertanya apakah mereka bisa bereproduksi, mereka tidak bisa. Saya setuju logging sebagian besar dapat dicapai dengan penebang yang digunakan dengan baik di beberapa titik engsel utama tetapi pesan-pesan aneh kecil di sana-sini juga sangat berharga. Ketakutan logging menyebabkan perangkat lunak berkualitas rendah. Jika Anda memiliki terlalu banyak data, pangkas kembali. Jangan optimalkan secara prematur.
Laju
12

2 sen saya ...

Iya dan tidak.

Anda seharusnya tidak pernah benar - benar melanggar prinsip-prinsip yang Anda adopsi; tetapi, prinsip Anda harus selalu diberi nuansa dan diadopsi untuk mencapai tujuan yang lebih tinggi. Jadi, dengan pemahaman yang dikondisikan dengan baik, beberapa jelas pelanggaran mungkin tidak aktual pelanggaran "roh" atau "isi prinsip secara keseluruhan."

Prinsip-prinsip SOLID khususnya, selain membutuhkan banyak nuansa, pada akhirnya tunduk pada tujuan "memberikan perangkat lunak yang berfungsi dan dapat dirawat." Jadi, mematuhi prinsip SOLID tertentu adalah merugikan diri sendiri dan bertentangan dengan diri sendiri ketika melakukan hal tersebut bertentangan dengan tujuan SOLID. Dan di sini, saya sering perhatikan bahwa memberikan mengalahkan rawatan .

Jadi, bagaimana dengan D di SOLID ? Yah, itu berkontribusi pada peningkatan rawatan dengan membuat modul yang dapat digunakan kembali relatif agnostik untuk konteksnya. Dan kita dapat mendefinisikan "modul yang dapat digunakan kembali" sebagai "kumpulan kode yang Anda rencanakan untuk digunakan dalam konteks lain yang berbeda." Dan itu berlaku untuk satu fungsi, kelas, set kelas, dan program.

Dan ya, mengubah implementasi logger mungkin menempatkan modul Anda ke dalam "konteks lain yang berbeda."

Jadi, izinkan saya menawarkan dua peringatan besar saya :

Pertama: Menggambar garis di sekitar blok kode yang merupakan "modul yang dapat digunakan kembali" adalah masalah penilaian profesional. Dan penilaian Anda tentu terbatas pada pengalaman Anda.

Jika Anda tidak saat ini berencana untuk menggunakan modul dalam konteks lain, itu adalah mungkin OK untuk itu bergantung tak berdaya di atasnya. Peringatan ke peringatan: Rencana Anda mungkin salah - tetapi itu juga OK. Semakin lama Anda menulis modul demi modul, semakin intuitif dan akurat perasaan Anda apakah "Aku akan membutuhkan ini lagi suatu hari nanti". Tetapi, Anda mungkin tidak akan pernah bisa secara retrospektif berkata, "Saya telah memodulasi dan memisahkan segala sesuatu sejauh mungkin, tetapi tanpa kelebihan ."

Jika Anda merasa bersalah tentang kesalahan penilaian Anda, buka pengakuan dan lanjutkan ...

Kedua: Pembalikan kontrol tidak sama dengan ketergantungan injeksi .

Ini terutama benar ketika Anda mulai menyuntikkan dependensi dan mual . Dependency Injection adalah taktik yang berguna untuk strategi IoC yang menyeluruh. Tapi, saya berpendapat bahwa DI kurang manjur dibandingkan beberapa taktik lain - seperti menggunakan antarmuka dan adaptor - satu titik paparan konteks dari dalam modul.

Dan mari kita benar-benar fokus pada ini sebentar. Karena, walaupun Anda menyuntikkan Logger mual iklan , Anda harus menulis kode pada Loggerantarmuka. Anda tidak dapat mulai menggunakan yang baru Loggerdari vendor yang berbeda yang mengambil parameter dalam urutan yang berbeda. Kemampuan itu berasal dari pengkodean, di dalam modul, terhadap antarmuka yang ada di dalam modul dan yang memiliki submodule tunggal (Adaptor) di dalamnya untuk mengelola ketergantungan.

Dan jika Anda mengkode terhadap Adaptor, apakah Loggerdisuntikkan ke Adaptor itu atau ditemukan oleh Adaptor umumnya sangat tidak signifikan untuk tujuan rawatan keseluruhan. Dan yang lebih penting, jika Anda memiliki Adaptor tingkat modul, mungkin hanya masuk akal untuk menyuntikkannya ke apa saja. Ini ditulis untuk modul.

tl; dr - Berhentilah meributkan prinsip tanpa mempertimbangkan mengapa Anda menggunakan prinsip tersebut. Dan, lebih praktisnya, hanya membangun sebuah Adapteruntuk setiap modul. Gunakan penilaian Anda saat memutuskan di mana Anda menggambar batas "modul". Dari dalam setiap modul, silakan dan merujuk langsung ke Adapter. Dan tentu saja, menyuntikkan logger nyata ke Adapter- tetapi tidak ke setiap hal kecil yang mungkin membutuhkannya.

svidgen
sumber
4
Sobat ... saya akan memberikan jawaban yang lebih pendek, tetapi saya tidak punya waktu.
svidgen
2
+1 untuk menggunakan Adaptor. Anda perlu mengisolasi dependensi pada komponen pihak ke-3 agar memungkinkannya untuk diganti sedapat mungkin. Pencatatan adalah target yang mudah untuk ini - banyak implementasi logging ada dan sebagian besar memiliki API yang serupa, sehingga implementasi adaptor sederhana dapat memungkinkan Anda untuk mengubahnya dengan sangat mudah. Dan kepada orang-orang yang mengatakan Anda tidak akan pernah mengubah penyedia logging Anda: Saya harus melakukan ini, dan itu menyebabkan rasa sakit karena saya tidak menggunakan adaptor.
Jules
"Prinsip-prinsip SOLID pada khususnya, selain membutuhkan banyak nuansa, pada akhirnya tunduk pada tujuan" memberikan perangkat lunak yang berfungsi dan dapat dipelihara. "" - Ini adalah salah satu pernyataan terbaik yang pernah saya lihat. Sebagai pembuat kode ringan-OCD, saya memiliki banyak perjuangan dengan idealisme vs produktivitas.
DVK
Setiap kali saya melihat +1 atau komentar pada jawaban lama, saya membaca jawaban saya lagi dan menemukan, lagi, bahwa saya seorang penulis yang sangat tidak teratur dan tidak jelas ... Saya menghargai komentarnya, @DVK.
svidgen
Adaptor adalah penyelamat hidup, mereka tidak membutuhkan biaya banyak dan membuat hidup Anda jauh lebih mudah, khususnya ketika Anda ingin menerapkan SOLID. Menguji sangat mudah bagi mereka.
Alan
8

Gagasan bahwa penebangan harus selalu dilaksanakan sebagai singleton adalah salah satu kebohongan yang telah diberitahukan begitu sering sehingga mendapatkan daya tarik.

Selama sistem operasi modern telah dikenali, Anda mungkin ingin masuk ke banyak tempat, tergantung pada sifat keluarannya .

Perancang sistem harus terus-menerus mempertanyakan kemanjuran solusi masa lalu sebelum secara membabi buta memasukkannya dalam yang baru. Jika mereka tidak melakukan ketekunan seperti itu, maka mereka tidak melakukan pekerjaan mereka.

Robbie Dee
sumber
2
Apa solusi yang Anda ajukan? Apakah ini menyuntikkan ILogger ke setiap kelas yang Anda tulis? Bagaimana dengan menggunakan pola dekorator?
Robert Harvey
4
Tidak benar-benar menjawab pertanyaan saya sekarang, bukan? Saya menyatakan polanya hanya sebagai contoh ... Tidak harus seperti itu jika Anda memiliki sesuatu yang lebih baik dalam pikiran.
Robert Harvey
8
Saya tidak benar-benar memahami jawaban ini, dalam hal proposal konkret
Brian Agnew
3
@RobbieDee - Jadi Anda mengatakan bahwa pembalakan harus dilaksanakan dengan cara yang paling berbelit-belit dan tidak nyaman dengan "off-chance" yang mungkin ingin kita masuki ke beberapa tempat? Bahkan jika perubahan seperti itu terjadi, apakah Anda benar-benar berpikir menambahkan fungsionalitas ke instance Logger yang ada akan lebih berfungsi daripada semua upaya untuk melewati Logger itu di antara kelas dan mengubah antarmuka ketika Anda memutuskan ingin Logger atau tidak aktif? puluhan proyek di mana penebangan banyak tempat tidak akan pernah terjadi?
Dunk
2
Re: "Anda mungkin ingin login ke beberapa tempat tergantung pada sifat dari output": Tentu, tetapi cara terbaik untuk mengatasinya adalah dalam kerangka logging , daripada mencoba menyuntikkan beberapa dependensi logging yang terpisah. (Kerangka kerja logging umum sudah mendukung ini.)
ruakh
4

Penebangan yang benar-benar merupakan kasus khusus.

@Telastyn menulis:

Apakah Anda benar-benar tidak akan pernah mengubah perpustakaan logging Anda, atau target, atau pemfilteran, atau pemformatan, atau ...?

Jika Anda mengantisipasi bahwa Anda mungkin perlu mengubah perpustakaan logging Anda, maka Anda harus menggunakan fasad; yaitu SLF4J jika Anda berada di dunia Java.

Adapun sisanya, perpustakaan logging yang layak menangani perubahan ke mana logging pergi, peristiwa apa yang disaring, bagaimana peristiwa log diformat menggunakan file konfigurasi logger dan (jika perlu) kelas plugin kustom. Ada sejumlah alternatif di luar rak.

Singkatnya, ini adalah masalah yang diselesaikan ... untuk logging ... dan karenanya tidak perlu menggunakan Dependency Injection untuk menyelesaikannya.

Satu-satunya kasus di mana DI mungkin bermanfaat (lebih dari pendekatan pendataan standar) adalah jika Anda ingin menjadikan pendataan aplikasi Anda ke unit testing. Namun, saya menduga sebagian besar pengembang akan mengatakan bahwa logging bukan bagian dari fungsi kelas, dan bukan sesuatu yang perlu diuji.

@Telastyn menulis:

Dan Anda kemudian akan mendapatkan argumen bahwa logger itu sendiri akan menangani perubahan. "Oh, jika target / filtering / pemformatan / strategi berubah, maka kita hanya akan mengubah konfigurasi!" Itu sampah. Anda tidak hanya sekarang memiliki Obyek Tuhan yang menangani semua hal ini, Anda juga menulis kode Anda dalam XML (atau serupa) di mana Anda tidak mendapatkan analisis statis, Anda tidak mendapatkan kesalahan waktu kompilasi, dan Anda tidak Saya tidak benar-benar mendapatkan tes unit yang efektif.

Saya khawatir itu adalah teori yang sangat teoritis. Dalam praktiknya, sebagian besar pengembang dan integrator sistem SEPERTI fakta bahwa Anda dapat mengonfigurasi pencatatan melalui file konfigurasi. Dan mereka SUKA fakta bahwa mereka tidak diharapkan untuk menguji unit logging modul.

Tentu, jika Anda mengisi konfigurasi logging maka Anda bisa mendapatkan masalah, tetapi mereka akan bermanifestasi sebagai salah satu aplikasi gagal selama startup atau terlalu banyak / terlalu sedikit logging. 1) Masalah-masalah ini mudah diperbaiki dengan memperbaiki kesalahan dalam file konfigurasi. 2) Alternatifnya adalah siklus build / analysis / test / deploy lengkap setiap kali Anda membuat perubahan ke level logging. Itu tidak bisa diterima.

Stephen C
sumber
3

Ya dan Tidak !

Ya: Saya pikir masuk akal bahwa subsistem yang berbeda (atau lapisan semantik atau pustaka atau gagasan bundling modular lainnya) masing-masing menerima (yang sama atau) logger yang mungkin berbeda selama inisialisasi mereka daripada semua subsistem yang mengandalkan singleton bersama yang sama .

Namun,

Tidak: pada saat yang sama tidak masuk akal untuk membuat parameter logging di setiap objek kecil (dengan konstruktor atau metode instance). Untuk menghindari mengasapi yang tidak perlu dan tidak berguna, entitas yang lebih kecil harus menggunakan logger singleton dari konteks terlampir mereka.


Ini adalah salah satu alasan di antara banyak orang lain untuk memikirkan modularitas dalam level: metode digabungkan ke dalam kelas, sementara kelas digabungkan ke dalam subsistem dan / atau lapisan semantik. Bundel yang lebih besar ini adalah alat abstraksi yang berharga; kita harus memberikan pertimbangan yang berbeda dalam batas-batas modular daripada ketika melintasinya.

Erik Eidt
sumber
3

Pertama dimulai dengan cache singleton yang kuat, hal-hal berikutnya yang Anda lihat adalah singleton yang kuat untuk lapisan basis data yang memperkenalkan keadaan global, API non-deskriptif classes dan kode yang tidak dapat diuji.

Jika Anda memutuskan untuk tidak memiliki singleton untuk basis data, mungkin bukan ide yang baik untuk memiliki singleton untuk cache, bagaimanapun, mereka mewakili konsep yang sangat mirip, penyimpanan data, hanya menggunakan mekanisme yang berbeda.

Menggunakan singleton di kelas ternyata kelas yang memiliki jumlah dependensi tertentu ke kelas yang secara teoritis memiliki jumlah tak terbatas, karena Anda tidak pernah tahu apa yang sebenarnya tersembunyi di balik metode statis.

Dalam dekade terakhir saya telah menghabiskan pemrograman, hanya ada satu kasus di mana saya menyaksikan upaya untuk mengubah logika logging (yang kemudian ditulis sebagai singleton). Jadi, meskipun saya menyukai suntikan ketergantungan, penebangan sebenarnya bukan masalah besar. Cache, di sisi lain, saya pasti akan selalu menjadikannya sebagai ketergantungan.

Andy
sumber
Ya, pencatatan jarang berubah dan biasanya tidak harus berupa modul yang dapat ditukar. Namun, saya pernah mencoba mengetes unit kelas pembantu logging, yang memiliki ketergantungan statis pada sistem logging. Saya memutuskan mekanisme termudah untuk membuatnya dapat diuji adalah dengan menjalankan kelas yang diuji dalam proses terpisah, mengkonfigurasi logger untuk menulis ke STDOUT, dan menguraikan output dalam kasus pengujian saya ಠ_ಠ Saya punya pengalaman serupa dengan jam di mana Anda d jelas tidak pernah menginginkan apapun selain waktu nyata, kan? Kecuali saat pengujian zona waktu / DST kasus tepi, tentu saja ...
Amon
@amon: Jam seperti masuk, sudah ada mekanisme lain yang melayani tujuan yang sama dengan DI, yaitu Joda-Time dan banyak portnya. (Bukannya ada yang salah dengan menggunakan DI sebagai gantinya; tetapi lebih mudah menggunakan Joda-Time secara langsung daripada mencoba menulis adaptor suntik khusus, dan saya belum pernah melihat ada yang menyesal melakukannya.)
ruakh
@amon "Saya punya pengalaman serupa dengan jam di mana Anda jelas tidak pernah menginginkan apa pun selain waktu nyata, bukan? Kecuali saat menguji zona waktu / kasus tepi DST, tentu saja ..." - atau ketika Anda menyadari bahwa bug memiliki rusak database Anda dan satu-satunya harapan untuk mendapatkannya kembali adalah untuk mengurai log peristiwa Anda dan memutar ulang itu mulai dari cadangan terakhir ... tapi tiba-tiba Anda membutuhkan semua kode Anda untuk bekerja berdasarkan cap waktu dari entri log saat ini daripada saat ini waktu.
Jules
3

Ya dan Tidak, tetapi kebanyakan Tidak

Saya menganggap sebagian besar percakapan didasarkan pada contoh statis vs disuntikkan. Tidak ada yang mengusulkan agar penebangan merusak SRP saya kira? Kita terutama berbicara tentang "prinsip inversi ketergantungan". Tbh saya sebagian besar setuju dengan tidak ada jawaban Telastyn.

Kapan boleh menggunakan statika? Karena jelas itu kadang oke. Jawaban ya poin dari manfaat abstraksi dan jawaban "tidak" menunjukkan bahwa itu adalah sesuatu yang Anda bayar. Salah satu alasan mengapa pekerjaan Anda sulit adalah karena tidak ada satu jawaban yang dapat Anda tulis dan terapkan pada semua situasi.

Mengambil: Convert.ToInt32("1")

Saya lebih suka ini:

private readonly IConverter _converter;

public MyClass(IConverter converter)
{
   Guard.NotNull(converter)
   _converter = conveter
}

.... 
var foo = _converter.ToInt32("1");

Mengapa? Saya menerima bahwa saya perlu memperbaiki kode jika saya memerlukan fleksibilitas untuk menukar kode konversi. Saya menerima bahwa saya tidak akan bisa mengejek ini. Saya percaya bahwa kesederhanaan dan kesederhanaan sepadan dengan perdagangan ini.

Melihat ujung spektrum yang lain, jika IConvertera SqlConnection, saya akan cukup ngeri melihatnya sebagai panggilan statis. Alasan mengapa itu jelas sekali. Saya akan menunjukkan bahwa a SQLConnectionbisa cukup "lintas silang" dalam aplikasi, jadi saya tidak akan menggunakan kata-kata yang tepat.

Apakah Logging lebih seperti a SQLConnectionatau Convert.ToInt32? Saya akan mengatakan lebih seperti 'SQLConnection`.

Anda seharusnya mengejek Logging . Ia berbicara kepada dunia luar. Saat menulis metode menggunakan Convert.ToIn32, saya menggunakannya sebagai alat untuk menghitung beberapa output lain yang dapat diuji secara terpisah dari kelas. Saya tidak perlu memeriksa Convertdipanggil dengan benar ketika memeriksa bahwa "1" + "2" == "3". Penebangan berbeda, ini merupakan output kelas yang sepenuhnya independen. Saya berasumsi ini adalah output yang memiliki nilai bagi Anda, tim pendukung, dan bisnis. Kelas Anda tidak berfungsi jika logging tidak benar, sehingga unit test tidak boleh lulus. Anda harus menguji apa yang dicatat log kelas Anda. Saya pikir ini adalah argumen pembunuh, saya benar-benar bisa berhenti di sini.

Saya juga berpikir itu adalah sesuatu yang sangat mungkin berubah. Pencatatan yang baik tidak hanya mencetak string, ini adalah pandangan tentang apa yang sedang dilakukan aplikasi Anda (saya penggemar pencatatan berdasarkan peristiwa). Saya telah melihat pembuatan log dasar berubah menjadi UI pelaporan yang cukup rumit. Jelas jauh lebih mudah untuk menuju ke arah ini jika logging Anda terlihat seperti _logger.Log(new ApplicationStartingEvent())dan kurang disukai Logger.Log("Application has started"). Orang mungkin berpendapat bahwa ini adalah menciptakan inventaris untuk masa depan yang mungkin tidak pernah terjadi, ini adalah panggilan penilaian dan kebetulan saya pikir itu layak.

Bahkan dalam proyek pribadi saya, saya membuat UI non logging murni menggunakan _loggeruntuk mencari tahu apa yang sedang dilakukan aplikasi. Ini berarti saya tidak perlu menulis kode untuk mencari tahu apa yang sedang dilakukan aplikasi, dan saya berakhir dengan logging yang solid. Saya merasa seolah-olah sikap saya terhadap penebangan sederhana dan tidak berubah, gagasan itu tidak akan terjadi pada saya.

Jadi saya setuju dengan Telastyn untuk kasus logging.

Nathan Cooper
sumber
Ini adalah bagaimana saya mencatat secara tidak sengaja . Saya ingin menautkan ke artikel atau sesuatu, tetapi saya tidak dapat menemukannya. Jika Anda berada di dunia .NET, dan mencari pencatatan acara, Anda akan menemukannya Semantic Logging Application Block. Jangan menggunakannya, seperti sebagian besar kode yang dibuat oleh tim "pola dan praktik" MS, ironisnya, ini adalah antipattern.
Nathan Cooper
3

Perhatian Lintas potong pertama bukanlah blok bangunan utama dan tidak seharusnya diperlakukan sebagai ketergantungan dalam suatu sistem. Suatu sistem harus bekerja jika mis. Logger tidak diinisialisasi atau cache tidak berfungsi. Bagaimana Anda membuat sistem lebih sedikit digabungkan dan kohesif? Di situlah SOLID muncul dalam desain sistem OO.

Menjaga objek sebagai singleton tidak ada hubungannya dengan SOLID. Itulah siklus hidup objek Anda, berapa lama Anda ingin objek itu hidup dalam memori.

Kelas yang membutuhkan dependensi untuk diinisialisasi seharusnya tidak tahu apakah instance kelas yang disediakan adalah singleton atau sementara. Tapi tldr; jika Anda menulis Logger.Instance.Log () di setiap metode atau kelas maka itu kode bermasalah (bau kode / kopling keras) yang benar-benar berantakan. Ini adalah saat ketika orang mulai menyalahgunakan SOLID. Dan sesama pengembang seperti OP mulai mengajukan pertanyaan asli seperti ini.

dendam
sumber
2

Saya telah memecahkan masalah ini menggunakan kombinasi pewarisan dan sifat-sifat (juga disebut mixin dalam beberapa bahasa). Ciri-ciri sangat berguna untuk menyelesaikan masalah lintas bidang seperti ini. Meskipun biasanya fitur bahasa, jadi saya pikir jawaban sebenarnya adalah itu tergantung pada fitur bahasa.

RibaldEddie
sumber
Menarik. Saya tidak pernah melakukan pekerjaan yang signifikan menggunakan bahasa yang mendukung sifat, tetapi saya telah mempertimbangkan menggunakan bahasa tersebut untuk beberapa proyek di masa depan, jadi akan sangat membantu bagi saya jika Anda dapat mengembangkan ini, dan menunjukkan bagaimana sifat menyelesaikan masalah.
Jules