it-swarm.dev

Dairesel referanslarda sorun nedir?

Bugün bir programlama tartışmasına katıldım ve burada temel olarak aksiyomatik olarak dairesel referansların (modüller, sınıflar, her ne olursa olsun) genel olarak kötü olduğunu varsaydım. Satış konuşmamdan geçtikten sonra iş arkadaşım "Dairesel referanslarda sorun nedir?" Diye sordu.

Bu konuda güçlü hislerim var, ama kısaca ve somut olarak sözlü ifade etmek benim için zor. Gelebileceğim herhangi bir açıklama, aksiyomları da düşündüğüm diğer öğelere güvenme eğilimindedir ("tek başına kullanamaz, bu yüzden test edemez", "katılan nesnelere devlet mutasyonları olarak bilinmeyen/tanımlanmamış davranış", vb. .), ama kendi beynimin yaptığı inanç sıçramaları almayan, yıllar boyunca uzun saatler boyunca onları anlamak, düzeltmek, ve çeşitli kod parçalarını genişletir.

Edit: Çift bağlantılı bir liste veya işaretçi-ebeveyn gibi homojen dairesel referanslar hakkında soru sormuyorum. Bu soru gerçekten, libA'yı çağırıp libA'yı çağıran libB gibi "daha geniş kapsam" dairesel referanslarını soruyor. İsterseniz 'lib' yerine 'module' kullanın. Şimdiye kadarki tüm cevaplar için teşekkürler!

167
dash-tom-bang

Dairesel referanslarda büyük bir çok yanlış şeyler var:

  • Dairesel sınıf referanslar yüksek oluşturur bağlantı; her ikisi de sınıflar her değiştiğinde yeniden derlenmelidir ikisinden biri.

  • Dairesel Montaj referanslar statik bağlantıyı önle, çünkü B A'ya bağlıdır, ancak B tamamlanana kadar A birleştirilemez.

  • Dairesel nesne referanslar kilitlenme yığın taşması olan naif özyinelemeli algoritmalar (serileştiriciler, ziyaretçiler ve güzel yazıcılar gibi) yapabilir. Daha gelişmiş algoritmalar döngü algılamaya sahip olacak ve sadece daha açıklayıcı bir istisna/hata mesajı ile başarısız olacaktır.

  • Dairesel nesne referanslar da bağımlılık enjeksiyonunu imkansız yapar ve sisteminizin test edilebilirliği değerini önemli ölçüde azaltır.

  • Çok büyük dairesel referans sayısına sahip nesneler genellikle Tanrı Nesneleri şeklindedir. Olmasalar bile Spagetti Code 'a yönlendirme eğilimi vardır.

  • Dairesel varlık referanslar (özellikle veritabanlarında, ancak etki alanı modellerinde), sonuçta veri bozulmasına veya en azından tutarsızlığa yol açabilecek güvenlik dışı kısıtlamalar kullanımını engeller.

  • Dairesel referanslar genel olarak basitçe kafa karıştırıcı ve bir programın nasıl çalıştığını anlamaya çalışırken bilişsel yükü büyük ölçüde artırır.

Lütfen çocukları düşünün; olabildiğince dairesel referanslardan kaçının.

228
Aaronaught

Dairesel bir referans, dairesel olmayan bir referansın iki katıdır.

Foo Bar'ı biliyorsa ve Bar Foo'yu biliyorsa, değiştirilmesi gereken iki şey var (gereksinim geldiğinde Foos ve Barlar artık birbirlerini bilmemelidir). Foo Bar'ı biliyorsa, ancak bir Bar Foo hakkında bir şey bilmiyorsa, Bar'a dokunmadan Foo'yu değiştirebilirsiniz.

Döngüsel referanslar, en azından uzun süre dayanan ortamlarda (dağıtılmış hizmetler, görüntü tabanlı geliştirme ortamları), önyükleme sorunlarına da neden olabilir; burada Foo, yüklemek için Bar'ın çalışmasına bağlıdır, ancak Bar, yük.

22
Frank Shearar

İki kod parçasını birbirine bağladığınızda, etkili bir şekilde büyük bir kod parçanız olur. Biraz kod tutmanın zorluğu, en azından boyutunun karesidir ve muhtemelen daha yüksektir.

