Apakah bermasalah untuk memiliki ketergantungan antara objek dari lapisan yang sama dalam arsitektur perangkat lunak berlapis?

12

Mempertimbangkan perangkat lunak menengah-besar dengan arsitektur n-layer dan injeksi ketergantungan, saya merasa nyaman untuk mengatakan bahwa objek yang dimiliki lapisan dapat bergantung pada objek dari lapisan bawah tetapi tidak pernah pada objek dari lapisan yang lebih tinggi.

Tapi saya tidak yakin apa yang harus dipikirkan tentang objek yang bergantung pada objek lain dari lapisan yang sama.

Sebagai contoh, mari kita asumsikan aplikasi dengan tiga lapisan dan beberapa objek seperti yang ada di gambar. Jelas dependensi top-down (panah hijau) ok, bottom-up (panah merah) tidak ok, tetapi bagaimana dengan dependensi di dalam lapisan yang sama (panah kuning)?

masukkan deskripsi gambar di sini

Tidak termasuk ketergantungan sirkular, saya ingin tahu tentang masalah lain yang dapat timbul dan seberapa banyak arsitektur berlapis dilanggar dalam kasus ini.

bracco23
sumber
Jika Anda tidak memiliki siklus, dalam lapisan di mana Anda memiliki tautan horysontal ada pemisahan menjadi sub-lapisan yang hanya memiliki dependensi di antara lapisan
max630

Jawaban:

10

Ya, objek dalam satu lapisan dapat memiliki dependensi langsung satu sama lain, kadang-kadang bahkan yang siklik - itulah yang sebenarnya membuat perbedaan inti dengan dependensi yang diperbolehkan antara objek di lapisan yang berbeda, di mana tidak ada dependensi langsung yang diizinkan, atau hanya dependensi yang ketat arah.

Namun, itu tidak berarti mereka harus memiliki ketergantungan seperti itu secara sewenang-wenang. Sebenarnya tergantung pada apa yang diwakili lapisan Anda, seberapa besar sistem itu dan dan apa tanggung jawab bagian-bagian itu. Perhatikan bahwa "arsitektur berlapis" adalah istilah yang tidak jelas, ada variasi besar dari apa yang sebenarnya berarti dalam berbagai jenis sistem.

Misalnya, katakanlah Anda memiliki "sistem berlapis horizontal", dengan lapisan basis data, lapisan bisnis, dan lapisan antarmuka pengguna (UI). Katakanlah layer UI mengandung setidaknya beberapa lusinan kelas dialog yang berbeda.

Seseorang dapat memilih desain di mana tidak ada kelas dialog yang bergantung pada kelas dialog lain secara langsung. Seseorang dapat memilih desain di mana "dialog utama" dan "sub dialog" ada dan hanya ada dependensi langsung dari dialog "utama" ke "sub". Atau seseorang dapat memilih desain di mana setiap kelas UI yang ada dapat menggunakan / menggunakan kembali kelas UI lain dari lapisan yang sama.

Ini semua adalah pilihan desain yang mungkin, mungkin lebih atau kurang masuk akal tergantung pada jenis sistem yang Anda bangun, tetapi tidak satu pun dari mereka membuat "pelapisan" sistem Anda tidak valid.

Doc Brown
sumber
Melanjutkan contoh UI, apa pro dan kontra dari memiliki dependensi batin? Saya bisa melihat bahwa itu membuat lebih mudah digunakan kembali dan memperkenalkan dependensi siklik, yang mungkin menjadi masalah tergantung pada metode DI yang digunakan. Ada yang lain?
bracco23
@ bracco23: pro dan kontra memiliki dependensi "dalam" adalah sama dengan pro kontra memiliki dependensi sewenang-wenang. "Kontra" adalah mereka membuat komponen lebih sulit untuk digunakan kembali dan lebih sulit untuk diuji, terutama dalam isolasi dari komponen lain. Kelebihannya, dependensi eksplisit membuat hal-hal yang membutuhkan kohesi lebih mudah digunakan, dipahami, dikelola, dan diuji.
Doc Brown
14

