Küresel Devlet neden bu kadar kötü?


328

Buna başlamadan önce, Soyutlama ve Bağımlılık Enjeksiyonu kavramlarının farkında olduğumu söylememe izin verin. Burada gözlerimin açılmasına ihtiyacım yok.

Pek çoğumuz, (pek çok kez) “Global değişkenleri kullanma” ya da “Singletonlar kötüdür, çünkü küreseldirler” anlamış olmadan defalarca. Ama gerçekten neyi olduğunu uğursuz küresel durumu hakkında çok kötü?

Uygulamam için, örneğin sistem klasörü yolları veya uygulama genelinde veritabanı kimlik bilgileri için genel bir yapılandırmaya ihtiyacım olduğunu varsayalım.

Bu durumda, bu ayarları genel olarak tüm uygulama için geçerli olacak bir tür küresel alanda sağlamaktan başka iyi bir çözüm göremiyorum.

Bunun için kötü olduğunu biliyorum kötüye onu, ama küresel uzay gerçekten OLDUĞUNU kötülük? Ve eğer öyleyse, hangi iyi alternatifler var?


5
Bu ayarlara erişimi ele alan bir config sınıfını kullanabilirsiniz. Yapılandırma ayarlarının config dosyalarından ve / veya veritabanlarından okunduğu ve yalnızca diğer nesnelerin bu yapılandırma şeyinden getirdiği tek bir yere sahip olmanın iyi bir uygulama olduğunu düşünüyorum. tasarımınızı daha temiz ve öngörülebilir yapar.
Hajo

25
Global kullanmanın farkı ne? "Bir ve sadece bir yer", Singleton'a çok şüpheli geliyor.
Madara Uchiha,

130
Tek gerçek kötülük dogmalardır.
Pieter B

34
Programlayıcı arkadaşlarınızla global durumu kullanmak, aynı diş fırçasını arkadaşlarınızla kullanmak gibi bir şeydir - siz birisinin serseriye ne zaman sokacağına karar vereceğinizi asla bilemezsiniz.
ziGi

5
Şeytan şeytandır. Küresel devlet ne kötü ne de iyi. Nasıl kullandığınıza bağlı olarak çok faydalı veya zararlı olabilir. Başkalarını dinlemeyin ve sadece programlamanın nasıl yapıldığını öğrenin.
annoying_squid

Yanıtlar:


282

Çok kısaca program durumunu tahmin edilemez kılar.

Ayrıntılı olarak, her ikisinde de aynı global değişkeni kullanan birkaç nesne olduğunu hayal edin. Herhangi bir modülde herhangi bir yerde rastgele bir kaynak kullanmadığınızı varsayarsak, yöntemi çalıştırmadan önce sistemin durumu biliniyorsa belirli bir yöntemin çıktısı tahmin edilebilir (ve bu nedenle test edilebilir).

Bununla birlikte, nesnelerden birindeki yöntem, paylaşılan genel durumun değerini değiştiren bir yan etki tetiklerse, o zaman diğer nesnede bir yöntem yürüttüğünüzde başlangıç ​​durumunun ne olduğunu artık bilemezsiniz. Artık, yöntemi uygularken elde edeceğiniz çıktıyı artık tahmin edemezsiniz ve bu nedenle test edemezsiniz.

Akademik düzeyde, bu o kadar ciddi gelmeyebilir, ancak test kodunu birime koyabilmek doğru olduğunu ispatlama sürecinde (veya en azından amaca uygunluk) önemli bir adımdır.

Gerçek dünyada bunun çok ciddi sonuçları olabilir. Global bir veri yapısını dolduran bir sınıfınız olduğunu ve bu veri yapısındaki verileri tüketen, durumunu değiştiren veya süreç içinde yok eden farklı bir sınıfınız olduğunu varsayalım. İşlemci sınıfı, popülatör sınıfı yapılmadan önce bir yöntem çalıştırırsa, sonuç, işlemci sınıfının muhtemelen işlem yapmak için eksik veriye sahip olması ve popülatör sınıfının üzerinde çalıştığı veri yapısı bozulabilir veya tahrip olabilir. Bu koşullarda program davranışı tamamen tahmin edilemez hale gelir ve muhtemelen epik bir kaybedilmeye yol açar.

Ayrıca, küresel devlet, kodunuzun okunabilirliğine zarar verir. Kodunuz açıkça koda dahil edilmemiş bir dış bağımlılığa sahipse, kodunuzu sağlama işini kim aldıysa, nereden geldiğini bulmak için aramaya gitmek zorunda kalacaktır.

Hangi alternatiflerin mevcut olduğuna gelince, hiç bir küresel devletin olması imkansızdır, ancak pratikte, küresel devleti, diğerlerini saran ve hiçbir zaman kapsam belirleme kurallarına dayanarak referans alınmaması gereken tek bir nesneyle sınırlamak mümkündür. kullandığınız dilin Belirli bir nesnenin belirli bir duruma ihtiyacı varsa, açıkça kurucusuna bir argüman olarak geçirerek veya bir ayarlayıcı yöntemle geçirmesini ister. Bu Bağımlılık Enjeksiyonu olarak bilinir.