İnsanlar genellikle tek sınıf (/ fonksiyon/dosya/vb.) Karmaşıklığına bakarlar ve en küçük ayrılabilir (kapsüllenebilen) birimin karmaşıklığını göz önünde bulundurmanız gerektiğini unuturlar. Dairesel bir bağımlılığa sahip olmak, o birimin boyutunu muhtemelen görünmez bir şekilde artırır (dosya 1'i değiştirmeye ve bunun 2-127 dosyalarında değişiklikler gerektirdiğini anlayana kadar).

17
Alex Feinman

Kendi başlarına değil, olası zayıf bir tasarımın göstergesi olarak kötü olabilirler. Foo Çubuğa ve Bar Foo'ya bağlıysa, benzersiz bir FooBar yerine neden iki olduklarını sorgulamak haklıdır.

14
mouviciel

Hmm ... bu dairesel bağımlılık ile ne demek istediğinize bağlı, çünkü aslında çok faydalı olduğunu düşündüğüm bazı dairesel bağımlılıklar var.

Bir XML DOM düşünün - her düğümün ebeveynlerine referans olması ve her ebeveynin çocuklarının bir listesine sahip olması mantıklıdır. Yapı mantıksal olarak bir ağaçtır, ancak çöp toplama algoritması veya benzeri bir bakış açısından yapı daireseldir.

10
Billy ONeal

Tavuk veya Yumurta sorunu gibidir.

Dairesel referansın kaçınılmaz olduğu ve yararlı olduğu birçok durum vardır, ancak aşağıdaki durumda işe yaramaz:

Proje A, proje B'ye ve B'ye bağlıdır. A, B'de kullanılmak üzere derlenmelidir; bu, B'nin A'dan önce derlenmesini gerektirir;.

9
Victor Hurdugaci

Buradaki yorumların çoğuna katılırken, "ebeveyn"/"çocuk" dairesel referansı için özel bir dava açmak istiyorum.

Bir sınıfın genellikle üst öğesi veya sahip olma sınıfı, belki de varsayılan davranış, verilerin geldiği dosyanın adı, sütunu seçen sql ifadesi veya bir günlük dosyasının konumu vb. Hakkında bir şeyler bilmesi gerekir.

Bunu, daha önce "üst" olanın şimdi bir kardeş olması için bir kapsayıcı sınıfa sahip olarak dairesel bir başvuru olmadan yapabilirsiniz, ancak bunu yapmak için mevcut kodu yeniden hesaba katmak her zaman mümkün değildir.

Diğer alternatif, bir çocuğun yapıcısında ihtiyaç duyabileceği tüm verileri aktarmaktır ve bu da sadece korkunç bir sonuçtur.

6
James Anderson

Veritabanı terimleriyle, uygun PK/FK ilişkilerine sahip dairesel referanslar veri eklemeyi veya silmeyi imkansız hale getirir. Kayıt tablo b'den gitmedikçe a tablosundan silemiyorsanız ve kayıt tablo A'dan gitmedikçe tablo b'den silemezseniz silemezsiniz. Ekler ile aynı. Bu nedenle, birçok veritabanı, döngüsel bir başvuru varsa basamaklı güncelleştirmeler veya silmeler ayarlamanıza izin vermez, çünkü bir noktada mümkün olmaz. Evet, resmi olarak beyan edilen PK/Fk ile bu tür ilişkiler kurabilirsiniz, ancak daha sonra (deneyimimde zamanın% 100'ü) veri bütünlüğü sorunları yaşayacaksınız. Bu sadece kötü tasarım.

5
HLGEM

Bu soruyu modelleme açısından ele alacağım.

Aslında orada olmayan hiçbir ilişki eklemediğiniz sürece güvendesiniz. Bunları eklerseniz, verilerde daha az bütünlük elde edersiniz (fazlalık olmasına neden olur) ve daha sıkı bir şekilde bağlanmış kod elde edersiniz.

Dairesel referanslarla ilgili olan şey, bir - kendinden referans dışında gerçekten ihtiyaç duyulacak bir durum görmedim. Ağaçları veya grafikleri modelliyorsanız buna ihtiyacınız vardır ve her şey yolundadır, çünkü öz referans kod kalitesi açısından zararsızdır (bağımlılık eklenmez).

Kendine ait olmayan bir referansa ihtiyaç duymaya başladığınızda, hemen bir grafik olarak modelleyip değiştiremeyeceğinizi sormalısınız (birden fazla varlığı bir düğüme daraltın). Belki de dairesel bir referans yaptığınız ancak grafik olarak modellemenin uygun olmadığı bir durum var ama bundan çok şüpheliyim.

İnsanların döngüsel bir referansa ihtiyaç duyduklarını düşündükleri bir tehlike var, ama aslında gerekmiyorlar. En sık karşılaşılan durum "Çok sayıda durumdan biri" dir. Örneğin, birincil adres olarak işaretlenmesi gereken birden fazla adrese sahip bir müşteriniz var. Bu durumu iki ayrı ilişki olarak modellemek çok caziptir has_address ve is_primary_address_of ama doğru değil. Nedeni birincil adres olmak kullanıcılar ve adresler arasında ayrı bir ilişki değil, bunun yerine bir özellik ilişkinin adresi var. Neden? Etki alanı, kullanıcının tüm adresleriyle sınırlı değil, kullanıcının adresleriyle sınırlıdır. Bağlantılardan birini seçip en güçlü (birincil) olarak işaretlersiniz.

