Favori (Akıllı) Defansif Programlama En İyi Uygulamaları [kapalı]


148

Eğer savunma kodlaması için Favori (akıllı) tekniklerinizi seçmek zorunda olsaydınız, bunlar ne olurdu? Mevcut dillerim Java ve Objective-C (arka plan C ++ 'da) olmasına rağmen, herhangi bir dilde cevap vermekten çekinmeyin. Buradaki vurgu ,% 70'inden fazlasının zaten bildiği teknikler dışında akıllı savunma tekniklerine olacaktır . Şimdi hile çantanızın derinliklerine inme zamanı.

Başka bir deyişle, bu ilginç örnek dışında düşünmeye çalışın :

  • if(5 == x) yerine if(x == 5) : istenmeyen atamayı önlemek için

İşte bazı ilginç en iyi savunma programlama uygulamalarına bazı örnekler (dile özgü örnekler Java'dadır):

- Değişkenlerinizi değiştirmeniz gerektiğini bilene kadar değişkenlerinizi kilitleyin

Yani, değiştirmeniz gerekeceğini bilinceye kadar tüm değişkenleri finalbildirebilirsiniz, bu noktada final. Yaygın olarak bilinmeyen bir gerçek, bunun yöntem parametreleri için de geçerli olduğudur:

public void foo(final int arg) { /* Stuff Here */ }

- Kötü bir şey olduğunda, geride bir kanıt bırakın

Bir istisnanız olduğunda yapabileceğiniz birkaç şey vardır: Açıkçası oturum açmak ve bazı temizlik yapmak birkaç şey olacaktır. Ancak bir kanıt izi de bırakabilirsiniz (örn. "DOSYA catchYÜKLENEMEZ " veya 99999 gibi sentinel değerlerine değişkenleri ayarlamak, bir istisna -block'u aşarsanız hata ayıklayıcıda yararlı olacaktır ).

- Tutarlılık söz konusu olduğunda: şeytan ayrıntıda gizlidir

Kullandığınız diğer kütüphanelerle tutarlı olun. Örneğin, Java'da, bir değer aralığı ayıklayan bir yöntem oluşturuyorsanız, alt sınırı kapsayıcı ve üst sınırını özel hale getirin . Bu String.substring(start, end), aynı şekilde çalışan yöntemler gibi tutarlı hale getirecektir . O endeksler Sıfır (gelmektedir diziler, tutarlı elemanların yineleme dahil olmak üzere çeşitli işlemleri yapar gibi bu şekilde davranmasına Güneş JDK yöntemlerin bu türdeki tüm bulacaksınız Anin dizinin (uzunluğuna) münhasır ).

Peki senin favori savunma uygulamaların neler?

Güncelleme: Henüz yapmadıysanız, giriş yapmaktan çekinmeyin. Resmi yanıtı seçmeden önce daha fazla yanıt gelmesi için bir şans veriyorum .


Burada basit teknikleri bilmeyen cahil% 30'umuzu temsil etmek istiyorum . Herkesin temel olarak bilmesi gereken "açık" tekniklerle bağlantısı olan var mı?
elliot42


Neden resmi bir cevap seçesiniz ki? Kulağa tamamen amca gibi geliyor.
bzlm

Programlama söz konusu olduğunda, akıllılık bile "en az şaşkınlık kuralı" onuruna arka koltuk almalıdır. Benim için en iyi cevabı işaretleme Yığın Taşması ruhu ile kırmak benim için Yığın Taşma protokolünü ihlal eder (dolayısıyla adı geçen kuralı ihlal eder). Bunun dışında:
Kapanmayı

Yanıtlar:


103

C ++, bir zamanlar çit sonrası hataları yakalamak için biraz fazladan bellek sağlamak için yeni tanımlamayı sevdim.

Şu anda, Test Odaklı Geliştirme lehine savunma programlamasından kaçınmayı tercih ediyorum . Hataları hızlı ve harici olarak yakalarsanız, kodunuzu savunma manevraları ile karıştırmanıza gerek yoktur, kodunuz KURU -er'dir ve savunmanız gereken daha az hatayla karşılaşırsınız.

WikiKnowledge'un yazdığı gibi :

Defansif Programlamadan Kaçının, Yerine Hızlı Başarısız Olun.

Defansif programlama ile, verilerdeki bazı arızaları telafi etmeye çalışan kod yazma alışkanlığı, arayanların arayan ve altyordam arasındaki sözleşmeye uymayan veriler sağlayabileceğini ve altyordamın bir şekilde başa çıkması gerektiğini varsayan kod yazma alışkanlığını kastediyorum Bununla.


8
Defansif programlama, bir programın diğer bölümleri tarafından getirilen yasadışı koşullarla başa çıkmaya çalışmaktadır. Hatalı kullanıcı girişini kullanmak tamamen farklı bir şeydir.
Joe Soul-getirici

5
Hata ... Bu savunmacı programlama tanımının, soruda dolaylı olarak kullanılan tanıma yakın olmadığını unutmayın.
Sol

15
Savunma Programlamasından asla kaçının. Mesele, verilerdeki hataları "telafi etmek" değil, kodunuzu yapması gerekmeyen şeyleri yapmak için tasarlanmış kötü amaçlı verilerden kendinizi korumaktır. Bkz. Arabellek Taşması, SQL Enjeksiyonu. Hiçbir şey XSS altında bir web sayfasından daha hızlı başarısız olmaz, ancak hoş değil
Jorge Córdoba

6
"Hızlı başarısız" prosedürlerin bir çeşit savunma programlaması olduğunu iddia ediyorum.
Ryan Delucchi

6
@ryan tam olarak doğru, hızlı başarısız olmak iyi bir savunma konsepti. Bulunduğunuz durum mümkün değilse, topallamaya çalışmayın, HIZLI VE YÜKSEK HATA! Meta veri odaklıysanız ekstra önem taşır. Defansif programlama sadece parametrelerinizi kontrol etmekle kalmaz ...
Bill K

75

SQL

Verileri silmem gerektiğinde

select *    
--delete    
From mytable    
Where ...

Koştuğumda, nerede ibaresini unuttuğumu veya yok ettiğimi bileceğim. Bir güvenliğim var. Her şey yolundaysa, '-' yorum belirteçlerinden sonra her şeyi vurgularım ve çalıştırırım.

Düzenleme: Çok fazla veri siliyorsam, sadece * yerine count (*) kullanacağım


Bunu iPhone'uma yazdım, burada metin seçemiyorum. Birisi kodumu kod olarak işaretleyebilirse, gerçekten takdir edilecektir. Teşekkürler.
John MacIntyre

6
Ben sadece bir işlemde sarın, bu yüzden eğer vidalanırsam geri alabilirim ...
rmeador

36
İŞLEM BAŞLANGIÇ | GERİ
BİLDİRİM İŞLEMİ

3
+1 Evet, bunun bir işlemle değiştirilebileceğini düşünüyorum, ancak bunu bu şekilde yapmanın basitliğini seviyorum.
Ryan Delucchi

3
Bir işlemi kullanmak daha iyidir; Bu, düzinelerce kez çalıştırabileceğiniz ve gerçek efektleri görebileceğiniz anlamına gelir , ancak doğru yaptığınızdan ve taahhüt edebileceğinizden emin oluncaya kadar.
Ryan Lundy

48

Uygulama başladığında makul bir bellek yığını ayırın - Bence Steve McConnell bunu Kod Tamamlama'da bir bellek paraşütü olarak adlandırdı .

Bu, ciddi bir şeyin yanlış gitmesi ve sonlandırmanız gerektiğinde kullanılabilir.

Bu belleği öne ayırmak size bir güvenlik ağı sağlar, çünkü bu belleği boşaltabilir ve ardından aşağıdakileri yapmak için kullanılabilir belleği kullanabilirsiniz:

  • Tüm kalıcı verileri kaydet
  • Tüm uygun dosyaları kapatın
  • Hata iletilerini bir günlük dosyasına yazma
  • Kullanıcıya anlamlı bir hata gösterin

Bunun yağmurlu bir gün fonu olduğunu gördüm.
Süpürgelik

42

Varsayılan bir durumda olmayan her switch deyiminde, programı bir hata iletisiyle iptal eden bir vaka eklerim.

#define INVALID_SWITCH_VALUE 0

switch (x) {
case 1:
  // ...
  break;
case 2:
  // ...
  break;
case 3:
  // ...
  break;
default:
  assert(INVALID_SWITCH_VALUE);
}

2
Ya da modern kanatlı bir dilde bir atış.
Tom Hawtin - tackline

2
Assert, etkilerinin derleme zamanında küresel olarak devre dışı bırakılabilmesi avantajına sahiptir. Yine de, bazı durumlarda diliniz destekliyorsa, atış daha uygun olabilir.
Diomidis Spinellis

2
Assert'in üretim kodu için yararlı olmasını sağlayan başka bir avantajı daha var: Bir şeyler ters gittiğinde, tam olarak neyin başarısız olduğunu ve hatanın hangi satırından geldiğini size söyler. Böyle bir hata raporu harika!
Mason Wheeler

2
@Diomidis: Başka bir açı şudur: Assert, etkilerinin derleme zamanında küresel olarak devre dışı bırakılabilmesi dezavantajına sahiptir .
hayal kırıklığına uğradı

1
atmak gerçekten daha iyi. Ve sonra test kapsamınızın yeterli olduğundan emin olursunuz.
Dominic Cronin

41

Bir numaralandırmanın çeşitli durumlarını (C #) işlerken:

enum AccountType
{
    Savings,
    Checking,
    MoneyMarket
}

Sonra, bazı rutinin içinde ...

switch (accountType)
{
    case AccountType.Checking:
        // do something

    case AccountType.Savings:
        // do something else

    case AccountType.MoneyMarket:
        // do some other thing

    default:
-->     Debug.Fail("Invalid account type.");
}

Bir noktada bu numaraya başka bir hesap türü ekleyeceğim. Ve bunu yaptığımda, bu anahtar deyimini düzeltmeyi unutacağım. Bu yüzden Debug.Faildikkatimi bu gerçeğe çekmek için (Hata Ayıklama modunda) korkunç çöküyor. Eklediğimde, case AccountType.MyNewAccountType:korkunç bir çökme durur ... başka bir hesap türü ekleyene ve buradaki durumları güncellemeyi unutana kadar.

(Evet, burada polimorfizm muhtemelen daha iyidir, ancak bu sadece kafamın üstünden bir örnek.)


4
Çoğu derleyici, bir vaka bloğundaki bazı numaralandırmaları işlemezseniz uyarı verecek kadar akıllıdır. Ancak varsayılanı başarısız olarak ayarlamak hala iyi bir formdur - bir numaralandırma sadece bir sayıdır ve bellek bozulması alırsanız geçersiz bir değere sahip olabilirsiniz.
Adam Hawes

c, sonunda bir geçersizAccountType eklemek için kullanılır. bu bazen yararlıdır.
Ray Tayek

1
@Adam - derleyiciler her şeyi yeniden derlerseniz uyarı verir . Yeni sınıflar ekler ve yalnızca kısmen yeniden derlerseniz, yukarıdaki gibi bir şey fark etmeyebilirsiniz ve varsayılan durum sizi kurtaracaktır. Sadece sessizce başarısız olmaz.
Eddie

4
Mola yorumlarda ima ediliyor, Slashene. : P
Ryan Lundy

2
Hata ayıklama sonra üretim kodu için bir 'yeni NotSupportedException () atmak' olmalıdır.
user7116

35

Hata mesajlarını bir dizeyle (özellikle kullanıcı girişine bağlı olan) yazdırırken, her zaman tek tırnak kullanırım ''. Örneğin:

FILE *fp = fopen(filename, "r");
if(fp == NULL) {
    fprintf(stderr, "ERROR: Could not open file %s\n", filename);
    return false;
}

Buradaki tırnak eksikliği %sgerçekten kötü, çünkü dosya adı boş bir dize veya sadece boşluk veya başka bir şey. Yazdırılan mesaj elbette:

ERROR: Could not open file

Yani, her zaman yapmak daha iyidir:

fprintf(stderr, "ERROR: Could not open file '%s'\n", filename);

Sonra en azından kullanıcı bunu görür:

ERROR: Could not open file ''

Bunun son kullanıcılar tarafından gönderilen hata raporlarının kalitesi açısından büyük bir fark yarattığını düşünüyorum. Genel bir şey yerine böyle komik görünümlü bir hata mesajı varsa, sadece "dosyalarımı açmaz" yazmak yerine kopyalayıp yapıştırmaları çok daha olasıdır.


4
iyi bir, ben de bu sorunu gördüm
Alex Baranosky

28

SQL Güvenliği

Verileri değiştirecek herhangi bir SQL yazmadan önce, her şeyi geri alma işleminde sararım:

BEGIN TRANSACTION
-- LOTS OF SCARY SQL HERE LIKE
-- DELETE FROM ORDER INNER JOIN SUBSCRIBER ON ORDER.SUBSCRIBER_ID = SUBSCRIBER.ID
ROLLBACK TRANSACTION

Bu, kalıcı olarak kötü bir silme / güncelleme yürütmenizi engeller. Ayrıca, her şeyi yürütebilir ve makul kayıt sayılarını doğrulayabilir veya her şeyin doğru göründüğünden emin olmak SELECTiçin SQL ile - arasında deyimler ekleyebilirsiniz ROLLBACK TRANSACTION.

Beklediğiniz şeyi yaptığından tamamen emin olduğunuzda, ROLLBACKdeğerini değiştirin COMMITve gerçekte çalıştırın.


Beni bu konuda yumruk at! :-)
Howard Pinsley

2
Bunu her zaman yapardım, ama DB kümeleri üzerinde çok fazla ek yüke neden olmak zorunda kaldım.
Zan Lynx

25

Tüm diller için:

Değişkenlerin kapsamını mümkün olan en düşük seviyeye indirin. Onları bir sonraki ifadeye taşımak için sağlanan Eschew değişkenleri . Var olmayan değişkenler, anlamanız gerekmeyen değişkenlerdir ve sorumlu tutulamazsınız. Aynı nedenden ötürü Lambdas'ı mümkün olduğunca kullanın.


5
Eschew kısmı tam olarak ne anlama geliyor? Bazen sadece bir sonraki satıra kadar yaşayan değişkenleri tanıtırım. Kodun daha okunaklı olmasını sağlayan bir ifade adı olarak işlev görürler.
zoul

4
Evet ben de katılmıyorum. Çok karmaşık ifadelerle, bunları geçici değişkenler kullanarak iki veya bazen daha kısa ve basit olanlara bölmek genellikle iyi bir fikirdir. Bakımda daha az hata oluşuyor ve derleyici temps'i optimize edecek
Cruachan

1
Açıklık için değişkenler beyan ettiğim (ve bazen hata ayıklama için bir hedef oluşturduğum) istisnai durumlar olduğunu kabul ediyorum. Benim tecrübem, genel uygulamanın ters yönde hata yapmaktır.
dkretz

Her iki görüşe de katılıyorum; ancak ifadeleri geçici değişkenlere ayırdığımda bunu ayrı bir kapsamda yapmaya çalışıyorum. Lambdalar, yardımcı yöntemler gibi bunun için de harika.
Erik Forbes

19

Şüphe duyduğunuzda, uygulamayı bombalayın!

Kontrol her başında parametreyi her yöntemi (explictly kendiniz kodlama veya sözleşmeye dayalı programlama kullanarak olmadığı değil mesele burada yapar) ve doğru istisna ve / veya anlamlı hata mesajı ile bomba kodunda herhangi ön şart ise karşılanmadı.

Kodu yazdığımızda hepimiz bu örtülü önkoşulları biliyoruz , ancak açıkça kontrol edilmezlerse, bir şeyler daha sonra ters gittiğinde ve düzinelerce yöntem çağrısı, belirtinin ve gerçek konumun ayrılığını ayırdığında kendimiz için labirentler yaratıyoruz. burada bir ön koşul karşılanmaz (= sorunun / hatanın gerçekte olduğu yer).


Ve elbette: Bunu kolaylaştırmak için genel kodu (küçük bir kütüphane, C # 'da uzantı yöntemleri) kullanın. Eğer glike birşey yazabilirsiniz Yani param.NotNull("param")yerineif ( param == null ) throw new ArgumentNullException("param");
peSHIr

2
Veya Spec #! Gibi sözleşme tabanlı programlamayı kullanın!
bzlm

Hangi uygulamaya bağlı olduğuna göre değişir. Umarım uçakla uçuş yapan uçaklar ve kalp pilleri için kod yazan kişiler peSHIr gibi düşünmezler.
MarkJ

6
@MarkJ: Gerçekten anlamıyorsun, değil mi? Erken bombalarsa (= geliştirici ve test sırasında) üretim sırasında asla bombalamamalıdır. Umarım böyle bir program yaparlar !
peSHIr

Bunu çok sevmediğimi itiraf etmeliyim, özellikle özel ve korunan yöntemler için. Sebepler: a) kodu, işletme gereksinimlerine hiç benzemeyen çeklerle karıştırırsınız b) bu ​​kontrolleri halka açık olmayan yöntemler açısından test etmek zordur c) birçok durumda işe yaramaz, örneğin boş bir değer yöntemin başarısız olmasına neden olacağından neyse iki satır sonra
Erich Kitzmueller

18

Java'da, özellikle koleksiyonlarda API'yı kullanın, bu nedenle yönteminiz Liste türü (örneğin) döndürüyorsa aşağıdakileri deneyin:

public List<T> getList() {
    return Collections.unmodifiableList(list);
}

Sınıfınızdan kaçmak için ihtiyaç duymadığınız hiçbir şeye izin vermeyin!


+1 C # 'da bunun için salt okunur koleksiyonlar vardır.
tobsen

1
Java için +1. Bunu her zaman kullanıyorum
Mart

+1 ... Bunu çok yapıyorum (daha fazla insan bunu yapmayı hatırlasa da).
Ryan Delucchi

Başka hiçbir şeyin altta yatan liste değişkeninin bir örneğine sahip olmadığından emin olun, yoksa bu size çok iyi
gelmeyecektir

5
FYI, Collections.unmodifiableList , değişmez bir kopya değil listenin sabit bir görünümünü döndürür . Orijinal liste değiştirilirse, görünüm de değişecektir!
Zarkonnen

17

Perl’de herkes

use warnings;

severim

use warnings FATAL => 'all';

Bu, herhangi bir derleyici / çalışma zamanı uyarısı için kodun ölmesine neden olur. Bu çoğunlukla başlatılmamış dizelerin yakalanmasında yararlıdır.

use warnings FATAL => 'all';
...
my $string = getStringVal(); # something bad happens;  returns 'undef'
print $string . "\n";        # code dies here

Bu biraz daha reklamı
olsaydı

16

C #:

string myString = null;

if (myString.Equals("someValue")) // NullReferenceException...
{

}

if ("someValue".Equals(myString)) // Just false...
{

}

Java ve muhtemelen çoğu OO dilinde aynıdır.
MiniQuark

Bu, nil'e (belirli bir lisansla “boş bir nesnenin çağrı yöntemleri”) mesaj göndermenin mümkün olduğu Objective-C'de güzel. [Nil isEqualToString: @ "Moo"] çağrısı yanlış döndürür.
zoul

C # örneğine katılmıyorum. Güzel bir çözüm "if (myString ==" someValue ")" kullanmaktır. Ayrıca null referans istisnası ve kesinlikle daha okunabilir.
Dan C.

13
bu örnek, programınızdaki potansiyel olarak tehlikeli bir durumu gizlemenize izin verir. Eğer null olmasını beklemiyorduysanız, bir istisna atmasını İSTERSİNİZ ve null olmasını bekliyorsanız, bu şekilde ele almalısınız. Bu kötü bir uygulamadır.
rmeador

2
C # 'da her zaman sadece string.Equals (<string1>, <string2>) kullanırım. İkisinin de boş olması önemli değil.
Darcy Casselman

15

Dizgede uzunluk, indexOf, mid vb gibi işlemler yapmadan önce string.IsNullOrEmpty öğesinin c # kontrolünde

public void SomeMethod(string myString)
{
   if(!string.IsNullOrEmpty(myString)) // same as myString != null && myString != string.Empty
   {                                   // Also implies that myString.Length == 0
     //Do something with string
   }
}

[Düzenle]
Şimdi ayrıca .NET 4.0, ayrıca değerin sadece boşluk olup olmadığını denetler aşağıdakileri yapabilirim

string.IsNullOrWhiteSpace(myString)

7
Bu defansif değil, sorunu görmezden geliyor. Olmalı if (!string.IsNullOrEmpty(myString)) throw new ArgumentException("<something>", "myString"); /* do something with string */.
enashnash

14

Java ve C # 'da, her iş parçacığına anlamlı bir ad verin. Bu, iş parçacığı havuzu iş parçacıklarını içerir. Yığın dökümlerini çok daha anlamlı hale getirir. Hatta iş parçacığı havuzu iş parçacıkları için anlamlı bir ad vermek için biraz daha fazla çaba gerektirir, ancak bir iş parçacığı havuzu uzun süren bir uygulamada bir sorun varsa, bir yığın dökümü oluşmasına neden olabilir ( SendSignal.exe hakkında bilmek , değil mi? ), günlükleri alın ve çalışan bir sistemi kesintiye uğratmadan hangi iş parçacıklarının olduğunu söyleyebilirim ... her neyse. Kilitlenme, sızıntı, büyüme, sorun ne olursa olsun.


Ve - Windows'ta - C ++ için de! (özel SEH istisna atışı ve aşağıdaki yakalama ile etkinleştirilir).
Brian Haak

12

VB.NET ile, Visual Studio'nun tamamı için varsayılan olarak Option Explicit ve Option Strict'i açın.


Ben eski kod ile çalışmama rağmen, bu yüzden sıkı bir seçenek yok (düzeltmek için çok fazla derleyici hataları neden olur), bu iki seçenek açık olan (ve benim durumumda) çok kalp kurtardı ağrısı.
Kibbee

1
Bu arada, kullanmak için Option Strict'i kullanmayan eski kodu dönüştüren herkes için, otomatik olarak String'e dönüştürülen öğelerde ToString () kullanmadığını unutmayın. yaymak için bir döküm kullanıyorlar. İlk .NET günlerimde ToString () kullanmak için bunları değiştirirdim ve özellikle numaralandırmalarda bazı şeyleri kıracaktı.
Ryan Lundy

10

C ++

#define SAFE_DELETE(pPtr)   { delete pPtr; pPtr = NULL; }
#define SAFE_DELETE_ARRAY(pPtr) { delete [] pPtr; pPtr = NULL }

ardından tüm ' pPtr sil ' ve ' sil [] pPtr ' çağrılarınızı SAFE_DELETE (pPtr) ve SAFE_DELETE_ARRAY (pPtr) ile değiştirin

Şimdi yanlışlıkla 'pPtr' işaretçisini sildikten sonra kullanırsanız, 'erişim ihlali' hatası alırsınız. Düzeltmek rastgele bellek bozulmalarından çok daha kolaydır.


1
Bir şablon kullansak iyi olur. Kapsamlı ve indirilebilir.

Bunu söylemek üzereydim. Makro yerine şablon kullanın. Bu şekilde, kod boyunca adım atmanız gerekirse, bunu yapabilirsiniz.
Steve Rowe

Okulda zor yoldan hata ayıklamanın daha kolay olduğunu öğrendim. O zamandan beri yapmadığım bir hata. :)
Greg D

