Tüm koşulları yakalaması gereken başka bir merdiven - fazladan bir son madde eklenmeli mi?


10

Bu son zamanlarda çok yaptığım bir şey.

Misal:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else if (i > current) {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

Çoğu zaman if / else merdiveni bundan çok daha karmaşıktır ...

Son maddeyi görüyor musunuz? Gereksiz. Merdivenin nihayetinde tüm olası koşulları yakalaması gerekiyor. Böylece şöyle yeniden yazılabilir:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

Ben kod yazmak için kullanılan bu, ama bu tarzı sevmiyorum. Benim şikayetim, kodun son bölümünün yürütüleceği koşulun koddan belirgin olmamasıdır. Böylece daha belirgin hale getirmek için bu durumu açıkça yazmaya başladım.

Ancak:

  • Nihai kapsamlı koşulu açıkça yazmak benim fikrimdir ve kendi fikirlerimle kötü deneyimlerim var - genellikle insanlar bana ne yaptığımın ne kadar korkunç olduğunu bağırıyorlar - ve (bazen çok daha sonra) bunun gerçekten olduğunu öğrendim standart altı;
  • Bunun neden kötü bir fikir olabileceğine dair bir ipucu: Javascript için geçerli değildir, ancak diğer dillerde derleyiciler işlevin sonuna ulaşma konusunda uyarılar ve hatta hatalar verme eğilimindedir. Böyle bir şey yapmak ima etmek çok popüler olmayabilir ya da yanlış yapıyorum.
    • Derleyici şikayetleri bazen bir yorumda son durumu yazmamı sağladı, ancak kodun aksine yorumların gerçek program semantiği üzerinde hiçbir etkisi olmadığı için bunu yapmak korkunç:
    } else { // i > current
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }

Bir şey mi kaçırıyorum? Yoksa tarif ettiğim şeyi yapmak uygun mu yoksa kötü bir fikir mi?


@ Christophe için + 1 koddaki fazlalığın hata olasılığını artırdığına dair cevabı. Daha az verimlilik sorunu da var. Bunu genişletmek için, söz konusu kod örneğiyle ilgili olarak, if-else-if serisinin başka bir şey olmadan ayrı olması gibi yazabiliriz, ancak genellikle if-else okuyucusuna özel alternatifler kavramını vermez. (bir maçtan sonra bile tüm koşulların değerlendirilmesi gerektiğini söyler çünkü bu daha az verimli olacaktır).
Erik Eidt

@ErikEidt> çünkü bir fonksiyondan dönmediğiniz veya bir döngüden "kopmadığınız sürece" (yukarıdaki örnekte böyle değildir) tüm koşulların +1 eşleşmelerinden sonra bile değerlendirilmesi gerektiğini söyler.
Darek Nędza

1
+1, Güzel soru. Bir taraf olarak, NaN'ların varlığında örneğin kapsamlı olmadığı sizi ilgilendirebilir.
monocell

Yanıtlar:


6

Her iki yaklaşım da geçerlidir. Ama artıları ve eksileri daha yakından inceleyelim.

ifBurada gibi önemsiz koşullara sahip bir zincir için gerçekten önemli değil:

  • bir final ile else, okuyucunun diğerinin hangi durumda tetiklendiğini öğrenmesi açıktır;
  • Bir finalde else if, okuyucu elseiçin her şeyi kapsadığınızdan beri ek bir ihtiyaç olmadığı açıktır .

Bununla birlikte, ifbelki de karmaşık bir mantıksal ifade ile çeşitli değişkenlerin durumlarını birleştiren daha karmaşık koşullara dayanan çok sayıda zincir vardır. Bu durumda daha az açıktır. Ve burada her stilin sonucu:

  • final else: şubelerden birinin alındığından eminsiniz. Bir vakayı unutursanız, bu son daldan geçecektir, bu nedenle hata ayıklama sırasında, son dal seçildiyse ve başka bir şey beklediyseniz, hızlı bir şekilde anlayacaksınız.
  • final else if: kodlamak için gereksiz koşulu türetmeniz gerekir ve bu, tüm durumları kapsamamaktan kaynaklanan bir hata kaynağı oluşturabilir. Ayrıca, bir vakayı kaçırdıysanız hiçbir şey yapılmayacak ve bir şeyin eksik olduğunu bulmak daha zor olabilir (örneğin, ayarlanmasını beklediğiniz bazı değişkenler önceki iterasyonlardan değerleri koruyorsa).