(Şimdi veritabanları hakkında konuşacaklar) Birçok insan iki ilişki çözümünü tercih ediyor çünkü "birincil" i benzersiz bir işaretçi olarak anlıyorlar ve yabancı bir anahtar bir çeşit işaretçi. Yani yabancı anahtar kullanılacak şey olmalı, değil mi? Yanlış. Yabancı anahtarlar ilişkileri temsil eder, ancak "birincil" bir ilişki değildir. Bir elemanın her şeyden önce olduğu ve geri kalanının sipariş edilmediği dejenere edilmiş bir dejenere durumdur. Toplam bir siparişi modellemeniz gerekiyorsa, elbette bir ilişkinin niteliği olarak düşünürdünüz, çünkü temel olarak başka bir seçenek yoktur. Ama onu dejenere ettiğiniz anda, bir ilişki olarak ilişki olmayan bir şeyi modellemek için bir seçenek ve oldukça korkunç bir seçenek var. İşte geliyor - kesinlikle azımsanacak bir şey olmayan ilişki fazlalığı. Benzersizlik şartı başka bir şekilde, örneğin benzersiz kısmi indekslerle dayatılmalıdır.

Bu yüzden, modellediğim şeyden geldiği kesin olarak belli değilse, dairesel bir referansın oluşmasına izin vermem.

(not: Bu veritabanı tasarımına biraz önyargılıdır, ancak diğer alanlara da oldukça uygulanabilir olduğuna eminim)

4
clime

Bu soruya başka bir soru ile cevap verirdim:

Dairesel bir referans model tutmanın, oluşturmaya çalıştığınız şeyin en iyi modeli olduğu durumlarda bana hangi durumu verebilirsiniz?

Deneyimlerime göre, en iyi model, asla bunu kastettiğini düşündüğüm şekilde dairesel referansları içermeyecek. Bununla birlikte, sürekli referanslar kullandığınız birçok model var, sadece son derece basit. Ebeveyn -> Çocuk ilişkileri, herhangi bir grafik modeli, vb, ancak bunlar iyi bilinen modellerdir ve bence tamamen başka bir şeye atıfta bulunuyorsunuz.

2
Joseph

Bazı çöp toplayıcıları, her nesneye başka bir nesne tarafından başvurulduğundan, bunları temizlemekte sorun yaşarlar.

EDIT: Aşağıdaki yorumlarda belirtildiği gibi, bu sadece pratikte karşılaşacağınız bir değil, bir çöp toplayıcı bir son derece naif girişimi için geçerlidir.

1
shmuelp

Dairesel bir referans yapısı sadece tasarım açısından değil, aynı zamanda hata yakalama açısından da sorunludur.

Kod hatası olasılığını düşünün. Her iki sınıfa da uygun bir hata yakalayamadınız, çünkü henüz yöntemlerinizi henüz geliştirmediniz ya da tembelsiniz. Her iki durumda da, neyin dolduğunu bildiren bir hata mesajınız yoktur ve hata ayıklamanız gerekir. İyi bir program tasarımcısı olarak, hangi yöntemlerin hangi süreçlerle ilişkili olduğunu bilirsiniz, böylece onu hataya neden olan süreçle ilgili yöntemlerle daraltabilirsiniz.

Dairesel referanslarla sorunlarınız ikiye katlandı. İşlemleriniz sıkı bir şekilde bağlı olduğundan, hangi sınıfın hataya neden olabileceğini veya hatanın nereden geldiğini bilmenin hiçbir yolu yoktur, çünkü bir sınıf diğerine bağımlıdır, diğeri bağımlıdır. Şimdi hangisinin hatadan gerçekten sorumlu olduğunu bulmak için her iki sınıfı birlikte test etmek için zaman harcamanız gerekiyor.

Elbette, doğru hata yakalama bunu çözer, ancak yalnızca bir hatanın ne zaman gerçekleşeceğini biliyorsanız. Genel hata mesajları kullanıyorsanız, hala çok daha iyi değilsiniz.

1
Zibbobz

Veri yapılarındaki dairesel referanslar bazen bir veri modelini ifade etmenin doğal yoludur. Kodlama açısından, kesinlikle ideal değildir ve bağımlılık enjeksiyonuyla (bir dereceye kadar) çözülebilir ve sorunu koddan verilere itebilir.

1
Vatine