3
Ya da Akıllı İşaretçiler kullanın ... Ya da heck, yeni / silmekten mümkün olduğunca kaçının.
Arafangion

1
@Arafangion: sadece kaçının delete. Kullanarak newyeni bir amacı, bir akıllı işaretçi sahip olur sürece, gayet iyi.
Alexandre

10

Java ile, üretim kodunu iddialar kapalıyken çalıştırsanız bile assert anahtar kelimesini kullanmak kullanışlı olabilir:

private Object someHelperFunction(Object param)
{
    assert param != null : "Param must be set by the client";

    return blahBlah(param);
}

İddialar kapalı olsa bile, en azından kod, parametrenin bir yerde ayarlanması beklendiğini belgelemektedir. Bunun özel bir yardımcı işlev olduğunu ve genel bir API'nın üyesi olmadığını unutmayın. Bu yöntem yalnızca sizin tarafınızdan çağrılabilir, bu nedenle nasıl kullanılacağı konusunda belirli varsayımlar yapmak sorun değildir. Genel yöntemler için, geçersiz giriş için gerçek bir istisna atmak daha iyidir.


.NET'te Debug.Assert de aynı şeyi yapar. Eğer düşündüğünüz bir yere sahip olduğunda, bunu eğer öyleyse bu, orada Debug.Assert koyabilirsiniz "Bu referans değil mi? Burada null olamaz" olabilir null, ya hata düzeltmek veya varsayımları değiştirebilir.
Ryan Lundy