Dolayısıyla, son gereksiz koşul bir risk kaynağıdır. Bu yüzden bir finale gitmeyi tercih ederim else.

Düzenleme: yüksek güvenilirlik kodlaması

Yüksek güvenilirliği düşünerek geliştiriyorsanız, başka bir varyantla ilgilenebilirsiniz: beklenmedik durumları yakalamak için gereksiz açık finalinizi else ifbir final ile tamamlamak else.

Bu savunma kodlamasıdır. SEI CERT veya MISRA gibi bazı güvenlik özellikleri tarafından önerilir . Bazı statik analiz araçları bunu sistematik olarak kontrol edilen bir kural olarak bile uygular (bu, derleyici uyarılarınızı açıklayabilir).


7
Son redundand koşulundan sonra her zaman "Bana ulaşmanız gerekmiyordu!" - Yaklaşımımın bazı problemlerini hafifletecek mi?
gaazkam

3
@gaazkam evet, bu çok savunmacı bir kodlama tarzı. Bu yüzden hala son durumu hesaplamanız gerekiyor, ancak karmaşık hataya eğilimli zincirler için en azından hızlı bir şekilde öğreneceksiniz. Bu varyant ile ilgili gördüğüm tek sorun, bariz bir durum için biraz aşırıya kaçması.
Christophe

@gaazkam Yorumunuzda bahsedilen ek fikrinizi de ele almak için cevabımı düzenledim
Christophe

1
@gaazkam İstisna atmak iyidir. Bunu yaparsanız, iletiye beklenmeyen değeri eklemeyi unutmayın. Çoğaltılması zor olabilir ve beklenmeyen değer sorunun kaynağı hakkında bir ipucu verebilir.
Martin Maat

1
Başka bir seçenek assertde finalde yer almaktır else if. Ancak stil rehberiniz bunun İyi Bir Fikir olup olmadığına göre değişebilir. ( assertProgramcı berbat olmadıkça a'nın durumu asla yanlış olmamalıdır. Bu en azından bu özelliği amaçlanan amaç için kullanmaktadır. Ancak pek çok insan birçok dükkanın bunu açıkça yasakladığını kötüye kullanır.)
Kevin

5

Şimdiye kadar cevaplarda eksik olan bir şey, ne tür bir başarısızlığın daha az zararlı olduğu meselesidir.

Eğer mantığınız iyiyse, ne yaptığınız gerçekten önemli değil, önemli durum, bir hatanız varsa ne olacağıdır.

Son koşulu atlıyorsunuz: Yapılması gereken doğru şey olmasa bile, son seçenek yürütülür.

Son koşulu eklemeniz yeterlidir: Herhangi bir seçeneği yürütmez, duruma bağlı olarak, bu sadece bir şeyin görüntülenemediği (düşük zarar) anlamına gelebilir veya daha sonraki bir noktada boş bir referans istisnası anlamına gelebilir (bu bir hata ayıklama olabilir) Ağrı.)

Son koşul ve bir istisna eklersiniz: Atar.

Bu seçeneklerden hangisinin en iyi olduğuna karar vermelisiniz. Geliştirme kodunda bunu no-brainer olarak görüyorum - üçüncü örneği ele alalım. Ancak, atmadan önce circle.src'yi bir hata görüntüsüne ve circle.alt'ı bir hata mesajına ayarlayacağım - eğer biri daha sonra iddiaları kapatmaya karar verirse, bu zararsız bir şekilde başarısız olur.

Dikkate alınacak başka bir şey - kurtarma seçenekleriniz nelerdir? Bazen bir kurtarma yolunuz olmaz. Bence bunun nihai örneği Ariane V roketinin ilk lansmanı. Destekleyicinin yok edilmesine yol açan yakalanmamış / 0 (aslında bir bölüm taşması) hatası oluştu. Gerçekte, çöken kod o noktada hiçbir amaca hizmet etmiyordu, kayış destekleyicilerin yandığı anda tartışmaya başlamıştı. Yörüngeyi veya patlamayı yaktıktan sonra, elinizden gelenin en iyisini yaparsınız, hatalara izin verilemez. (Roket bundan dolayı saparsa, güvenlik görevlisi anahtarını çevirir.)


