Seberapa ketat Anda mengikuti aturan "Tanpa Siklus Ketergantungan" (NDepend)

10

Sedikit latar belakang: Sebagai pemimpin tim saya menggunakan NDepend seminggu sekali untuk memeriksa kualitas kode kami. Khususnya cakupan uji, baris kode dan metrik kompleksitas siklomatik sangat berharga bagi saya. Tetapi ketika sampai pada levelisasi dan siklus ketergantungan saya sedikit ... prihatin. Patrick Smacchia memiliki posting blog yang bagus yang menggambarkan tujuan levelisasi.

Agar lebih jelas: Di bawah "siklus ketergantungan" saya memahami referensi melingkar antara dua ruang nama.

Saat ini saya sedang mengerjakan kerangka GUI berbasis Windows CE untuk instrumen yang tertanam - pikirkan saja platform grafis Android tetapi untuk instrumen yang sangat rendah. Kerangka kerja ini adalah perakitan tunggal dengan sekitar 50.000 baris kode (tidak termasuk tes). Kerangka kerja dibagi menjadi ruang nama berikut:

  • Navigasi Inti & Subsistem Menu
  • Subsistem Layar (Penyaji / Tampilan / ...)
  • Lapisan Kontrol / Widget

Hari ini saya menghabiskan setengah hari untuk mencoba membawa kode ke tingkat yang tepat [terima kasih kepada Resharper tidak ada masalah secara umum] tetapi dalam semua kasus beberapa siklus ketergantungan ada.

Jadi pertanyaan saya: Seberapa ketat Anda mengikuti aturan "Tidak Ada Siklus Ketergantungan"? Apakah levelisasi benar-benar penting?

Olifant
sumber
2
Jika "tidak ada siklus ketergantungan" berarti tidak ada referensi melingkar, maka - tidak ada alasan. Itu adalah kejahatan murni.
Arnis Lapsa
@ollifant: tentukan apa yang Anda maksudkan tepat ketika Anda menulis "Tidak Ada Siklus Ketergantungan". Antara lapisan atau antara kelas dalam suatu lapisan?
Doc Brown

Jawaban:

9

Baru-baru ini saya menulis 2 buku putih, yang diterbitkan di Simple-Talk tentang topik arsitektur kode .NET (buku pertama adalah tentang .NET assemblies, buku kedua tentang ruang nama dan levelisasi):

Mempartisi Basis Kode Anda Melalui. NET Assemblies dan Proyek Visual Studio

Mendefinisikan Komponen .NET dengan Namespaces

Apakah levelisasi benar-benar penting?

Ya itu!

Kutipan dari buku putih ke-2:

Jika grafik dependensi antara komponen mengandung siklus, komponen yang terlibat dalam siklus tidak dapat dikembangkan dan diuji secara independen. Karena itu, siklus komponen merupakan komponen super, dengan entropi lebih tinggi daripada jumlah entropi komponen yang terkandung.

(...)

Selama batasan komponen asiklik terus dihormati, basis kode tetap sangat dapat dipelajari dan dipelihara.

  • Dalam arsitektur bangunan tradisional, kekuatan gravitasi memberi tekanan pada artefak tingkat rendah. Ini membuat mereka lebih stabil: 'stabil' dalam arti mereka sulit untuk bergerak.
  • Dalam arsitektur perangkat lunak, mematuhi gagasan komponen asiklik memberi tekanan pada komponen tingkat rendah. Ini membuat mereka lebih stabil, dalam arti menyakitkan untuk refactor mereka. Abstraksi secara empiris lebih jarang dikenakan refactoring daripada implementasi. Oleh karena itu, ide bagus bahwa komponen tingkat rendah sebagian besar berisi abstraksi (antarmuka dan penghitungan) untuk menghindari refactoring yang menyakitkan.
Patrick Smacchia - NDepend dev
sumber
6

Saya tidak pernah mengizinkan dependensi melingkar antara kelas atau ruang nama. Di C #, Java, dan C ++ Anda selalu dapat memutus ketergantungan kelas melingkar dengan memperkenalkan antarmuka.

Pengodean terlebih dahulu menyulitkan untuk memperkenalkan dependensi melingkar.

kevin cline
sumber
4

Itu selalu merupakan pertukaran: Anda harus memahami biaya dependensi untuk memahami mengapa dependensi harus dihindari. Dengan cara yang sama, jika Anda memahami biaya ketergantungan, Anda dapat lebih baik memutuskan apakah itu layak dalam kasus spesifik Anda.

Misalnya, dalam video game konsol, kita sering mengandalkan dependensi yang memerlukan hubungan informasi yang erat, sebagian besar untuk alasan kinerja. Itu bagus sejauh kita tidak harus sefleksibel alat edisi misalnya.

Jika Anda memahami kendala dalam penyihir yang harus dijalankan oleh perangkat lunak Anda (menjadi perangkat keras, OS, atau hanya mendesain (seperti "UI yang lebih sederhana yang kami bisa")) maka haruslah mudah untuk memilih memahami mana ketergantungan tidak boleh dilakukan dan yang mana baik.

Tetapi jika Anda tidak memiliki alasan yang baik dan jelas, hindari ketergantungan yang Anda bisa. Kode dependen adalah neraka sesi-debug.

Klaim
sumber
2

Setiap kali topik ini dibahas, para peserta biasanya kehilangan situs perbedaan antara siklus build-time dan run-time. Yang pertama adalah apa yang disebut John Lakos sebagai "desain fisik," sedangkan yang terakhir pada dasarnya tidak relevan dengan diskusi (jangan terpaku pada siklus run-time, seperti yang dibuat oleh callback).

Ini mengatakan, John Lakos sangat ketat tentang menghilangkan semua siklus (build-time). Bob Martin, bagaimanapun, mengadopsi sikap bahwa hanya siklus antara binari (misalnya DLL, executable) yang signifikan dan harus dihindari; dia percaya siklus antar kelas dalam biner tidak terlalu penting.

Saya pribadi memegang pandangan Bob Martin tentang hal ini. Namun, saya masih memperhatikan siklus antara kelas karena tidak adanya siklus seperti itu membuat kode lebih mudah bagi orang lain untuk membaca dan belajar.

Akan tetapi, harus ditunjukkan bahwa kode apa pun yang Anda buat dengan Visual Studio tidak mampu memiliki dependensi melingkar di antara binari (baik kode asli atau dikelola). Jadi masalah paling buruk dengan siklus telah dipecahkan untuk Anda. :)

Brent Arias
sumber
0

Hampir sepenuhnya, karena siklus dependensi tipe-bangunan tidak nyaman di Haskell, dan tidak mungkin di Agda dan Coq, dan itu adalah bahasa yang biasanya saya gunakan.

Robin Green
sumber