Kullandığınız dilin kapsam kuralları nedeniyle halihazırda erişebileceğiniz bir devlet parçasına geçmek aptalca görünebilir, ancak avantajlar muazzamdır. Şimdi eğer biri koddaki izolasyona bakarsa, hangi duruma ihtiyaç duyduğu ve nereden geldiği açıktır. Ayrıca, kod modülünüzün esnekliği ve bu nedenle farklı bağlamlarda yeniden kullanılması için fırsatlar konusunda da büyük yararları var. Durum iletilirse ve durum değişiklikleri kod bloğunda yerel ise, o zaman istediğiniz herhangi bir durumu (doğru veri türü ise) geçirebilir ve kodunuzun işlemesini sağlayabilirsiniz. Bu tarzda yazılmış kod, kolayca değiştirilebilen, gevşek bir şekilde ilişkili bileşenlerden oluşan bir koleksiyon görünümüne sahip olma eğilimindedir. Bir modülün kodu, durumun nereden geldiği ve nasıl işleneceği ile ilgilenmemelidir.

Etrafta devleti dolaşmanın küresel devlete güvenmekten çok daha üstün olmasının birçok nedeni var. Bu cevap, hiçbir şekilde kapsamlı değildir. Muhtemelen küresel devletin neden kötü olduğu konusunda bütün bir kitap yazabilirsiniz.


61
Temel olarak, kimse devleti değiştirebildiği için ona güvenemezsiniz.
Oded

21
@Truth Alternatif? Bağımlılık Enjeksiyonu .
rdlowrey

12
Ana argümanınız, gerçekten bir konfigürasyonu temsil eden bir nesne gibi salt okunur olan bir şeye uygulanmaz.
frankc

53
Bunların hiçbiri OP'nin açıkça sorduğu salt küresel değişkenlerin neden kötü olduğunu açıklamıyor . Aksi takdirde iyi bir cevap, OP'nin açıkça farklı bir noktaya değindiğinde “kabul edildi” olarak işaretlemesine şaşırdım.
Konrad Rudolph

20
being able to unit test code is a major step in the process of proving its correctness (or at least fitness for purpose). Hayır değil. “Program testinin hataların ikna edici bir şekilde gösterilebileceğini, ancak bunların bulunmadığını asla gösteremediğine işaret ettiğinden bu yana yirmi yıl geçti. Krizoskobik saflaştırmalarını daraltmaya devam eden, tıpkı eskiden simyacı gibi, test stratejilerini geliştirmek. ” - Djikstra, 1988. (Bu onu 4.5 yıl sonra yapar ...)
Mason Wheeler

135

Değişken küresel devlet birçok sebepten dolayı kötüdür:

  • Değişken küresel durumdan kaynaklanan hatalar - çoğu zor böcek, değişkenlikten kaynaklanır. Kesin sebebi bulmak çoğu zaman zordur, çünkü programın herhangi bir yerinden mutasyonun neden olabileceği hatalar daha da kandırıcıdır.
  • Zayıf test edilebilirlik - Değişken bir küresel durumunuz varsa, yazdığınız tüm testler için yapılandırmanız gerekir. Bu, test etmeyi zorlaştırır (ve insanların insanlar olması bu yüzden daha az olasıdır!). Örneğin, uygulama genelinde veri tabanı kimlik bilgileri söz konusu olduğunda, bir testin her şeyden farklı olan belirli bir test veritabanına erişmesi gerekiyorsa?
  • Esneklik - ya kodun bir kısmı global durumda bir değer isterse, başka bir parça başka bir değer isterse (örneğin bir işlem sırasında geçici bir değer)? Birden elinizde kötü bir şekilde yeniden yönlenişiniz oldu
  • İşlev kirliliği - "saf" işlevler (örneğin, sonucun yalnızca girdi parametrelerine bağlı olduğu ve yan etkisi olmayanlar) daha büyük programlar oluşturmak için nedenini oluşturmak ve oluşturmak için çok kolaydır. Değişken küresel durumu okuyan ya da manipüle eden işlevler doğası gereği saf değildir.
  • Kod kavrama - birçok değişken global değişkene bağlı olan kod davranışının anlaşılması daha zordur - kodun davranışını düşünmeden önce global değişkenle olası etkileşimler aralığını anlamanız gerekir. Bazı durumlarda, bu sorun anlaşılmaz hale gelebilir.
  • Eşzamanlılık sorunları - değişken küresel durum genellikle eşzamanlı bir durumda kullanıldığında bir tür kilitleme gerektirir. Bu doğru olması çok zordur (bir hata nedenidir) ve kodunuza (bakımı zor / pahalı) çok daha fazla karmaşıklık ekler.
  • Performans - sürekli aynı küresel duruma dayanan çoklu iş parçacığı önbellek çekişmesine neden olur ve sisteminizi genel olarak yavaşlatır.

