Bir schrödinbug nedir?


52

Bu wiki sayfası şunları söylüyor:

Bir schrödinbug, yalnızca kaynak kodunu okuduktan veya programı alışılmadık bir şekilde kullandıktan sonra ortaya çıkan bir hatadır; ilk aşamada hiç çalışmaması gerektiğini fark eder, bu noktada program derhal herkes için çalışmayı durdurur. Jargon Dosyası şunu ekliyor: "Her ne kadar ... bu imkansız gibi geliyor, oluyor; bazı programlar yıllarca gizli schrödinbugs barındırıyor."

Konuşulan şey çok belirsiz ..

Birisi bir schrödinbug'un nasıl olduğunu gösteren bir örnek verebilir mi (kurgusal / gerçek hayattaki bir durum gibi)?


15
Alıntı şaka olarak söylenir.

11
Sana Shrödinger kedisine haberi olsaydı daha iyi shrodinbug anlardın düşünüyorum: en.wikipedia.org/wiki/Shrodingers_cat
Eimantas

1
@Eimantas Aslında daha fazla kafam karıştı ama bu ilginç bir makale :)

Yanıtlar:


82

Tecrübelerime göre, kalıp şudur:

  • Sistem, yıllarca sık çalışır
  • Bir hata bildirildi
  • Geliştirici hatayı araştırır ve tamamen kusurlu görünen ve "asla çalışamadığını" bildiren bir kod bulur.
  • Hata giderildi ve asla çalışamayacak (ancak yıllarca yapılan) kod efsanesi büyüdü

Burada mantıklı olalım. Çalışmış asla Kod ... çalışmış asla . O Eğer yaptığımız işi daha sonra ifadesi yanlıştır.

Bu yüzden tam olarak açıklandığı gibi bir hatanın (hatalı kodun çalışmasını durdurduğunu gözlemleyerek) açıkça saçma olduğunu söyleyeceğim .

Gerçekte olan şey iki şeyden biri:

1) Geliştirici kodu tam olarak anlamadı . Bu durumda, kod genellikle bir karışıklıktır ve içindeki bir yerde, bazı dış koşullara karşı büyük ancak belirgin olmayan bir duyarlılık vardır (belirli bir işletim sistemi sürümünü veya bazı işlevlerin küçük ama anlamlı bir şekilde nasıl çalıştığını düzenleyen bir yapılandırma söyleyin). Bu dış koşul değiştirilir (örneğin, ilgisiz olduğuna inanılan bir sunucu yükseltme veya değiştirme ile) ve bunu yaparken kodun kırılmasına neden olur.

Ardından geliştirici, koda bakar ve tarihsel bağlamı anlamayan veya olası her bağımlılık ve senaryoyu izlemeye vakti olmayan, hiçbir zaman çalışamayacağını ilan etti ve yeniden yazdı.

Bu durumda, burada anlaşılması gereken şey, “asla işe yaramayacağı” fikrinin kesinlikle yanlış olduğu (çünkü öyle olduğu).

Bu, yeniden yazmanın kötü bir şey olduğunu söylemek değildir - çoğu zaman değildir, çoğu zaman ne yanlış olduğunu bilmek güzel olsa da, zaman alan ve kod bölümünü yeniden yazmak genellikle daha hızlıdır ve işleri düzelttiğinizden emin olmanıza olanak sağlar.

2) Aslında hiç çalışmadı, hiç kimse hiç farketmedi . Bu, özellikle büyük sistemlerde şaşırtıcı şekilde yaygındır. Bu örnekte, yeni bir insan, daha önce hiç kimsenin yapmadığı şekilde olaylara bakmaya başlar veya daha önce bazı küçük davaları ana sürece ve daha önce gerçekten işe yaramayan (ya da hiçbirisini işe yaramayan bir şey) getiren bir iş süreci değişir. zaman) bulunur ve raporlanır.

Geliştirici ona bakar ve "hiç çalışamayacağını" açıklar ancak kullanıcılar "saçma, onu yıllardır kullanıyoruz" diyor ve haklılar ama ilgisiz olduğunu düşündükleri bir şey (ve genellikle geliştirici onlar "ah evet, biz yapacağız gitmek noktada kesin koşulunu bulur o şimdi ve daha önce yoktu" değişti).

