Muhtemelen istisna dışında işlemlerle kodun güçlendirilmesi


12

Kodun başka bir bölümünün doğru kodlanmamış olması durumunda işe yaramaz istisna işlemeyi uygulamak iyi bir uygulama mı?

Temel örnek

Basit bir tane, bu yüzden herkesi kaybetmem :).

Diyelim ki bir kişinin bilgilerini (ad, adres vb.) Görüntüleyecek bir uygulama yazıyorum, veriler bir veritabanından çıkartılıyor. Diyelim ki UI bölümünü kodlayan benim ve başka biri DB sorgu kodunu yazıyor.

Şimdi, uygulamanızın özelliklerinin, kişinin bilgileri eksikse (diyelim ki, ad veritabanında eksikse), sorguyu kodlayan kişinin eksik alan için "NA" döndürerek bunu ele alması gerektiğini söylediğini düşünün.

Sorgu kötü kodlanmışsa ve bu durumu ele almıyorsa ne olur? Sorguyu yazan kişi size eksik bir sonuç verirse ve bilgileri görüntülemeye çalıştığınızda kodunuz boş şeyler görüntülemeye hazır olmadığından her şey çöker?

Bu örnek çok basit. Çoğunuzun "bu sizin probleminiz değil, bu kazadan siz sorumlu değilsiniz" diyeceğine inanıyorum. Ancak, hala kodun çökmekte olan kısmı.

Başka bir örnek

Diyelim ki sorguyu yazan kişi benim. Spesifikasyonlar yukarıdakiyle aynı şeyi söylemez, ancak "insert" sorgusunu yazan adamın, eksik bilgi eklemekten kaçınmak için veritabanına bir kişi eklerken tüm alanların eksiksiz olduğundan emin olması gerekir. Kullanıcı arabirimine tam bilgi verdiğimden emin olmak için "select" sorgumu korumam gerekir mi?

Sorular