Değişken küresel duruma alternatifler:

  • İşlev parametreleri - genellikle göz ardı edilir, ancak işlevlerinizi daha iyi parametreleştirmek çoğu zaman küresel durumu önlemenin en iyi yoludur. Sizi önemli kavramsal soruyu çözmeye zorlar: bu işlev işini yapmak için hangi bilgileri gerektirir? Bazen, ilgili tüm bilgileri saran bir fonksiyonlar zincirinden aşağıya aktarılabilen "Bağlam" adı verilen bir veri yapısına sahip olmak mantıklıdır.
  • Bağımlılık enjeksiyonu - fonksiyon parametrelerinde olduğu gibi, biraz daha erken yapılır (fonksiyon çağrısı yerine nesne yapımında). Bağımlılıklarınız değişebilir nesneler ise dikkatli olun, bu hızlı bir şekilde değişebilir küresel durumla aynı sorunlara neden olabilir…
  • Sürdürülebilir küresel devlet çoğunlukla zararsızdır - etkili bir sabittir. Ancak bunun gerçekten bir sabit olduğundan ve daha sonraki bir noktada değişebilir bir küresel duruma dönmeye cazip olmayacağınızdan emin olun!
  • Değişken tekiller - değişmez küresel devletle hemen hemen aynıdır, ancak ihtiyaç duyulana kadar örneklemeyi erteleyebilirsiniz. Pahalı bir kereye mahsus ön hesaplama gerektiren büyük sabit veri yapıları için kullanışlıdır. Değişken singletonlar elbette değişken küresel duruma eşdeğerdir ve bu nedenle kötüdür :-)
  • Dinamik ciltleme - yalnızca Common Lisp / Clojure gibi bazı dillerde kullanılabilir, ancak bu, diğer dişlileri etkilemeyen kontrollü bir kapsamda (tipik olarak yerel olarak yerel olarak) bir değeri bağlamanıza izin verir. Bir dereceye kadar bu, küresel değişkenle aynı etkiyi elde etmenin "güvenli" bir yoludur, çünkü yalnızca geçerli yürütme iş parçasının etkileneceğini biliyorsunuzdur. Bu, örneğin her biri bağımsız işlem yapan birden fazla iş parçacığı olması durumunda özellikle yararlıdır.

11
Bir bağlam nesnesini, işlev parametresi veya bağımlılık enjeksiyonuyla geçirmenin, bağlam değişken olduğunda, değişken global durumun kullanılmasıyla aynı sorunlara neden olacağını düşünüyorum.
Alfredo Osorio

1
Tüm iyi şeyler ve amen! Ancak soru değişmez küresel devletle ilgili
MarkJ

@Alfredo - çok doğru. O kadar kötü olmasa da, en azından kapsam biraz kontrol altına alınabiliyor. Ancak genel olarak, bağlamı ve bağımlılıkları değişmez hale getirerek sorunu çözmek daha kolaydır.
mikera

2
Değişken / değişmez için +1. Değiştirilemez globals iyi. Tembel yüklü olan fakat asla değişmeyen olanlar bile. Tabii ki, global değişkenleri değil, global bir arayüzü veya API'yi ifşa edin.
Jess

1
@giorgio Soru, söz konusu değişkenlerin başlangıçta değerlerini aldıklarını ve program yürütme sırasında hiçbir zaman değişmediklerini (sistem klasörleri, veritabanı kimlik bilgileri) açıkça ortaya koyuyor. Bir başka deyişle, bir değer verildiğinde değişmez. Şahsen ben de "state" kelimesini kullanıyorum çünkü bir uygulamadan diğerine veya farklı bir makinede farklı olabilir. Daha iyi kelimeler olabilir.
Mark

62
  1. Tüm uygulamanız onu kullanabildiğinden, onları tekrar etkilemek her zaman inanılmaz zordur. Global'inle ilgili bir şeyi değiştirirsen, tüm kodunun değişmesi gerekir. Bu, bir bakım baş ağrısıdır - sadece greptür isminin hangi işlevleri kullandığını bulmasını sağlamaktan çok daha fazlası .
  2. Kötüdürler, çünkü giderek artan birçok uygulama için hayati önem taşıyan, çok iş parçacılığını kıran gizli bağımlılıklar ortaya çıkmaktadır.
  3. Global değişkenin durumu her zaman tamamen güvenilmezdir, çünkü kodunuzun tümü ona bir şey yapabilir.
  4. Test etmek gerçekten zor.
  5. API'yi çağırmayı zorlaştırıyorlar. "API'yi aramadan önce SET_MAGIC_VARIABLE () işlevini çağırmayı hatırlamalısınız" sadece birinin aramayı unutması için yalvarıyor . API hataya eğilimlidir ve bulması zor hatalara neden olur. Bunu normal bir parametre olarak kullanarak, arayan kişiyi uygun bir değer sağlamaya zorlarsınız.

Sadece ihtiyaç duyduğu fonksiyonlara referans verin. O kadar zor değil.


3
Peki, kilitlemeyi içine alan genel bir config sınıfına sahip olabilirsiniz ve IS mümkün olan her durumda durumu değiştirmek için tasarlanmıştır. Bu yaklaşımı kodun 1000x yerinden konfigürasyon okuyucularının başlatılması üzerinden seçerdim. Ama evet, tahmin edilemezlik, onlar hakkında kesinlikle en kötü şey.
Kodlayıcı

6
@Coder: küresel aklı başında alternatif, fakat "kod 1000x yerlerden yapılandırma okuyucu" olmadığına dikkat bir (-> bağımlılık enjeksiyon) yöntemleri bir parametre olarak kabul edebileceği bir yapılandırma nesnesi yaratır yapılandırma okuyucu.
12'de

2
Nitpicking: Neden bir tür için genel bir kürekle aşırmak daha kolaydır? Ve soru salt okunur
globals'lar

2
@MarkJ: İnşallah hiç kimsenin adı gölgelendirmediğini umarım.
DeadMG

2
@DeadMG, Re ".. her zaman tamamen güvenilmez ..", aynı bağımlılık enjeksiyonunda da geçerli. Sırf bunu bir parametre yapmış olmanız, objenin sabit bir duruma sahip olmasının garanti edildiği anlamına gelmez. Fonksiyonun alt kısmında, enjekte edilen değişkenin durumunu değiştiren başka bir fonksiyona çağrı yapabilirsiniz.
Pacerier