Saya merasa nyaman untuk mengatakan bahwa objek yang dimiliki lapisan dapat bergantung pada objek dari lapisan bawah

Sejujurnya, saya tidak berpikir Anda harus nyaman dengan itu. Ketika berurusan dengan apa pun kecuali sistem yang sepele, saya bertujuan untuk memastikan semua lapisan hanya bergantung pada abstraksi dari lapisan lain; keduanya lebih rendah dan lebih tinggi.

Jadi misalnya, Obj 1tidak harus bergantung Obj 3. Itu harus memiliki ketergantungan pada misalnya IObj 3dan harus diberitahu implementasi yang abstraksi itu untuk bekerja dengan saat runtime. Hal yang melakukan penceritaan seharusnya tidak terkait dengan level mana pun karena tugasnya adalah memetakan dependensi tersebut. Itu mungkin wadah IoC, kode khusus yang disebut misalnya oleh mainyang menggunakan DI murni. Atau dengan dorongan itu bahkan bisa menjadi pencari layanan. Apapun, dependensi tidak ada di antara lapisan sampai hal itu menyediakan pemetaan.

Tapi saya tidak yakin apa yang harus dipikirkan tentang objek yang bergantung pada objek lain dari lapisan yang sama.

Saya berpendapat bahwa ini adalah satu-satunya waktu Anda harus memiliki dependensi langsung. Ini bagian dari cara kerja lapisan dalam itu dan dapat diubah tanpa mempengaruhi lapisan lainnya. Jadi itu bukan kopling berbahaya.

David Arno
sumber
Terima kasih atas jawabannya. Ya, layer seharusnya tidak mengekspos objek tetapi antarmuka, saya tahu itu tetapi saya meninggalkannya demi kesederhanaan.
bracco23
4

Mari kita lihat ini secara praktis

masukkan deskripsi gambar di sini

Obj 3sekarang tahu Obj 4ada. Terus? Kenapa kita peduli?

Kata DIP

"Modul tingkat tinggi seharusnya tidak bergantung pada modul tingkat rendah. Keduanya harus bergantung pada abstraksi."

OK tapi, bukankah semua objek abstraksi?

DIP juga mengatakan

"Abstraksi tidak harus bergantung pada detail. Detail harus bergantung pada abstraksi."

OK tapi, jika objek saya dienkapsulasi dengan benar bukankah itu menyembunyikan detail?

Beberapa orang suka membabi buta bersikeras bahwa setiap objek membutuhkan antarmuka kata kunci. Saya bukan salah satu dari mereka. Saya suka secara membabi buta bersikeras bahwa jika Anda tidak akan menggunakannya sekarang Anda perlu rencana untuk berurusan dengan membutuhkan sesuatu seperti mereka nanti.

Jika kode Anda sepenuhnya dapat di-refactor pada setiap rilis, Anda bisa mengekstrak antarmuka nanti jika Anda membutuhkannya. Jika Anda telah menerbitkan kode yang tidak ingin Anda kompilasi ulang dan mendapati diri Anda berharap Anda berbicara melalui antarmuka, Anda memerlukan rencana.

Obj 3tahu Obj 4ada. Tapi apakah Obj 3tahu kalau Obj 4beton?

Ini di sini adalah mengapa sangat bagus untuk TIDAK menyebar ke newmana-mana. Jika Obj 3tidak tahu apakah Obj 4konkret, kemungkinan karena itu tidak membuatnya, maka jika Anda menyelinap masuk dan berubah Obj 4menjadi kelas abstrak Obj 3tidak akan peduli.

Jika Anda bisa melakukan itu, maka Obj 4abstrak sepenuhnya selama ini. Satu-satunya hal yang membuat antarmuka di antara mereka dari awal membuat Anda adalah jaminan bahwa seseorang tidak akan sengaja menambahkan kode yang memberikan yang Obj 4konkret saat ini. Konstruktor yang dilindungi dapat mengurangi risiko itu tetapi itu mengarah ke pertanyaan lain:

Apakah Obj 3 dan Obj 4 dalam paket yang sama?

Objek sering dikelompokkan dalam beberapa cara (paket, namespace, dll). Ketika dikelompokkan dengan bijak, ubahlah dampak yang lebih mungkin terjadi dalam suatu kelompok daripada lintas kelompok.