1
+1, genel yöntemler sözleşme başarısızlıklarına yol
açmalı

9

Ben bulamadık readonlyReSharper bulana kadar anahtar kelime, ama şimdi özellikle hizmet sınıfları için, içgüdüsel kullanabilirsiniz.

readonly var prodSVC = new ProductService();

Java'nın eşdeğer 'final' anahtar kelimesini kullanabileceğim tüm alanlarda kullanıyorum. Gerçekten, bir alan ayarlamamak / alanları birden çok kez ayarlayabilen kafa karıştırıcı anahtarlar yazmak gibi bonehead hareketleri yapmaktan sizi kurtarır. Yerel değişkenleri / parametreleri işaretlemek daha az olasıdır, ancak sanırım zarar veremezdi.
Yasadışı Programcı

C #, yerel değişkenleri salt okunur olarak işaretlemenize izin vermez, bu yüzden seçeneğimiz bile yoktur ...
Jason Punyon

Burada salt okunurluğun ne olduğundan emin değilim, ama Java'nın finali benim için yeterli değil. Bu sadece bir nesnenin işaretçisinin değişmediği anlamına gelir, ancak nesnenin kendisinde değişiklik yapılmasını önlemenin bir yolu yoktur.
Slartibartfast

C # 'da salt okunur bir yapı, değiştirilmesini engeller.
Samuel