34

"Devlet" derseniz, bu genellikle "değişken durum" anlamına gelir. Ve küresel değişken durum tamamen kötüdür, çünkü programın herhangi bir parçasının başka bir kısmı etkileyebileceği (küresel devleti değiştirerek) anlamına gelir.

Bilinmeyen bir programda hata ayıklama olduğunu düşünün: A fonksiyonunun belirli giriş parametreleri için belirli bir şekilde davrandığını, ancak bazen aynı parametreler için farklı şekilde çalıştığını düşünün. Bunun global değişkeni x kullandığını görürsünüz .

Değiştirmek yerlerde arayın x ve değişiklik beş yer vardır bulmak. Şimdi hangi durumlarda A işlevinin ne yaptığını bulmada iyi şanslar ...


Yani değişmez küresel devlet o kadar kötü değil mi?
SinirliFormsDesigner ile

50
Değişmez küresel devletin “sabit” olarak bilinen iyi bilinen bir uygulama olduğunu söyleyebilirim.
Telastyn,

6
Düşünülemez küresel devlet kötü değil, sadece kötü. Tanıttığı kuplaj nedeniyle hala problemlidir (değişiklikleri yapar, yeniden kullanır ve ünite testini zorlaştırır), ancak çok daha az problem yaratır, bu yüzden basit durumlarda genellikle kabul edilebilir.
12'de

2
IFF biri global değişkenler kullanır, o zaman sadece bir kod parçasını değiştirmelidir. Gerisi okumak için ücretsiz. Bunu değiştiren diğerlerinin sorunları, kapsülleme ve erişim işlevleriyle bitmiyor. Bu yapılar ne için değil.
phkahler

1
@Pacerier: Evet, genel veya yerel bir değişken olarak kullanılsa da, yaygın olarak kullanılan bir arayüzün değiştirilmesi zordur. Ancak, bu benim açımdan bağımsızdır, yani farklı kod parçalarının etkileşiminin küresel değişkenlerle anlaşılması güçtür.
sleske

9

Kendi sorunuzu cevapladınız. 'İstismara uğradıklarında' başlarını yönetmek zor, ancak onları nasıl kullanacaklarını bilen biri tarafından doğru kullanıldığında yararlı ve [biraz] öngörülebilir olabilir. Kürelerdeki / kürelerdeki bakım ve değişiklikler, genellikle uygulama büyüklüğü arttıkça daha da kötüleşen bir kabustur.

Globaller tek seçenek olmaktan ve onları kolay düzeltme olmak arasındaki farkı söyleyebilir Deneyimli programcılar, olabilir bunları kullanarak minimum sorunları var. Ancak, kullanımları ile doğabilecek olası olası sorunlar, bunların kullanımına karşı tavsiyeyi gerektirmektedir.

düzenleme: Ne demek istediğimi açıklamak için, globals doğası gereği öngörülemez. Tahmin edilemez bir şey olduğu gibi, öngörülemezliği içermek için adımlar atabilirsiniz, ancak her zaman yapılabileceklerin sınırları vardır. Buna, projeye katılan yeni geliştiricilerin görece bilinmeyen değişkenlerle uğraşma derdinden dolayı, küresel kullanmaya karşı öneriler anlaşılabilir olmalıdır.


9

Singletons ile ilgili birçok sorun var - işte aklımdaki en büyük iki sorun.

  • Ünite testini problemli hale getirir. Küresel devlet bir testten diğerine bulaşabilir

  • Birden bire değişmesine rağmen, birdenbire değişmeyen "Bire-tek-tek" sert kuralını zorlar. Global olarak erişilebilir nesneyi kullanan bütün bir yardımcı kod kodu daha sonra değiştirilmelidir.

Bunu söyledikten sonra, çoğu sistemin Büyük Küresel Nesnelere ihtiyacı var. Bunlar büyük ve pahalı olan öğelerdir (örneğin Veri Tabanı Bağlantı Yöneticileri) veya yaygın durum bilgisi (örneğin, kilitleme bilgisi).

Bir Singleton'a alternatif, bu Büyük Küresel Nesnelerin başlangıçta yaratılmasını ve bu nesneye erişmesi gereken tüm sınıflara veya yöntemlere parametre olarak geçirilmesini sağlamaktır.

Burada sorun şu ki, büyük bir "parsel geçişi" oyunu ile bitiyor olmanız. Bir bileşen grafiğine ve bağımlılıklarına sahip olursunuz ve bazı sınıflar başka sınıflar yaratır ve her biri sadece ortaya çıkmış bileşenleri (veya doğmuş bileşenlerin bileşenleri) onlara ihtiyaç duydukları için bir sürü bağımlılık bileşeni bulundurmalıdır.

Yeni bakım problemleriyle karşılaşıyorsunuz. Örnek: Birdenbire "WidgetFactory" 'nizin, grafikteki bileşenin derinliklerinde, çıkarmak istediğiniz bir zamanlayıcı nesneye ihtiyacı var. Bununla birlikte, "WidgetFactory", "WidgetCreationManager" in bir parçası olan "WidgetBuilder" tarafından oluşturulur ve gerçekte yalnızca gerçekte kullanmasına rağmen, bu zamanlayıcı nesnesi hakkında bilgi sahibi olan üç sınıfa ihtiyacınız vardır. Kendinizi vazgeçmek ve Singletons'a geri dönmek istediğinizde buluyorsunuz ve bu zamanlayıcı nesnesini küresel olarak erişilebilir hale getirin.