Saya suka mengelompokkan berdasarkan fitur. Jika Obj 3dan Obj 4berada di grup dan lapisan yang sama, sangat tidak mungkin Anda telah menerbitkan satu dan tidak ingin membuatnya kembali sementara hanya perlu mengubah yang lain. Itu berarti benda-benda ini cenderung mendapat manfaat dari memiliki abstraksi yang diletakkan di antara mereka sebelum memiliki kebutuhan yang jelas.

Jika Anda melewati batas grup, meskipun itu ide yang bagus untuk membiarkan objek di kedua sisi berbeda secara independen.

Seharusnya sesederhana itu, tetapi sayangnya Java dan C # telah membuat pilihan yang tidak menguntungkan yang menyulitkan ini.

Dalam C # itu tradisi untuk memberi nama setiap antarmuka kata kunci dengan Iawalan. Itu memaksa klien untuk TAHU mereka berbicara dengan antarmuka kata kunci. Itu mengacaukan rencana refactoring.

Di Jawa tradisi menggunakan pola penamaan yang lebih baik: FooImple implements FooNamun, ini hanya membantu pada tingkat kode sumber karena Java mengkompilasi antarmuka kata kunci ke biner yang berbeda. Itu berarti ketika Anda refactor Foodari klien konkret ke abstrak yang tidak memerlukan satu karakter kode yang diubah masih harus dikompilasi ulang.

BUGS dalam bahasa-bahasa khusus inilah yang membuat orang tidak bisa menunda abstraksi formal sampai mereka benar-benar membutuhkannya. Anda tidak mengatakan bahasa apa yang Anda gunakan tetapi mengerti ada beberapa bahasa yang tidak memiliki masalah ini.

Anda tidak mengatakan bahasa apa yang Anda gunakan jadi saya hanya akan mendorong Anda untuk menganalisis bahasa dan situasi Anda dengan cermat sebelum Anda memutuskan itu akan menjadi antarmuka kata kunci di mana-mana.

Prinsip YAGNI memainkan peran kunci di sini. Tetapi begitu juga "Tolong buat sulit untuk menembak diri sendiri di kaki".

candied_orange
sumber
0

Selain jawaban di atas, saya pikir itu mungkin membantu Anda untuk melihatnya dari sudut pandang yang berbeda.

Misalnya, dari sudut pandang Ketergantungan . DR adalah aturan yang disarankan oleh Robert C. Martin untuk Arsitektur Bersihnya yang terkenal .

Ia mengatakan

Ketergantungan kode sumber harus mengarah hanya ke dalam, menuju kebijakan tingkat yang lebih tinggi.

Dengan kebijakan tingkat yang lebih tinggi , yang ia maksud adalah abstraksi tingkat yang lebih tinggi . Komponen yang bocor pada detail implementasi, seperti misalnya antarmuka atau kelas abstrak berbeda dengan kelas konkret atau struktur data.

Masalahnya, aturannya tidak terbatas pada ketergantungan antar-lapisan. Itu hanya menunjukkan ketergantungan antara potongan-potongan kode, terlepas dari lokasi atau lapisan milik mereka.

Jadi tidak, tidak ada yang salah secara inheren dengan memiliki ketergantungan antara elemen-elemen dari lapisan yang sama. Namun, ketergantungan masih dapat diterapkan untuk menyampaikan dengan prinsip ketergantungan yang stabil .

Sudut pandang lain adalah SRP.

Decoupling adalah cara kami untuk memutus dependensi berbahaya dan menyampaikan dengan beberapa praktik terbaik seperti dependensi inversi (IoC). Namun, elemen-elemen yang memiliki alasan untuk berubah mereka tidak memberikan alasan untuk decoupling karena elemen-elemen dengan alasan yang sama untuk berubah akan berubah pada saat yang sama (sangat mungkin) dan mereka akan digunakan pada waktu yang sama juga. Jika itu adalah kasus antara Obj3dan Obj4kemudian, sekali lagi, tidak ada yang salah secara inheren.

Laiv
sumber