9

Java'da bir şey olduğunda ve nedenini bilmiyorum, bazen Log4J'yi şu şekilde kullanacağım:

if (some bad condition) {
    log.error("a bad thing happened", new Exception("Let's see how we got here"));
}

bu şekilde bana beklenmedik duruma nasıl geldiğimi gösteren bir yığın izlemesi alıyorum, asla kilidin açılmadığı bir kilit söyleyin, boş olamaz bir şey söyle. Açıkçası, eğer gerçek bir İstisna atılırsa, bunu yapmam gerekmiyor. Bu, aslında başka bir şey rahatsız etmeden üretim kodunda neler olduğunu görmem gerektiğinde. Ben yok bir özel durum atmak istiyorum ve bir tane anlayamadım. Sadece olanları işaretlemek için uygun bir mesajla bir yığın izlemesini istiyorum.


Hmm, bu biraz temiz ama fonksiyonel ve hata işleme kodunun bir miktar karışmasına neden olacağından endişeliyim. Try-catch mekanizması sakar tarafında olabilir, hepsi hata işleme nerede olduğu, başka (catch) için bir blok (deneyin) den istisna yeniden yönlendirme yürütme yapmak için birini zorlar
Ryan Delucchi

1
Bu, hata işleme için değil , yalnızca tanılama için kullanılır. Bu, kodunuzun akışını kesintiye uğratmadan kodunuzun beklenmedik bir duruma girme yolunu görmenizi sağlar. Bunu, yöntemin kendisi beklenmedik durumla başa çıkabildiğinde kullanıyorum, ancak yine de olmamalı.
Eddie