Neyse ki, bu tam olarak bir Bağımlılık Enjeksiyonu çerçevesiyle çözülen problemdir. Çerçeveye hangi sınıfları yaratması gerektiğini söyleyebilirsiniz ve bağımlılık grafiğini sizin için bulmak için yansıma kullanır ve gerektiğinde her nesneyi otomatik olarak oluşturur.

Yani, özet olarak, Singletons kötüdür ve alternatif bir Bağımlılık Enjeksiyonu çerçevesi kullanmaktır.

Windsor Kalesi'ni kullanıyorum, ama seçim için şımarıksın. Mevcut çerçevelerin bir listesi için 2008 yılında bu sayfaya bakın .


8

Her şeyden önce bağımlılık enjeksiyonunun “durumsal” olması için, tekilleri kullanmanız gerekir, bu yüzden bunun bir şekilde alternatif olduğunu söyleyen insanlar yanlıştır. İnsanlar her zaman global bağlam nesnelerini kullanırlar ... Örneğin, oturum durumu bile temelde küresel bir değişkendir. Her şeyi bağımlılık enjeksiyonuyla yapıp yapmamak, her zaman en iyi çözüm değildir. Şu anda çok fazla küresel bağlam nesnesi (IoC kabı aracılığıyla enjekte edilen singletonlar) kullanan çok büyük bir uygulama üzerinde çalışıyorum ve bu hata ayıklama konusunda hiçbir zaman sorun olmadı. Özellikle olaya dayalı bir mimariyle, değişmiş olanı dolaşmak yerine küresel bağlam nesnelerini kullanmak tercih edilebilir. Kime sorduğuna bağlı.

Her şey kötüye kullanılabilir ve aynı zamanda uygulamanın türüne de bağlıdır. Örneğin bir web uygulamasında statik değişkenlerin kullanılması, bir masaüstü uygulamasından tamamen farklıdır. Genel değişkenlerden kaçınabiliyorsanız, bunu yapın, ancak bazen kullanımları vardır. En azından global verilerinizin açık bir bağlamsal nesnede olduğundan emin olun. Hata ayıklama kadarıyla hiçbir arama yığını ve bazı kesme noktaları çözemez.

Genel değişkenleri kör kullanmanın kötü bir fikir olduğunu vurgulamak istiyorum. İşlevler yeniden kullanılabilir olmalı ve verilerin nereden geldiğine dikkat etmemelidir - genel değişkenlere atıfta bulunmak, işlevi belirli bir veri girişi ile birleştirir. Bu nedenle içeri aktarılmasının ve bağımlılık enjeksiyonunun neden hala merkezi bir bağlam deposuyla (singletonlar aracılığıyla) uğraşıyor olmanıza yardımcı olabileceği konusunda yardımcı olabileceğini unutmayın.

Btw ... Bazı insanlar Linq'in yaratıcısı da dahil olmak üzere bağımlılık enjeksiyonunun kötü olduğunu düşünüyor, ancak bu ben de dahil insanların bunu kullanmasını engellemeyecek. Sonunda deneyim en iyi öğretmeniniz olacak. Kurallara uymanın ve onları çiğnemenin zamanları vardır.


4

Diğer bazı cevaplar burada arasındaki ayrım yapmak yana değişken ve değişmez küresel devlet, ben farzetmek istiyorum hatta değişmez küresel değişkenler / ayarlar genellikle sıkıntı vardır .

Sorunun sorusuna dikkat edin:

... Uygulamam için, örneğin sistem klasör yolları veya uygulama genelinde veritabanı kimlik bilgileri için genel bir yapılandırmaya ihtiyacım olduğunu varsayalım. ...

Doğru, küçük bir program için, bu muhtemelen bir sorun değildir, ancak bunu biraz daha büyük bir sistemde bileşenlerle yapar yapmaz , otomatik sınama yazmak aniden zorlaşır çünkü tüm sınamaların (~ aynı işlem içinde çalışıyor) çalışması gerekir. aynı global yapılandırma değeri.

Tüm konfigürasyon verilerinin açıkça aktarılması durumunda, bileşenlerin test edilmesi çok daha kolay hale gelir ve birden fazla test için, hatta paralel olarak bile, genel bir konfigürasyon değerini nasıl önyükleyeceğiniz konusunda endişelenmenize gerek yoktur.


3

Birincisi, tam olarak singleton'larla yapabileceğiniz aynı konuya girebilirsiniz. Bugün "yalnızca birine ihtiyacım olan küresel bir şey" gibi görünen şeyler birden bire yolun aşağısında ihtiyacınız olan bir şeye dönüşecek.

Örneğin, bugün bu genel yapılandırma sistemini yaratıyorsunuz çünkü tüm sistem için tek bir genel yapılandırma istiyorsunuz. Yoldan birkaç yıl sonra başka bir sisteme geçiyorsunuz ve biri "hey, bilirsin, genel bir genel yapılandırma ve bir platforma özgü yapılandırma olsaydı daha iyi çalışabilir" diyor. Birdenbire, küresel yapılarınızı küresel değil yapmak için tüm bu çalışmalara sahipsiniz, bu yüzden birden fazla olabilir.

(Bu rastgele bir örnek değil ... bu, şu an içinde bulunduğum projedeki yapılandırma sistemimizde oldu.)