Spesifikasyonlar açıkça "bu adam bu durumu idare etmekten sorumlu kişi" demezse ne olur? Üçüncü bir kişi başka bir sorgu uygularsa (birincisine benzer, ancak başka bir DB'de) ve görüntülemek için UI kodunuzu kullanır, ancak kodunda bu durumu ele almazsa ne olur?

Kötü davayı ele almam gereken kişi olmasam da, olası bir çökmeyi önlemek için gerekenleri yapmalı mıyım?

"Çarpışmadan o sorumlu olan biri" gibi bir cevap aramıyorum, burada bir çatışmayı çözmediğim için bilmek istiyorum, kodumu durumlara karşı korumalıyım, bu benim sorumluluğum değil idare etmek? Burada, basit bir "boş bir şey yap" yeterli olacaktır.

Genel olarak, bu soru gereksiz istisna yönetimiyle ilgilenir. Bunu soruyorum çünkü bir projede tek başıma çalıştığımda, ardışık işlevlerde benzer bir istisna işlemeyi 2-3 kez kodlayabilirim, "ne olursa olsun" yanlış bir şey yaptım ve kötü bir durumun ortaya çıkmasına izin verdim.


4
"Testler" hakkında konuşuyorsunuz, ancak sorununuzu anladığım kadarıyla "üretimde uygulanan testler" anlamına geliyorsunuz, buna "doğrulama" veya "istisna işleme" denir.
Doc Brown

1
Evet, uygun sözcük "istisna işleme" dir.
rdurand

yanlış etiketi değiştirdi
Doc Brown

Sizi The DailyWTF'e yönlendiriyorum - bu tür bir test yapmak istediğinizden emin misiniz?
gbjbaanb

@gbjbaanb: Bağlantınızı doğru anlarsam, bahsettiğim hiç de bu değil. "Aptal testlerden" bahsetmiyorum, istisna yönetimini çoğaltmaktan bahsediyorum.
rdurand

Yanıtlar:


14

Burada bahsettiğiniz şey güven sınırlarıdır . Uygulamanız ve veritabanı arasındaki sınıra güveniyor musunuz? Veritabanı, uygulamadaki verilerin her zaman önceden doğrulandığına güveniyor mu?

Bu, her başvuruda alınması gereken bir karardır ve doğru ve yanlış cevap yoktur. Çok fazla sınırın güven sınırı olarak adlandırılma yanına düşme eğilimindeyim, diğer geliştiriciler her zaman, her zaman, yapmasını beklediğiniz şeyi yapmak için üçüncü taraf API'larına güvenecekler.


5

Sağlamlık ilkesi "Gönderdiklerinizde muhafazakar olun, kabul ettiğiniz şeylerde liberal olun" peşinde olduğunuz şeydir. Bu iyi bir prensiptir - DÜZENLEME: uygulaması herhangi bir ciddi hatayı gizlemediği sürece - @pdr ile her zaman duruma uymanız gerekip gerekmediğine bağlı olduğunu kabul ediyorum.


Bazı insanlar "sağlamlık ilkesi" nin saçma olduğunu düşünüyor. Makale bir örnek veriyor.

@MattFenwick: işaret ettiğin için teşekkürler, geçerli bir nokta, cevabımı biraz değiştirdim.
Doc Brown

2
Bu, "sağlamlık ilkesi" ile ilgili sorunları gösteren daha iyi bir makaledir: joelonsoftware.com/items/2008/03/17.html
hakoja

1
@hakoja: dürüst olmak gerekirse, bu makaleyi iyi biliyorum , sağlamlık prensibini takip etmemeye başladığınızda karşılaştığınız problemlerle ilgili (bazı MS'lerin yeni IE sürümleriyle denediği gibi). Bununla birlikte, bu orijinal sorudan biraz uzakta olur.
Doc Brown

1
@DocBrown: kabul ettiğiniz şeyde asla liberal olmamalısınız. Sağlamlık, size atılan her şeyi şikayet etmeden kabul etmeniz gerektiği anlamına gelmez, sadece çarpışmadan size atılan her şeyi kabul etmeniz gerekir.
Marjan Venema

1

Ne test ettiğine bağlı; ancak testinizin kapsamının yalnızca kendi kodunuz olduğunu varsayalım. Bu durumda, şunları test etmelisiniz:

  • "Mutlu durum": uygulamanızın geçerli girdisini besleyin ve doğru çıktı ürettiğinden emin olun.
  • Hata durumları: uygulamanız geçersiz girişlerini besleyin ve doğru şekilde işlediğinden emin olun.

Bunu yapmak için meslektaşınızın bileşenini kullanamazsınız: bunun yerine alaycı kullanın , uygulamanın geri kalanını test çerçevesinden kontrol edebileceğiniz "sahte" modüller ile değiştirin. Bunu tam olarak nasıl yapacağınız modüller arayüzüne bağlıdır; modülünüzün yöntemlerini sabit kodlu bağımsız değişkenlerle çağırmanız yeterli olabilir ve diğer modüllerin genel arabirimlerini test ortamına bağlayan bütün bir çerçeve yazmak kadar karmaşık olabilir.

Bu sadece birim test senaryosu. Ayrıca tüm modülleri birlikte test ettiğiniz entegrasyon testleri de istersiniz. Yine, hem mutlu durumu hem de başarısızlıkları test etmek istiyorsunuz.

"Temel Örnek" durumunuzda, kodunuzu birim sınamak için, veritabanı katmanını taklit eden bir sahte sınıf yazın. Sahte sınıfınız gerçekten veritabanına gitmiyor: sadece beklenen girdiler ve sabit çıktılarla önceden yüklüyorsunuz. Sahte kodda:

function test_ValidUser() {
    // set up mocking and fixtures
    userid = 23;
    db = new MockDB();
    db.fixedResult = { firstName: "John", lastName: "Doe" };
    db.expectedCall = { method: 'getUser', params: { userid: userid } };
    userController = new UserController(db);
    expectedResult = "John Doe";

    // run the actual test
    actualResult = userController.displayUserAsString(userid);

    // check assertions
    assertEquals(expectedResult, actualResult);
    db.assertExpectedCall();
}

Doğru şekilde bildirilen eksik alanları nasıl test edeceğiniz aşağıda açıklanmıştır :

function test_IncompleteUser() {
    // set up mocking and fixtures
    userid = 57;
    db = new MockDB();
    db.fixedResult = { firstName: "John", lastName: "NA" };
    db.expectedCall = { method: 'getUser', params: { userid: userid } };
    userController = new UserController(db);

    // let's say the user controller is specified to leave "NA" fields 
    // blank
    expectedResult = "John";

    // run the actual test
    actualResult = userController.displayUserAsString(userid);

    // check assertions
    assertEquals(expectedResult, actualResult);
    db.assertExpectedCall();
}

Şimdi işler ilginçleşiyor. Gerçek DB sınıfı yanlış davranırsa ne olur? Örneğin, belirsiz nedenlerden dolayı bir istisna atabilir. İşe yarayıp yaramadığını bilmiyoruz, ancak kendi kodumuzu incelikle işlemesini istiyoruz. Sorun değil, sadece MockDB'mizin bir istisna atmasını sağlamalıyız, örneğin böyle bir yöntem ekleyerek:

class MockDB {
    // ... snip
    function getUser(userid) {
        if (this.fixedException) {
            throw this.fixedException;
        }
        else {
            return this.fixedResult;
        }
    }
}

Ve sonra test durumumuz şöyle görünüyor:

function test_MisbehavingUser() {
    // set up mocking and fixtures
    userid = 57;
    db = new MockDB();
    db.fixedException = new SQLException("You have an error in your SQL syntax");
    db.expectedCall = { method: 'getUser', params: { userid: userid } };
    userController = new UserController(db);

    // run the actual test
    try {
        userController.displayUserAsString(userid);
    }
    catch (DatabaseException ex) {
        // This is good: our userController has caught the raw exception
        // from the database layer and wrapped it in a DatabaseException.
        return TEST_PASSED;
    }
    catch (Exception ex) {
        // This is not good: we have an exception, but it's the wrong kind.
        testLog.log("Found the wrong exception: " + ex);
        return TEST_FAILED;
    }
    // This is bad, too: either our mocking class didn't throw even when it
    // should have, or our userController swallowed the exception and
    // discarded it
    testLog.log("Expected an exception to be thrown, but nothing happened.");
    return TEST_FAILED;
}

Bunlar birim testleriniz. Entegrasyon testi için MockDB sınıfını kullanmazsınız; bunun yerine, her iki gerçek sınıfı birlikte zincirlersiniz. Hala fikstürlere ihtiyacınız var; örneğin, testi çalıştırmadan önce test veritabanını bilinen bir duruma başlatmalısınız.

Şimdi, sorumluluklar söz konusu olduğunda: Kodunuz, kod tabanının geri kalanının spesifikasyona göre uygulanmasını beklemelidir, ancak geri kalanı vidalandığında işleri zarif bir şekilde ele almaya da hazır olmalıdır. Kendi dışındaki kodu test sorumlu değildir, ama olan diğer ucundaki kod uygunsuz hareket eden kodunuzu esnek hale sorumlu ve aynı zamanda kodun esnekliğini test sorumludur. Yukarıdaki üçüncü test budur.


sorunun altındaki yorumları okudun mu? OP "testler" yazdı, ancak "doğrulama kontrolleri" ve / veya "istisna yönetimi" anlamında kastetti
Doc Brown

1
@tdammers: yanlış anlama için özür dilerim, aslında istisnalarla uğraşmak istedim .. Neyse tam cevap için teşekkürler, son paragraf aradığım şeydi.
rdurand

1

Kodlamaya çalıştığım 3 ana ilke var:

  • KURU

  • ÖPMEK

  • YAGNI

Tüm bu ovmak başka bir yerde çoğaltılan doğrulama kodu yazma riski vardır. Doğrulama kuralları değişirse, bunların birden fazla yerde güncellenmesi gerekir.

Tabii ki, gelecekte bir noktada, sen olabilir bu durumda avantajlı olacaktır birden fazla yerde koduna sahip düşünebilir (olur) veritabanınızı replatform. Ama ... olmayan bir şeyi kodluyorsun.

Yazılması, okunması, saklanması ve test edilmesi gerekeceği için herhangi bir ek kod (asla değişmezse bile) ek yüktür.

Yukarıdakilerin hepsi doğruysa, hiçbir doğrulama yapmamanız size hatırlatıyor olacaktır. Uygulamada tam bir ad görüntülemek için, verilerin kendisini doğrulamasanız bile bazı temel verilere ihtiyacınız olacaktır.


1

Layman'ın sözleriyle.

"Veritabanı" veya "uygulama" diye bir şey yoktur .

  1. Bir veritabanı birden fazla uygulama tarafından kullanılabilir.
  2. Bir uygulama birden fazla veritabanı kullanabilir.
  3. Veritabanı modeli, tablo tanımında varsayılan bir değer tanımlanmadığı sürece, bir ekleme işlemine gerekli bir alan eklenmediğinde hata atmayı içeren veri bütünlüğünü sağlamalıdır. Uygulamayı atlayarak satırı doğrudan veritabanına ekleseniz bile bu işlem yapılmalıdır. Veritabanı sisteminin sizin için yapmasına izin verin.
  4. Veritabanları veri bütünlüğünü korumalı ve hatalar atmalıdır .
  5. İş mantığı bu hataları yakalamalı ve sunum katmanına istisnalar atmalıdır .
  6. Sunum katmanı girişi doğrulamalı, istisnaları işlemeli veya kullanıcıya üzgün bir hamster göstermelidir.

Tekrar:

  • Veritabanı-> atış hataları
  • Business Logic-> hataları yakalamak ve istisnalar atmak
  • Sunum Katmanı -> doğrulayın, istisnalar atın veya üzücü mesajlar gösterin.
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.