2
ayrıca yeni İstisna ("mesaj") da kullanabilirsiniz. printStackTrace (); Atma veya yakalama gerekmez, ancak yine de günlükte güzel bir yığın izi alırsınız. Açıkçası, bu üretim kodunda olmamalı, ancak hata ayıklama için çok yararlı olabilir.
Jorn

9

Visual C ++ kullanıyorsanız, bir temel sınıfın yöntemini her geçtiğinizde override anahtar sözcüğünü kullanın . Bu şekilde, herhangi biri temel sınıf imzasını değiştirirse, yanlış yöntem sessizce çağrılmak yerine derleyici hatası atar. Daha önce var olsaydı bu beni birkaç kez kurtaracaktı.

Misal:

class Foo
{
   virtual void DoSomething();
}

class Bar: public Foo
{
   void DoSomething() override { /* do something */ }
}

Java için bu sınıf Foo {void doSomething () {}} sınıf Çubuğu {@Override void doSomething () {}} Ek açıklama eksikse bir uyarı verir (böylece yapmadığınız bir yöntemi sessizce geçersiz kılamazsınız) ek açıklama varsa ve hiçbir şeyi geçersiz kılmadığında).
Jorn

Güzel ... Bunu bilmiyordum ... Microsoft'a özgü gibi gözüküyor ... ama bazı
#defines