İşte geliştirici haklı - asla işe yaramadı ve hiç işe yaramadı.

Ancak her iki durumda da iki şeyden biri doğrudur:

  • Asla işe yaramadığı iddiası doğrudur ve asla işe yaramadı - insanlar yaptığını sanıyorlardı
  • İşe yaradı ve “asla işe yaramazdı” ifadesi yanlış ve aşağı (genellikle makul) kod ve bağımlılıklarını anlama eksikliğine bağlı.

1
Çok sık başıma geliyor
genesis

2
Bu durumlar gerçekçilik içine büyük bir kavrayış
StuperUser

1
Bunun genellikle "WTF" anının bir sonucu olduğunu tahmin ediyorum. Bunu bir kere yaptım. Yazdığım bazı kodları tekrar okudum ve kısa süre önce fark edilen bir hatanın tüm uygulamayı bozması gerektiğini fark ettim. Aslında, daha fazla incelemeden sonra yazdığım diğer bir bileşen hataları telafi etmesi kadar iyi oldu.
Thaddee Tyl,

1
@Thaddee - Bunu daha önce görmüştüm ama kod modüllerinde birbirlerini iptal eden ve böylece gerçekten de işe yarayan iki hata kodu gördüm. İkisine de bakın, kırıldılar ama birlikte iyilerdi.
Jon Hopkins,

7
@Jon Hopkins: Birbirimizi iptal eden 2 böcek de var ve bu gerçekten şaşırtıcı. Bir hata buldum, “hiç işe yaramadı” şeklindeki aldatıcı ifadeyi dile getirdim, neden yine de işe yaradığını bulmak için daha derinlere baktım ve en azından çoğu durumda ilkini düzelten başka bir hata buldum. Keşif beni gerçekten şaşkına çevirdi ve aslında sadece böceklerden bir tanesi ile sonuç felaket olurdu!
Alexis Dufrenoy

54

Herkes hiç çalışmaması gereken bir koddan bahsettiği için, yaklaşık 8 yıl önce .net'e dönüştürülen ölmekte olan bir VB3 projesinde karşılaştığım bir örnek vereceğim. Ne yazık ki projenin .net sürümü tamamlanıncaya kadar güncel tutulması gerekiyordu - ve VB3'ü uzaktan bile anlayan tek kişi bendim.

Her hesaplama için yüzlerce kez denilen çok önemli bir işlev vardı - uzun vadeli emeklilik planlarına aylık faiz hesapladı. İlginç kısımları çoğaltacağım.

Function CalculateMonthlyInterest([...], IsYearlyInterestMode As Boolean, [...]) As Double
    [about 30 lines of code]
    If IsYearlyInterestMode Then
        [about 30 lines of code]
        If Not IsYearlyInterestMode Then
            [about 30 lines of code (*)]
        End If
    End If
End Function

Yıldız işaretli bölüm en önemli koda sahipti; Gerçek hesaplamayı yapan tek kısım buydu. Açıkçası bu hiç çalışmamalıydı, değil mi?

Çok fazla hata ayıklama aldı, ama sonunda sebebini buldum: IsYearlyInterestModeöyleydi Trueve Not IsYearlyInterestModeaynı zamanda doğruydu. Bunun nedeni, bir çizgi boyunca birisinin onu bir tamsayıya dönüştürmesidir, daha sonra onu doğru olarak arttırması gereken bir fonksiyonda (eğer bunun 0 Falseise 1 olacak, VB True, yani mantığı görebilecektim) orada), sonra bir boole geri. Ve asla olamayacak bir koşulla kaldım ve her zaman olur.


7
Epilog: Bu işlevi asla düzelttim; Ben sadece başarısız olan diğer sitelere 2 tane göndermek için arama sitemini yamaladım.
konfigüratör

Yani insanlar kodu yanlış anladıklarında kullanılır.
Pacerier