Global olmayan bir şeyi yapmanın maliyetinin genellikle önemsiz olduğunu göz önünde bulundurarak bunu yapmak aptalca. Sadece gelecekteki problemleri yaratıyorsun.


Örnekiniz OP'nin anlamı değil. Açıkça soyut konfigürasyonlardan (sadece bir konfigürasyon yöneticisi veri yapısını, uygulamaya özel tercih anahtarları olmadan) defalarca dile getirdiğinizden bahsediyorsunuzdur çünkü programınızın çalışan bir örneğindeki tüm anahtarları konfigürasyon yöneticisi sınıfınızın birden fazla örneğine bölmek istersiniz. (Örneğin, bu örneklerin her biri bir yapılandırma dosyasını işleyebilir).
Jo,

3

Merakla meraklı olan bir diğer sorun da bir uygulamayı ölçeklendirmeyi zorlaştırmasıdır, çünkü yeterince “küresel” değildir. Global bir değişkenin kapsamı süreçtir.

Birden fazla işlem kullanarak veya birden fazla sunucuda çalıştırarak uygulamanızı ölçeklendirmek istiyorsanız, yapamazsınız. En azından, tüm dünyayı ele alıp başka bir mekanizma ile değiştirene kadar.


3

Küresel Devlet neden bu kadar kötü?

Değişken küresel durum kötüdür çünkü beynimizin bir seferde birkaç parametreden fazlasını hesaba katması ve bir şeyi etkilemek için hem zamanlama perspektifinden hem de değer perspektifinden nasıl birleştiğini bulması çok zordur.

Bu nedenle, bir programın yürütülmesi sırasında davranışının değiştirilmesi gereken birkaç dış nedenden daha fazlasına sahip olan bir nesnede hata ayıklama veya test etme konusunda çok kötüyüz. Bu nesnelerin bir araya getirilmesinde onlarca neden düşünmek zorunda kaldığımızda yalnız kal.


3

Güvenli ve sağlam sistemler tasarımı için tasarlanan diller, genellikle küresel değişebilir durumdan tamamen kurtulur . (Muhtemelen bu, hiçbir küre anlamına gelmez, çünkü değişmez nesneler hiçbir zaman bir devlet geçişine sahip olmadıkları için bir anlamda gerçekten de devletli değildirler.)

Joe-E buna bir örnek, ve David Wagner bu kararı şöyle açıklıyor:

Bir nesneye erişimi olanların ve en az ayrıcalık ilkesinin analizi, yetenekler global değişkenlerde saklandığında ve dolayısıyla programın herhangi bir kısmı tarafından potansiyel olarak okunabildiği zaman, altüst olur. Bir nesne global olarak kullanılabilir hale geldiğinde, analizin kapsamını sınırlamak artık mümkün değildir: nesneye erişim programdaki herhangi bir koddan alınamayan bir ayrıcalıktır. Joe-E, global kapsamın hiçbir yetenek, sadece değişken veri içermediğini doğrulayarak bu sorunlardan kaçınır.

Bunun hakkında düşünmenin bir yolu var

  1. Programlama dağıtılmış bir muhakeme problemidir. Büyük projelerdeki programcıların, programı bireylerin sebep olabileceği parçalara bölmeleri gerekir.
  2. Kapsam ne kadar küçük olursa, sebep o kadar kolay olur. Bu, bir sistemin özelliklerini kanıtlamaya çalışan hem bir sistemin özelliklerini test etmek için gereken testlerin hem bireyler hem de statik analiz araçları için geçerlidir.
  3. Global olarak mevcut olan önemli otorite kaynakları sistemin özelliklerini akla zorlaştırıyor.

Bu nedenle, küresel olarak değişebilir devlet, bunu zorlaştırıyor

  1. sağlam sistemler tasarlayabilir,
  2. bir sistemin özelliklerini ispatlamak daha zordur ve
  3. Testlerinizin üretim ortamınıza benzer bir kapsamda test edildiğinden emin olmak daha zor.

Genel değişken durumu DLL cehenneme benzer . Zaman içinde, büyük bir sistemin farklı parçaları, paylaşılabilir değişken durum parçalarından çok farklı davranışlar gerektirecektir. DLL cehennemini ve paylaşılabilir değişken durum tutarsızlıklarını çözmek, farklı ekipler arasında büyük ölçekli koordinasyon gerektirir. Bu sorunlar küresel devletin başlaması için uygun şekilde ele alındığı takdirde ortaya çıkmaz.


2

Globals o kadar da kötü değil. Diğer birkaç cevapta da belirtildiği gibi, onlarla ilgili asıl sorun, bugünün global klasör yolunuzun ne olacağı , yarın birkaç, hatta yüzlerce olabilir. Hızlı bir kereye mahsus bir program yazıyorsanız, daha kolaysa küreler kullanın. Genel olarak, ancak, yalnızca bir kişiye ihtiyacınız olduğunu düşündüğünüzde bile, katları kabul etmek, gitmenin yoludur. Birdenbire iki veritabanıyla konuşması gereken geniş ve karmaşık bir programı yeniden yapılandırmanız gerekmiyor .

Ancak güvenilirliğe zarar vermezler. Herhangi beklenmedik değişirse programınızda birçok yerlerden kaynak veri sorunlara yol açabilir. Numaralandırıcılar, numaralandırmakta oldukları koleksiyon numaralandırma ortasında değiştiğinde boğulur. Olay kuyruğu olayları birbiriyle ilgili püf noktaları oynayabilir. Dişler her zaman hasara yol açabilir. Yerel bir değişken veya değiştirilemez alan olmayan herhangi bir problemdir. Globals bu tür bir problemdir, fakat onları küresel olmayan hale getirerek düzeltemeyeceksiniz.