4

Ne tavsiye bir kullanıyor assertbu iki stilleri biriyle, son else deyimi:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else {
        assert i > current
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    }
}

Veya ölü bir kod iddiası:

setCircle(circle, i, { current }) {
    if (i == current) {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
    } else if (i < current) {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
    } else if (i > current) {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
    } else {
        assert False, "Unreachable code"
    }
}

Kod kapsamı aracı, genellikle kapsama raporundan "iddia False" gibi kodu yok sayacak şekilde yapılandırılabilir.


Koşulu bir iddiaya koyarak, bir şubenin durumunu etkili bir şekilde belgelersiniz, ancak bir yorumdan farklı olarak, iddia koşulu gerçekten kontrol edilebilir ve geliştirme veya üretim sırasında iddiaları etkin tutarsanız başarısız olur (genellikle iddiaları etkin tutmanızı öneririm performansı çok fazla etkilemezlerse).


1
İlk seçeneğinizi beğenmedim, ikincisi bunun imkansız olması gereken bir durum olduğu çok daha açık.
Loren Pechtel

0

Bir koşulu değerlendiren “iddia edilen” bir makro tanımladım ve bir hata ayıklama derlemesinde hata ayıklayıcıya düştüm.

Dolayısıyla, üç koşuldan birinin doğru olması gerektiğinden yüzde 100 emin olursam,

If condition 1 ...
Else if condition 2 .,,
Else if asserted (condition3) ...

Bu, bir koşulun doğru olacağını yeterince açıklar ve bir iddia için ekstra dal gerekmez.


-2

Tamamen başka bir şeyden kaçınmanızı öneririm . ifKod bloğunun ne işleyeceğini bildirmek için kullanın ve işlevden çıkarak bloğu sonlandırın.

Bu çok açık bir kodla sonuçlanır:

setCircle(circle, i, { current })
{
    if (i == current)
    {
        circle.src = 'images/25CE.svg'
        circle.alt = 'Now picking'
        return
    }
    if (i < current)
    {
        circle.src = 'images/25C9.svg'
        circle.alt = 'Pick failed'
        return
    }
    if (i > current)
    {
        circle.src = 'images/25CB.svg'
        circle.alt = 'Pick chance'
        return
    }
    throw new Exception("Condition not handled.");
}

Final ifelbette gereksiz ... bugün. Gelecekteki bazı geliştiricilerin blokları yeniden düzenleyip düzenlemediği / ne zaman ayarlanacağı çok önemli bir düşünce haline gelebilir. Bu yüzden orada bırakmak yararlıdır.


1
Aslında çok net değil çünkü şimdi ilk dalın yürütülmesinin ikinci testin sonucunu değiştirip değiştiremeyeceğini düşünmem gerekiyor. Artı anlamsız çoklu dönüş. Ayrıca hiçbir koşulun doğru olmaması olasılığı.
gnasher729

Aslında bilerek birden fazla vaka alınabileceğini düşündüğümde böyle ifadeler yazıyorum. Özellikle düşmeye izin vermeyen anahtar ifadeleri olan dillerde kullanışlıdır. Eğer seçimler birbirini dışlarsa, vakaların birbirini dışladığı (başkalarını kullanarak) belli olacak şekilde yazılmalıdır. Ve eğer böyle yazılmadıysa, sonuç, davaların birbirini dışlamadığıdır (düşme mümkündür).
Jerry Jeremiah

@ gnasher729 Tepkinizi tamamen anlıyorum. Ben ilk başta "başka önlemek" ve "erken dönüş" ile sorun vardı bazı çok akıllı insanlar biliyorum. Fikre alışmak ve ona bakmak için biraz zaman ayırmanızı öneririm - çünkü bu fikirler objektif ve ölçülebilir bir şekilde karmaşıklığı azaltır. Erken dönüş aslında ilk noktanıza hitap eder (bir şubenin başka bir testi değiştirip değiştiremeyeceğini düşünmek gerekir). Ve "hiçbir koşulun doğru olmaması olasılığı" hala mevcuttur; bu stille, gizli bir mantık hatası yerine bariz bir istisna elde edersiniz.
John Wu

Ancak, her iki stilin siklomatik karmaşıklığı tam olarak aynı değil mi? yani koşul sayısına eşit
gaazkam
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.