1
@Pacerier: Kod, genellikle yalnızca kazayla doğru şekilde çalışacak şekilde bir karışıklık olduğunda daha sık görülür. Benim örneğimde, hiçbir geliştiricinin IsYearlyInterestModehem doğru hem de doğru olmadığını; birkaç satır ekleyen orijinal geliştirici (biri de dahil olmak üzere ifaslında nasıl çalıştığını anlamadı - işe yarayacaktı, bu yüzden yeterince iyiydi.
konfigüratör

16

Gerçek dünyadan bir örnek bilmiyorum ama örnek bir durumla basitleştirmek için:

  • Bir hata, bir süredir fark edilmez, çünkü uygulama kodu bozmasına neden olan koşullar altında çalıştırmaz.
  • Birisi normal kullanım dışında bir şey yaparak (veya kaynağı inceleyerek) fark eder.
  • Artık hata fark edildiğinde, uygulama normal koşullara ve hata düzeltilinceye kadar başarısız olur.

Bu durum, hatanın önceki normal koşullarda başarısızlığa neden olan uygulamanın bazı durumlarını bozması nedeniyle olabilir.


4
Bir açıklama, yazılımda hiç kimsenin zihinsel olarak birbirine bağlanamadığı konusunda rastgele başarısızlıklar yaşandığıdır. Bu nedenle, bu hataların doğal sebeplerden biri olduğu düşünülüyordu (rastgele donanım hataları gibi). Kaynak kod okunduğunda, insanlar artık tüm önceki rastgele hataları bu sebeple ilişkilendirebilirler ve ilk başta hiç çalışmaması gerektiğini anlarlar.
rwong

4
İkinci bir açıklama, yazılımın bir sorumluluk zinciri modeliyle uygulanmış bir parçası olduğudur. Her bir işleyici, kritik bir hataya sahip olmasına rağmen, sağlam bir şekilde yazılmıştır. Şimdi, ilk işleyici her zaman başarısız olur, ancak ikinci işleyiciden (sorumluluğunda çakışan) aynı görevi yerine getirmeye çalıştığından, genel işlem başarılı olmuş gibi görünüyor. İkinci modülde, sorumluluk alanındaki değişiklik gibi herhangi bir değişiklik olması durumunda, asıl hata farklı bir konumda olmasına rağmen, genel bir arızaya neden olacaktır.
rwong

13

Gerçek hayattan bir örnek. Kod gösteremiyorum, ancak çoğu kişi bununla ilgili olacak.

Çalıştığım yerde büyük bir yardımcı program işlev kütüphanemiz var. Bir gün belirli bir şeyi yapacak bir işleve bakıyorum ve onu Frobnicate()kullanmayı deniyorum. Uh-oh: Frobnicate()Her zaman bir hata kodu veren çıktı.

Uygulamaya girerek, Frobnicate()her zaman başarısız olmasını sağlayan bazı temel mantık hataları buluyorum . Kaynak kontrolünde, fonksiyonun yazıldığı zamandan beri değiştirilmediğini görebiliyorum, yani fonksiyon hiç bir zaman amaçlandığı gibi çalışmadı. Neden kimse bunu fark etmedi? Kaynak listesinin geri kalanını araştırıyorum ve var olan tüm arayanların Frobnicate()geri dönüş değerini görmezden geldiğini tespit ediyorum (ve bu nedenle de kendilerine özgü ince hatalar içeriyor). Bu fonksiyonları gerektiği gibi dönüş değerini kontrol etmek için değiştirirsem, o zaman da başarısızlığa başlarlar.

Bu, Jon Hopkins'in cevabında bahsettiği 2 numaralı yaygın bir durumdur ve büyük iç kütüphanelerde iç karartıcı olarak yaygındır.


... harici bir kütüphanenin kullanılabilir olduğu her yerde, iç kütüphaneyi yazmaktan kaçınmak için iyi bir sebep yapar. Daha fazla test edilecek ve bu yüzden çok daha az kötü sürprizle karşılaşacak (açık kaynaklı kütüphaneler tercih edilir, çünkü yine de yaparsanız düzeltebilirsiniz).
Jan Hudec

Evet, ancak programcılar dönüş kodlarını görmezden gelirlerse, bu kütüphanenin hatası değildir. (Bu arada, en son ne zaman kodunu kontrol ettin printf()?)
JensG

İşte bu yüzden kontrol edilen istisnalar icat edildi.
Kevin Krumwiede 27:15

10

İşte bazı sistem kodunda gördüğüm gerçek bir Schrödinbug. Bir kök arka plan programının bir çekirdek modülüyle iletişim kurması gerekir. Böylece, çekirdek kodu bazı dosya tanımlayıcıları yaratır:

int pipeFDs[1];

daha sonra adlandırılmış bir boruya bağlanacak bir boru üzerinden iletişim kurar:

int pipeResult = pipe(pipeFDs);

Bu olmamalı çalışır. pipe()diziye iki dosya tanımlayıcısı yazar, ancak bir tane için yer vardır. Ancak yaklaşık yedi yıl boyunca işe yaradı ; dizi, bellekte bir dosya tanıtıcısı olarak kullanılmaya başlanan kullanılmamış bir alandan önceydi.

Sonra bir gün, kodu yeni bir mimariye taşımak zorunda kaldım. Çalışmayı bıraktı ve asla çalışmaması gereken böcek keşfedildi.


5

Schrödinbug'un bir sonucu, Heisenbug - araştırmaya ve / veya düzeltmeye çalışırken ortadan kaybolan (ya da bazen ortaya çıkan) bir hatayı tarif ediyor.

Heisenbugs, bir hata ayıklayıcı yüklendiğinde çalışan ve gizlenen, ancak izlemeyi bıraktıktan sonra ahşaptan çıkan efsanevi, zeki küçük yanmalardır.

Gerçekte, bunlar genellikle aşağıdakilerden birinin veya diğeri tarafından kaynaklanıyor gibi görünmektedir:

  • Kodun derlendiği optimizasyonun -DDEBUGsürüm derlemesinden farklı bir seviyeye optimize edilmesi
  • gerçek dünyadaki iletişim otobüsleri ya da benzetilmiş "mükemmel" kukla yüklerden tamamen farklı olmaları nedeniyle ince zamanlama farkları

Her ikisi de, serbest bırakma ekipmanı üzerinde serbest bırakma kodunun test edilmesinin yanı sıra emülatörleri kullanan birim / modül / sistem testinin önemini vurgulamaktadır.


Bunu göndermeden önce neden S.Lote'un cevabını ve delnan'ın yorumunu fark etmedim?
Andrew

Çok az deneyimim oldu ama birkaç tanesini buldum. Android NDK ortamında çalışıyordum. Hata ayıklayıcı bir kesme noktası bulduğunda, yalnızca C ++ olanları değil, bazı çağrıları mümkün kılan öğeler C ++ 'da başlatıldığı için Java iş parçacığını durdurdu. Hata ayıklayıcı olmadan bırakılırsa, Java kodu C ++ 'dan daha hızlı gider ve henüz başlatılmamış değerleri kullanmaya çalışır.
MLProgrammer-CiM 10:13

Birkaç ay önce Django veritabanı API'sini kullanmamızda Heisenbug'u keşfettim : Ne zaman DEBUG = Trueham bir SQL sorgusuna "parametreler" argümanı değişti. Sorgu uzunluğundan dolayı netlik için anahtar kelime argümanı olarak kullanıyorduk, beta sitesine DEBUG = False
gitme

2

Birkaç Schödinbug gördüm ve hep aynı sebepten dolayı:

Şirket politikası herkesin bir program kullanmasını gerektiriyordu.
Kimse gerçekten kullanmadı (çoğunlukla bunun için eğitim yoktu.)
Fakat bunu yönetemediler. Bu yüzden herkes "Ben bu programı 2 yıldır kullanıyorum ve bugüne dek bu hataya hiç karşılaşmadım" demek zorunda kaldı.
Program, azınlık bir kullanıcı haricinde (onu yazan geliştiriciler dahil) hiçbir zaman gerçekten çalışmadı.

Bir durumda, program çok fazla teste tabi tutulmuştu, ancak gerçek veritabanında (çok hassas kabul edildi, bu yüzden sahte bir versiyon kullanıldı).


1

Kendi tarihimden bir örneğim var, bu 25 yıl önceydi. Turbo Pascal'da ilkel grafik programlama yapan bir çocuktum. TP, ekranın bir bölgesini imleç tabanlı bir bellek bloğuna kopyalamanızı ve daha sonra başka bir yerde karıştırmanızı sağlayan bazı işlevleri içeren BGI adlı bir kütüphaneye sahiptir. Siyah beyaz ekranda xor blending ile birlikte basit animasyon yapmak için kullanılabilir.

Bir adım daha ileri gitmek ve sprite yapmak istedim. Bunları renklendirmek için büyük bloklar ve kontroller çizen bir program yazdım, bunu yaptığınız gibi bunları piksel olarak çoğalttıktan sonra sprite oluşturmak için daha sonra belleğe kopyalayabileceği basit bir çizim programı ürettim. Sadece bu sorunlu sprite'ları kullanmak için bir problem vardı, başka programların okuyabilmesi için bir dosyaya kaydedilmeleri gerekiyordu. Ancak TP'nin işaretçi tabanlı bellek ayırmayı seri hale getirme yolu yoktu. Yassı kılavuzlar dosyaya yazılamadıklarını belirtti.

Dosyaya başarıyla yazılan bir kod parçası ile geldim. Çizim programımdan bir arka plan üzerinde bir sprite içeren bir test programı yazmaya başladım - bir oyun yaratma yolunda. Ve güzelce çalıştı. Ancak ertesi gün çalışmayı bıraktı. Bozuk bir karmaşa dışında hiçbir şey göstermedi. Bir daha asla çalışmadı. Yeni bir sprite yarattım ve mükemmel bir şekilde çalıştı - olmadıkça ve yine karışık bir karmaşa oldu.

Uzun zaman aldı ama sonunda ne olduğunu anladım. Çizim programı, düşündüğüm gibi, kopyalanan piksel verisini dosyaya kaydetmiyordu - işaretçiyi de kurtarıyordu. Bir sonraki program dosyayı okuduğunda, aynı bellek bloğuna bir işaretçi ile son verdi - ki hala orada en son programın yazdıklarını içeriyordu (bu MS-DOS'taydı, bellek yönetimi yoktu). Ama işe yaradı ... tam olarak yeniden başlatılana ya da aynı hafıza alanını yeniden kullanan herhangi bir şeyi yönetene kadar çalıştı, ve sonra karışık bir karmaşa elde ettiniz, çünkü video belleği bloğuyla tamamen alakasız bir veriyi karıştırıyordunuz.

Asla çalışmamalıydı, hiç işe yaramamış bile görünmemeliydi (ve sahip olamayacağı herhangi bir gerçek işletim sisteminde) ama yine de yaptı ve bir kez bozuldu - kırıldı.


0

Bu, insanların hata ayıklayıcıları kullanması her zaman olur.

Hata ayıklama ortamı gerçek - hata ayıklayıcı - üretim ortamından farklıdır.

Bir hata ayıklayıcıyla çalışmak, yığın taşması gibi şeyleri maskeleyebilir, çünkü hata ayıklayıcının yığın çerçeveleri hatayı maskeler.


Bir hata ayıklayıcıda çalışan kod ile derlendiğinde arasındaki farktan bahsettiğini sanmıyorum.
Jon Hopkins

26
Bu bir schrödinbug değil, o bir heisenbug .

@delnan: Kenarında, IMO. Belirsiz bir şey buluyorum çünkü bilinmeyen bir özgürlük derecesi var. Heisenbug'u, bir şeyi ölçmenin aslında başkalarını rahatsız ettiği şeyler (örneğin, yarış koşulları, en iyi duruma getirici ayarları, ağ bant genişliği sınırlamaları, vb.) İçin ayırmayı severim
S.Lott

@ S.Lott: Tanımladığınız durum, yığın çerçeveleri veya benzeri şeyleri karıştırarak, şeyleri değiştiren gözlemi içerir. (Şimdiye kadar gördüğüm en kötü örnek, hata ayıklayıcının barışçıl ve tek adımlı modda geçersiz segment kayıt değerlerinin yüklerini "doğru" şekilde yürütmesiydi. Sonuç, RTL'de, korumalı modda gerçek mod göstergesini yüklemesine rağmen gönderilen bazı rutinlerdi. Sadece kopyalandığından ve kurallara
aykırı

0

Hiç gerçek bir schrodinbug görmedim ve onların var olabileceğini sanmıyorum - bulmanın bir şeyleri bozmayacağını.

Aksine, uzun zamandır gizlenen bir böceği açığa çıkaran bir şey değişti. Ne değişti olursa olsun hala değişmiştir ve böylelikle böcek ortaya çıkmaya devam ederken aynı zamanda birisi de hatayı bulur.

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.