Bir dosyaya yazmak üzereyseniz ve klasör yolu değişirse, değişiklik ve yazmanın senkronize edilmesi gerekir. (Yanlış gidebilen bin şeyden biri olarak, yolu tuttuğunuzu, sonra bu dizinin silindiğini, ardından klasör yolunun iyi bir dizine dönüştüğünü, daha sonra silinen dizine yazmayı denediğinizi söyleyin.) Sorun olup olmadığını klasör yolu geneldir veya programın şu anda kullandığı binden biridir.

Sıradaki farklı olayların, farklı özyineleme seviyelerinin veya farklı iş parçacıklarının erişebileceği alanlarla ilgili gerçek bir sorun var. Basit (ve basit) yapmak için: yerel değişkenler iyi ve alanlar kötüdür. Ancak eski küreler hâlâ alan olacak, bu yüzden bu kritik öneme sahip konu, Küresel alanların İyilik veya Kötülük durumu için geçerli değil .

Ekleme: Çok Okunaklı Sorunlar:

(Bir olay kuyruğunda veya özyinelemeli çağrılarla benzer sorunlarla karşılaşabileceğinizi unutmayın, ancak çoklu okuma en kötüsüdür.) Aşağıdaki kodu göz önünde bulundurun:

if (filePath != null)  text = filePath.getName();

Eğer filePathyerel bir değişken veya sabit bir çeşit, programınız olduğunu değil çünkü çalışırken başarısız olacak filePathboş. Kontrol her zaman çalışır. Başka hiçbir iplik değerini değiştiremez. Aksi takdirde , hiçbir garanti yoktur. Java'da çok iş parçacıklı programlar yazmaya başladığımda, her zaman bu gibi satırlarda NullPointerExceptions var. herhangidiğer iş parçacığı değeri istediği zaman değiştirebilir ve sık sık yaparlar. Diğer bazı cevapların işaret ettiği gibi, bu test için ciddi problemler yaratır. Yukarıdaki açıklama, kapsamlı ve kapsamlı testlerden geçirerek milyarlarca kez çalışabilir ve ardından bir kez üretimde patlayabilir. Kullanıcılar sorunu çözemezler ve kendilerini bir şeyleri görmeye ve unutmaya ikna edene kadar bir daha olmaz.

Globals kesinlikle bu soruna sahiptir ve bunları tamamen ortadan kaldırabilir veya bunları sabitler veya yerel değişkenlerle değiştirebilirseniz, bu çok iyi bir şey. Bir web sunucusunda çalışan durumsuz kod varsa, muhtemelen yapabilirsiniz. Tipik olarak, tüm okuyuculuk sorunlarınız veritabanıyla çözülebilir.

Ancak, programınız bir kullanıcı işleminden diğerine bir şeyleri hatırlamak zorunda kalırsa, çalışan herhangi bir iş parçacığı tarafından erişilebilen alanlara sahip olacaksınız. Global bir dünyayı böyle küresel olmayan bir alana geçirmek, güvenilirliğe yardımcı olmaz.


1
Bununla
Andres F.

1
@AndresF .: Cevabımı uzattım. Sanırım bu sayfadaki çoğu kişinin bir veritabanı ile sunucu kodu olduğu daha fazla masaüstü yaklaşımı kullanıyorum. "Global" bu durumlarda farklı anlamlara gelebilir.
RalphChapin

2

Devlet herhangi bir gerçek uygulamada kaçınılmazdır. İstediğiniz şekilde sararsınız, ancak bir elektronik tablonun hücrelerde veri içermesi gerekir. Hücre nesnelerini yalnızca arabirim işlevi görerek yapabilirsiniz, ancak bu kaç kişinin hücre üzerinde bir yöntem çağırabileceğini ve verileri değiştirebileceğini kısıtlamaz. Sen arayüzleri kod böylece diğer kısımlarını gizlemek için denemek için tüm nesne hiyerarşileri inşa edemezVerileri varsayılan olarak değiştirin. Bu, içeren nesneye yapılan bir referansın keyfi bir şekilde iletilmesini engellemez. Bunların hiçbiri eşzamanlılık sorunlarını kendiliğinden ortadan kaldırmaz. Verilere erişimi arttırmayı zorlaştırıyor, ancak küresellerle ilgili algılanan sorunları gerçekten ortadan kaldırmıyor. Birisi bir devlet parçasını değiştirmek isterse, küresel ya da karmaşık bir API üzerinden havaya çıkarırlar.

Genel depolama kullanmamak için gerçek nedeni, ad çakışmalarını önlemektir. Aynı global adı bildiren birden fazla modül yüklerseniz, tanımsız davranışınız (birim testleri geçeceği için hata ayıklamak çok zor) veya bir linker hatası (bence C - Bağlayıcınız bu konuda uyarıyor veya başarısız oluyor mu?).

Eğer kodu tekrar kullanmak istersen, başka bir yerden bir modül kapmak zorundasın ve aynı isimde bir tane kullandıklarından yanlışlıkla dünyaya adım atmalarını sağlamalısın. Ya da şanslıysanız ve bir hata alırsanız, çarpışmayı önlemek için tüm referansları kodun bir bölümünde değiştirmek zorunda kalmazsınız.