8

Gerçekten süresiz olarak uzun sürebileceğini beklemediğim sürece , Java'da kilidin kilidini açmak için neredeyse hiç süresiz olarak beklemeyi öğrendim . Gerçekçi olarak, kilit birkaç saniye içinde kilidini açacaksa, sadece belirli bir süre bekleyeceğim. Kilit açılmazsa, yığını günlüklere şikayet edip döküyorum ve sistemin kararlılığı için en iyi olana bağlı olarak ya kilit açılmış gibi devam edin ya da kilit hiç açılmamış gibi devam edin.

Bu, bunu yapmaya başlamadan önce gizemli olan birkaç yarış koşulunu ve sahte kilitlenme koşullarını izole etmeye yardımcı oldu.


1
bu gibi zaman aşımlarıyla beklemek diğer, daha kötü sorunların bir işaretidir.
dicroce

2
Yüksek çalışma süresine sahip olması gereken bir sistemde, sorunu bulmak için en azından tanı bilgilerini almak daha iyidir. Bazen sistem bilinen bir durumdayken bir iş parçacığından çıkmayı veya arayana bir yanıt vermeyi tercih edersiniz, böylece bir semaforda beklersiniz. Ama sonsuza kadar asmak istemezsin
Eddie

8

C #

  • Genel yöntemde başvuru türü parametreleri için null olmayan değerleri doğrulayın.
  • Ben sealedistemediğim yerde bağımlılıkları tanıtmak önlemek için sınıflar için çok kullanıyorum . Mirasa izin vermek, kazara değil açık bir şekilde yapılmalıdır.

8

Bir hata mesajı verirken, en azından program bir hata atma kararı verdiğinde sahip olduğu bilgileri sağlamaya çalışın.

"İzin reddedildi" size bir izin sorunu olduğunu söylüyor, ancak sorunun neden veya nerede oluştuğu hakkında hiçbir fikriniz yok. "İşlem günlüğü / dosyam: dosya salt okunur dosya sistemi" yazılamıyor, en azından yanlış olsa bile kararın verildiği temeli bilmenizi sağlıyor - özellikle yanlışsa: yanlış dosya adı? yanlış mı açıldı? başka beklenmedik hata? - ve sorun yaşadığınızda nerede olduğunuzu bilmenizi sağlar.


1
Bir hata mesajı kodunu yazarken, mesajı okuyun ve daha sonra ne bilmek istediğinizi sorun , ardından ekleyin. Mantıksız oluncaya kadar tekrarlayın. Örneğin: "Aralık dışı." Kapsama alanı dışında ne var? "Foo sayımı aralık dışında." Değer neydi? "Foo sayısı (42) aralık dışında." Aralık nedir? "Foo sayısı (42) aralık dışında (549 ila 666)."
HABO

7

C # 'da asyayınlamak için anahtar kelimeyi kullanın.

string a = (string)obj

obj bir dize değilse bir istisna atar

string a = obj as string

obj bir dize değilse, null değerini bırakacaktır

Hala null değerini dikkate almanız gerekir, ancak bu genellikle istisnaları aramaktan daha doğrudur. Bazen "döküm veya havaya uçurma" tipi davranışlar istersiniz, bu durumda (string)objsözdizimi tercih edilir.

Kendi kodumda, assözdizimini yaklaşık% 75 oranında ve (cast)sözdizimi yaklaşık% 25 kullandığımı görüyorum .


Doğru, ancak şimdi referansı kullanmadan önce null olup olmadığını kontrol etmeniz gerekiyor.
Brian Rasmussen

7
Anlamadım. Boş olanı tercih etmek benim için kötü bir karar gibi görünüyor. Orijinal nedenden ötürü hiçbir ipucu olmadan çalışma zamanı sırasında bir yerde sorunlar yaşarsınız .
Kai Huppmann

Evet. Bu, yalnızca doğru tür olmadığında null istemeniz durumunda kullanışlıdır. Bazı durumlarda kullanışlıdır: kontrol mantığının ve tasarımın sıklıkla ayrıldığı Silverlight'ta, mantık yalnızca bir düğme ise "Yukarı" kontrolünü kullanmak ister. Değilse, sanki yokmuş gibi (= null).
Sander

2
Bu, bir kaledeki büyük balo salonu pencereleri kadar savunmacı görünüyor. Ama güzel bir manzara!
Pontus Gagge

1
Bu bana 'programları kırdıkları' istisnaları kullanmayan birini hatırlatıyor. Bir nesne beklediğiniz bir sınıf olmadığında belirli davranışlar istiyorsanız, bunu başka bir şekilde kodlayacağımı düşünüyorum. is/instanceofakla ilkbahar.
Kirschstein

6

Herhangi bir giriş için hazır olun ve beklenmedik bir şekilde aldığınız herhangi bir giriş, günlüklere dökün. (Bu nedenle, kullanıcıdan şifreleri okuyorsanız, günlüklere dökmeyin! Bu tür binlerce iletiyi saniyede günlüklere kaydetmeyin. Oturum açmadan önce içerik, olasılık ve sıklık nedeni .)

Sadece kullanıcı girişi doğrulamasından bahsetmiyorum. Örneğin, XML içermeyi beklediğiniz HTTP isteklerini okuyorsanız, diğer veri biçimlerine hazır olun. Yalnızca XML beklediğim yerde HTML yanıtlarını gördüğüme şaşırdım - isteğimin farkında olmadığım şeffaf bir proxy'den geçtiğini ve müşterinin cehaletini talep ettiğini görünceye kadar - ve proxy istek. Böylece proxy, istemcime bir HTML hata sayfası döndürerek istemciden yalnızca XML verisi bekleyen karışıklığı karıştırdı.

Böylece, telin her iki ucunu da kontrol ettiğinizi düşünseniz bile, herhangi bir kötü niyetli olmadan beklenmedik veri formatları alabilirsiniz. Beklenmedik bir giriş durumunda hazırlıklı olun, savunmacı bir şekilde kodlayın ve tanı çıktısı sağlayın.


6

Sözleşme ile Tasarım yaklaşımını kullanmaya çalışıyorum. Herhangi bir dil tarafından çalışma süresi benzetilebilir. Her dil "iddia" yı destekler, ancak hatayı daha kullanışlı bir şekilde yönetmenizi sağlayan daha iyi bir uygulama yazmak kolay ve rahattır.

In Top 25 En Tehlikeli Programlama Hataları "Yanlış Girdi Doğrulama" bölümünde "Bileşenler Arasında güvensiz Etkileşim" en tehlikeli hatadır.

Yöntemlerin başına önkoşul önerileri eklemek , parametrelerin tutarlı olduğundan emin olmak için iyi bir yoldur. Yöntemlerin sonunda yazıyorum Hedefşartlar o çıktı olmak inteded ne olduğunu kontrol edin.