1

Tüm küresel devleti görmek ve erişmek kolay olduğunda, programcılar her zaman böyle yaparlar. Alacağınız şey söylenmemiş ve bağımlılıkların izlenmesi zor (int blahblah, dizi foo'nun ne olursa olsun geçerli olduğu anlamına gelir). Temel olarak, program değişmezlerini korumayı neredeyse imkansız kılar, çünkü her şey bağımsız olarak bükülebilir. someInt'ın otherInt arasında bir ilişkisi var, yönetilmesi zor ve herhangi bir zamanda doğrudan değiştirip değiştiremeyeceğinizi kanıtlamak zor.

Bu, yapılabilir (bazı sistemlerde tek yol olduğunda geri dönüş yolu) yapılabilir, ancak bu beceriler kaybolur. Çoğunlukla kodlama ve adlandırma kuralları etrafında dönüyorlar - alan iyi sebeplerden dolayı ilerledi. Derleyici ve bağlayıcınız, korunan / özel sınıf / modül verilerindeki değişmezleri, bir ana planı takip etmek ve kaynakları okumak için insanlara güvenmekten daha iyi bir iş çıkarmaktadır.


1
"ama bu beceriler kayboldu" ... henüz tam değil. Kısa süre önce, alt rutinlere argüman gönderme gibi özelliklerden yoksun olan, kendi temeline benzer bir dili olan bir kod üretme aracı olan "Clarion" tarafından yemin edilen bir yazılımhanede çalıştım. "değişim" veya "modernleşme", sonunda sözlerimden bıktı ve beni yetersiz ve beceriksiz olarak resmetti. Ayrılmak zorunda kaldım ...
Louis Somers

1

Global değişkenlerin iyi ya da kötü olup olmadığını söylemeyeceğim, ancak tartışmaya ekleyeceğim şey, küresel durumu kullanmıyorsanız, muhtemelen çok fazla hafıza boşa harcayacağınızı söylemek. özellikle de bağımlılıklarını tarlalarda saklamak için sınıf kullandığınızda.

Küresel devlet için böyle bir sorun yoktur, her şey küreseldir.

Örneğin: aşağıdaki senaryoyu hayal edin: "Board" ve "Tile" sınıfından oluşan 10x10'luk bir ızgaraya sahipsiniz.

OOP yolu yapmak istiyorsanız, muhtemelen "Board" nesnesini her "Tile" 'a ileteceksiniz. Şimdi "Çini" nin koordinatını depolayan 2 "bayt" tipi alana sahip olduğunu varsayalım. Bir karo için 32 bit makinede alacağı toplam bellek (1 + 1 + 4 = 6) bayt: x koordinatı için 1, y koordinatı için 1 ve panoya bir işaretçi için 4 olacaktır. Bu, 10x10 karo kurulumu için toplam 600 bayt verir

Şimdi, Yönetim Kurulu'nun global kapsamda olduğu durumda, her bir döşemeden erişilebilen tek bir nesne, her döşemede yalnızca 2 bayt bellek almak zorunda kalacaktı, x ve y koordinat baytları. Bu sadece 200 bayt verirdi.

Yani bu durumda, yalnızca genel durumu kullanıyorsanız, bellek kullanımının 1 / 3'ünü alırsınız.

Bu, diğer şeylerin yanı sıra, küresel kapsamın hala C ++ gibi düşük seviyeli dillerde kalmasının bir nedeni olduğunu düşünüyorum.


1
Bu oldukça dile bağlı. Programların sürekli çalıştığı dillerde, birçok sınıfı başlatmak yerine global alan ve singleton kullanarak bellekten tasarruf edebileceğiniz doğru olabilir, ancak bu tartışma bile sarsıcıdır. Her şey öncelikler hakkında. PHP gibi (istek başına bir kez çalıştırılan ve nesneler devam etmez) gibi dillerde, bu argüman bile tartışmalıdır.
Madara Uchiha,

1
@MadaraUchiha Hayır, bu argüman hiçbir şekilde titrek değildir. Bu, VM veya başka bir derlenmiş dil bu tür bir konuda bazı zorlu kod optimizasyonları yapmadıkça, nesnel gerçeklerdir. Aksi taktirde hala alakalı. "Tek seferde" kullanılan sunucu tarafı programlarında bile, bellek yürütme sırasında saklanır. Yüksek yük sunucularında bu kritik bir nokta olabilir.
luke1985

0

Küresel devlet ile göz önünde bulundurulması gereken birkaç faktör var:

  1. Programcı hafızası
  2. Değişmez globals / bir kere globals yazmak.
  3. Değişebilen globals
  4. Küresellere bağımlılık.

Ne kadar küresel olursanız, çoğaltmaları tanıma ve bu sayede çoğaltmalar senkronizasyondan çıktığında işleri parçalama şansı o kadar artar. Tüm dünyayı sahte insan hafızanızda tutmak hem gerekli hem de acı vericidir.

Değiştirilemeyen / yazma bir kez genellikle tamam, ancak başlatma sırası hataları için dikkat edin.

Değişebilir küreler genellikle değişmez küreler ile karıştırılır…

Küreselleri etkili bir şekilde kullanan bir fonksiyon, ekstra "gizli" parametrelere sahiptir ve bu da yeniden düzenlemeyi zorlaştırır.

Küresel devlet kötü değildir, ancak belirli bir maliyetle gelir - fayda maliyetten daha ağır basarsa kullanın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.