Değişmezleri uygulamak için , herhangi bir sınıfa "sınıf tutarlılığını" kontrol eden, önkoşul ve sonkoşul makrosu tarafından otomatik olarak çağrılması gereken bir yöntem yazıyorum.

Kod Sözleşme Kütüphanesini değerlendiriyorum .


6

Java

Java api'nin değişmez nesneler kavramı yoktur, bu kötüdür! Final bu durumda size yardımcı olabilir. Final ile değiştirilemeyen her sınıfı etiketleyin ve sınıfı buna göre hazırlayın .

Bazen değerlerini asla değiştirmediklerinden emin olmak için yerel değişkenlerde final kullanmak yararlı olabilir. Bunu çirkin ama gerekli döngü yapılarında yararlı buldum. Bir değişkeni düzeltmek olsa bile, bir değişkeni yanlışlıkla tekrar kullanmak kolaydır.

Alıcılarınızda savunma kopyasını kullanın . İlkel bir türü veya değiştirilemez bir nesneyi döndürmediğiniz sürece, nesneyi kapsüllemeyi ihlal etmeyecek şekilde kopyaladığınızdan emin olun.

Asla klon kullanmayın, bir kopya oluşturucu kullanın .

Eşittir ve hashCode arasındaki sözleşmeyi öğrenin. Bu çok sık ihlal ediliyor. Sorun, vakaların% 99'unda kodunuzu etkilememesidir. İnsanlar eşittir, ancak hashCode umrunda değil. Kodunuzun kırılabileceği veya garip davranabileceği durumlar vardır, örn. Haritadaki anahtar olarak değiştirilebilir nesneler kullanın.


5

Ben echoPHP bir çok kez yazmayı unuttum :

<td><?php $foo->bar->baz(); ?></td>
<!-- should have been -->
<td><?php echo $foo->bar->baz(); ?></td>

Denemek ve neden -> baz () aslında sadece yankılama değildi bir şey döndürmüyordu anlamaya sonsuza kadar sürer! : -S Yani EchoMeyankılanması gereken herhangi bir değerin etrafına sarılabilecek bir sınıf yaptım :

<?php
class EchoMe {
  private $str;
  private $printed = false;
  function __construct($value) {
    $this->str = strval($value);
  }
  function __toString() {
    $this->printed = true;
    return $this->str;
  }
  function __destruct() {
    if($this->printed !== true)
      throw new Exception("String '$this->str' was never printed");
  }
}

Ve sonra geliştirme ortamı için, yazdırılması gereken şeyleri sarmak için bir EchoMe kullandım:

function baz() {
  $value = [...calculations...]
  if(DEBUG)
    return EchoMe($value);
  return $value;
}

Bu tekniği kullanarak, eksik olan ilk örnek echoşimdi bir istisna atar ...


Yıkıcı $ this-> print! == true için kontrol etmemeli mi?
Karsten

Bir şablon sistemi kullanmayı düşünmelisiniz, php'yi html'ye gömmek neredeyse tüm sistemlerde alt optimaldir.
Cruachan

Belki bir şey eksik? Ama bana öyle geliyor ki kodlama için telafi etmeye çalışıyor: AnObject.ToStringyerine Writeln(AnObject.ToString)?
hayal kırıklığına uğradı

Evet, ancak PHP'de hata yapmak çok daha kolay
çok fazla php

4

C ++

Yeni yazdığımda, hemen delete yazmalıyım. Özellikle diziler için.

C #

Özelliklere erişmeden önce, özellikle de Meditor desenini kullanırken null olup olmadığını kontrol edin. Nesneler iletilir (ve daha önce belirtildiği gibi kullanılarak kullanılmalıdır) ve sonra null'a karşı kontrol edin. Boş olmayacağını düşünseniz bile yine de kontrol edin. Şaşırdım.


İlk noktanı seviyorum. Örneğin, bir şeyler koleksiyonu döndüren bir yöntem yazarken benzer şeyler yaparım. Koleksiyonu ilk satırda oluşturuyorum ve hemen return ifadesini yazıyorum. Geriye kalan tek şey koleksiyonun nasıl doldurulduğunu doldurmak.
Yasadışı Programcı

5
C ++ 'da, yeni yazdığınızda, bu işaretçiyi hemen bir AutoPtr veya başvuru sayılan kapsayıcıya atamalısınız. C ++, yıkıcılara ve şablonlara sahiptir; silme işlemini otomatik olarak yapmak için bunları akıllıca kullanın.
An̲̳̳drew

4

Dinamik, çalışma süresi günlük düzeyi ayarlarına izin veren bir günlük sistemi kullanın. Genellikle günlüğe kaydetmeyi etkinleştirmek için bir programı durdurmanız gerekiyorsa, hatanın meydana geldiği nadir durumları kaybedersiniz. İşlemi durdurmadan daha fazla günlük bilgisi açabilmeniz gerekir.

Ayrıca, linux üzerindeki 'strace -p [pid]', sistem çağrılarının bir işlem (veya linux iş parçacığı) yapmasını istediğinizi gösterecektir. İlk başta garip görünebilir, ancak genellikle sistem çağrılarının hangi libc çağrıları tarafından yapıldığına alıştıktan sonra, alan teşhisinde bunun için çok değerli olduğunu göreceksiniz.

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.