Asla kamuya açıklanmayacak kod için savunma programlama uygulamalarını takip etmek ne kadar gerekli?


45

Bir kart oyununun Java uygulamasını yazıyorum, bu yüzden bir Bölge dediğim özel bir Koleksiyon türü oluşturdum. Java'nın Koleksiyonundaki tüm modifikasyon yöntemleri desteklenmemektedir, ancak Zone API'de move(Zone, Card)bir Kartı belirli bir Bölgeden kendisine taşıyan (özel paket teknikleriyle gerçekleştirilen) bir yöntem vardır. Bu şekilde, hiçbir bölgeden kart çıkartılmadığından emin olabilirim; sadece başka bir bölgeye taşınabilirler.

Sorum şu, bu tür bir savunma kodlaması ne kadar gerekli? Bu "doğru" ve doğru uygulama gibi hissediyor, ancak Zone API'nin bazı halk kütüphanelerinin bir parçası olacağı gibi değil. Bu sadece benim için, sanırım sadece standart Koleksiyonlar kullanarak daha verimli olabileceğimde kodumu kendimden koruyor gibiyim.

Bu Bölge fikrini ne kadar ileri götürmeliyim? Birileri bana, özellikle halka açık olmayacak olanlar için yazdığım sınıflardaki sözleşmeleri korumayla ilgili ne kadar düşünmem gerektiğini önerebilir mi?


4
= ~ s / gerekli / önerilen / gi
GrandmasterB

2
Veri tipleri, inşaat gereği doğru olmalı, yoksa başka ne üzerine inşa ediyorsunuz? Değişken olsun ya da olmasın, yalnızca geçerli durumlarda olabilecekleri şekilde kapsüllenmelidirler. Sadece bunu statik olarak uygulamak imkansızsa (veya makul olmayan bir şekilde zor) çalışma zamanı hatası vermelisiniz.
Jon Purdy

1
Asla asla Deme. Kodunuz asla kullanılmadıkça, kodunuzun nerede biteceğini kesin olarak bilemezsiniz. ;)
Izkata

1
@codebreaker GrandmasterB'nin yorumu, ifadenin yerini aldı. Bunun anlamı: "gerekli" yi "önerilen" ile değiştirin.
Ricardo Souza,

1
Kodsuz Kod # 116 Güven Kimse burada özellikle uygun olabilir.

Yanıtlar:


72

Tasarım sorununu ele almayacağım - sadece halka açık olmayan bir API'de "doğru" işlem yapıp yapmama sorusu.

bu sadece benim için, sanki kendi kodumu kendimden koruyor gibiyim

Bu tam olarak nokta. Belki de orada her sınıfın nüanslarını ve yazdıkları metodu hatırlayan ve yanlış bir anlaşmayla asla yanlışlıkla çağrılmayan kodlayıcılar vardır. Ben onlardan biri değilim. Yazdığım kodun yazdıktan sonra saatler içinde nasıl çalışması gerektiğini sık sık unutuyorum. Eğer doğru bir kez olduğu düşünülünce sonra, zihniniz üzerinde çalıştığınız probleme vites geçiş eğiliminde olacaktır şimdi .

Bununla savaşmak için araçların var. Bu araçlar (belirli bir sıra ile değil) sözleşmeleri, birim testlerini ve diğer otomatik testleri, önkoşul kontrolünü ve belgeleri içerir. Ben, birim testlerinin paha biçilmez olduğunu buldum çünkü hem sözleşmenizin nasıl kullanılacağı hakkında düşünmeye zorlarlar hem de arayüzün nasıl tasarlandığı konusunda belgeler sunarlar.


Bilmek güzel. Eskiden mümkün olduğu kadar verimli bir şekilde programlanırdım, bu yüzden bazen böyle fikirlere alışmak için zor zamanlar geçiririm. Doğru yöne gittiğim için memnunum.
kod kırıcı

15
"Verimli" birçok farklı anlama gelebilir! Tecrübelerime göre, acemiler (bir tane olduğumu söylemiyorum) genellikle programı ne kadar verimli destekleyebileceklerini görmezden geliyorlar. Kod, ürün yaşam döngüsünün destek aşamasında genellikle "yeni kod yazma" aşamasında olduğundan daha uzun zaman harcıyor, bu yüzden dikkatlice değerlendirilmesi gereken bir verimlilik olduğunu düşünüyorum.
Charlie Kilian

2
Kesinlikle katılıyorum. Üniversiteye döndüğümde, bunun hakkında hiçbir zaman düşünmedim.
kod kırıcı,

25

Genelde bazı basit kuralları izlerim:

  • Her zaman sözleşmeyle programlamaya çalışın .
  • Bir yöntem kamuya açıksa veya dış dünyadan girdi alıyorsa, bazı savunma önlemlerini alın (örn. IllegalArgumentException).
  • Sadece içeriden erişilebilir olan her şey için, iddiaları kullanın (örn. assert input != null).

Eğer bir müşteri gerçekten onun içine girerse, kodunuzu yanlış yapmak için her zaman bir yol bulur. En azından yansıma yoluyla bunu her zaman yapabilirler. Ancak bu sözleşme ile tasarımın güzelliği . Kodunuzun bu şekilde kullanılmasını onaylamazsınız ve bu nedenle bu gibi senaryolarda çalışacağını garanti edemezsiniz.

Özel durumunuza göre, Zoneyabancılar tarafından kullanılmaması ve / veya erişilmemesi gerekiyorsa, ya sınıf paketini özel (veya muhtemelen final) özel yapın veya tercihen Java'nın size sağladığı koleksiyonları kullanın. Test edildiler ve tekerleği yeniden icat etmeniz gerekmiyor. Bunun, her şeyin beklendiği gibi çalıştığından emin olmak için kodunuz boyunca iddialar kullanmanızı engellemediğine dikkat edin.


1
Sözleşme ile Tasarım'dan bahsetmek için +1. Davranışı tamamen yasaklayamıyorsanız (ve yapılması zor), en azından kötü davranış konusunda hiçbir garanti olmadığını açıkça belirtirsiniz. Ayrıca bir IllegalStateException veya UnsupportedOperationException atmayı da seviyorum.
user949300

@ user949300 Elbette. Bu istisnaların anlamlı bir amaç için yapıldığına inanmayı seviyorum. Sözleşmelerin onurlandırılması bu role uygun gibi görünüyor.
afsantos

16

Savunma programlaması çok iyi bir şey.
Kod yazma yoluna girinceye kadar. O zaman bu iyi bir şey değil.


Pragmatik olarak biraz daha konuşmak ...

İşleri çok uzağa götürmenin tam yanında gibisin. Zorluk (ve sorunuzun cevabı) programın iş kurallarının veya gereksinimlerinin ne olduğunu anlamada yatmaktadır.

Kart oyunu API'nizi bir örnek olarak kullanarak, hile yapmayı önlemek için yapılabilecek her şeyin kritik olduğu bazı ortamlar vardır. Büyük miktarlarda gerçek para söz konusu olabilir, bu nedenle aldatmanın gerçekleşmeyeceğinden emin olmak için çok sayıda kontrol yapılması önemlidir.

Öte yandan, SOLID ilkelerine, özellikle de tek sorumluluğa dikkat edin. Konteyner sınıfından kartların nereye gittiğini etkin bir şekilde denetlemesini istemek biraz fazla olabilir. Kart kabı ile taşıma taleplerini alan fonksiyon arasında bir denetim / denetleyici katmanının olması daha iyi olabilir.


Bu kaygılarla ilgili olarak, API’nizin hangi bileşenlerinin kamuya açık (ve dolayısıyla savunmasız) olduğunu, neyin özel ve daha az maruz kaldığını anlamanız gerekir. "Yumuşak iç kısmı olan sert dış kaplama" nın savunucusuyum ama çabanızın en iyi geri dönüşü API'nizin dışını sertleştirmek.

Bir kütüphanenin amaçlanan son kullanıcısı, ne kadar savunma amaçlı programlama yaptığınıza karar vermenin kritik olduğunu düşünmüyorum. Kendi kullanımım için yazdığım modüller ile bile, geleceğin kütüphaneyi çağırırken yanlışlıkla yanlış bir hata yapmadığından emin olmak için bir önlem alıyorum.


2
+1, "Kod yazmaya başlamadan önce" Özellikle kısa vadeli kişisel projeler için, savunmacı bir şekilde kodlama yapmak değerinden çok daha fazla zaman alabilir.
Corey

2
Kabul ediyorum, savunmak / savunmak / programlamak için iyi bir şey olduğunu belirtmek isterim, fakat aynı zamanda prototip bir şekilde programlayabilmek de çok önemlidir. Her ikisini de yapabilme yeteneği, savunmayı yalnızca kimin programlayabileceğini (çeşitleyebileceğini) bildiğim birçok programcının çok daha iyi olan en uygun eylemini seçmenize izin verecektir.
David Mulder

13

Savunma kodlaması sadece genel kod için iyi bir fikir değildir. Bu bir var harika hemen atılır verilmeyen herhangi kodu için fikir. Tabii, şimdi nasıl aranması gerektiğini biliyorsunuz , ancak bundan altı ay sonra projeye geri döndüğünüzde ne kadar iyi hatırlayacağınız konusunda hiçbir fikriniz yok.

Java'nın temel sözdizimi, sırasıyla C veya Javascript gibi daha düşük bir seviye ya da yorumlanmış bir dil ile karşılaştırıldığında size çok fazla pişmiş savunma sağlar. Yöntemlerinizi açık bir şekilde adlandırdığınızı ve harici "yöntem sıralamanız" olmadığını varsayarak, doğru şekilde yazılan veriler hala geçersizse, argümanları doğru bir veri türü olarak tanımlayarak ve mantıklı bir davranış dahil ederek muhtemelen uzaklaşabilirsiniz.

(Bir kenara, eğer Kartlar her zaman bölgenin bölgesinde olmak zorundaysa, tüm kartların oyunda Oyun nesnesine global bir koleksiyon tarafından yönlendirilmesini sağlayarak daha iyi kazanabileceğini düşünüyorum. Her kart. Ancak Bölgelerinizin kart tutmaktan başka ne yaptığını bilmediğimden, bunun uygun olup olmadığını bilmek zor.)


1
Bölgenin kartın bir özelliği olduğunu düşündüm, ancak Kartlarım değiştirilemez nesneler olarak daha iyi çalıştığından, bu yolun en iyisi olduğuna karar verdim. Tavsiye için teşekkürler.
codebreaker

3
@codebreaker bu durumda yardımcı olabilecek bir şey, kartı başka bir nesneye yerleştirmektir. Maça Ası budur. Konum kimliğini tanımlamıyor ve bir kart muhtemelen değiştirilemez olmalı. Belki bir Zone kart içerir: belki de CardDescriptorkart içeren bir kart, yeri, yüzü yukarı / aşağı durumu ve hatta bunu önemseyen oyunlar için rotasyon. Bunların hepsi bir kartın kimliğini değiştirmeyen değiştirilebilir özelliklerdir.

1

Önce bir Bölge listesi tutan bir Bölge oluşturun, böylece bir Bölge veya içindeki kartları kaybetmezsiniz. Daha sonra bir transferin ZoneList'inizde olup olmadığını kontrol edebilirsiniz. Bu sınıf muhtemelen bir tür singleton olacaktır, çünkü yalnızca bir örneğe ihtiyacınız olacak, ancak daha sonra Bölge grupları isteyebilirsiniz, bu nedenle seçeneklerinizi açık tutun.

İkincisi, Zone veya ZoneList'in Koleksiyon veya uygulama yapmasını istemiyorsanız başka herhangi bir şey yapmayın. Bir Bölge veya ZoneList Bir Koleksiyon beklediği şey geçilecek olursa belirtecektim, sonra onu yerine getirirler. Bir istisna (UnimplementedException veya buna benzer bir şey) atmalarını veya basitçe hiçbir şey yapmalarını isteyerek bir dizi yöntemi devre dışı bırakabilirsiniz. (İkinci seçeneği kullanmadan önce çok düşünün. Bunu yaparsanız kolay olduğu için erken yakalamış olabileceğiniz hataları kaçırdığınızı görürsünüz.)

Neyin "doğru" olduğuna dair gerçek sorular var. Ama bir kere ne olduğunu anlayınca, bu şekilde yapmak isteyeceksiniz. İki yıl içinde tüm bunları unutmuş olacaksınız ve eğer kodu kullanmaya çalışırsanız, o zaman bu tür bir karşı-yönden yazan ve hiçbir şey açıklamayan adama gerçekten sinirleneceksiniz.


2
Cevabınız, OP'nin genel olarak savunma programlaması hakkında sorduğu daha geniş sorular yerine eldeki probleme biraz odaklanıyor.

Bölgeleri Koleksiyonlar alan yöntemlere aktarıyorum, bu yüzden uygulama gerekli. Oysa, oyun içindeki bölgelerin bir nevi kayıt defteri ilginç bir fikir.
kod kırıcı,

@ GlenH7: Belirli örneklerle çalışmanın çoğu zaman soyut teoriden daha çok yardımcı olduğunu düşünüyorum. OP oldukça ilginç bir tane sağladı, ben de bununla gittim.
RalphChapin

1

API tasarımında savunma kodlaması genellikle girdiyi doğrulamak ve dikkatlice uygun bir hata işleme mekanizması seçmekle ilgilidir. Diğer cevapların bahsettiği şeyler de dikkate değer.

Bu aslında örneğinizin konusu değil. Çok özel bir nedenden dolayı API yüzeyinizi sınırlıyorsunuz. As GlenH7 bahseder, ne zaman kartların kümesi örneğin bir ( 'kullanılmış' ve 'kullanılmayan') güverte, bir masa ve ellerle, gerçek bir oyunda kullanılmak üzere, kesinlikle emin her olmak için yerinde kontrolleri koymak istiyorum setteki kart bir kez ve sadece bir kez bulunur.

Bunu "bölgeler" ile tasarladığınız, keyfi bir seçimdir. Uygulamaya bağlı olarak (bir bölge yalnızca bir el, bir güverte veya yukarıdaki örnekte bir masa olabilir) çok iyi bir tasarım olabilir.

Bununla birlikte, bu uygulama Collection<Card>daha az kısıtlayıcı bir API ile türetilmiş, daha çok benzer bir kart grubuna benzer. Örneğin, bir el değeri hesap makinesi veya bir AI oluşturmak istediğinizde, hangi kartların kaç tanesini alacağınızı seçmekte kesinlikle özgürsünüz.

Bu yüzden, söz konusu kısıtlayıcı bir API'yi ifşa etmek iyidir, eğer o API'nin tek amacı her bir kartın daima bir bölgede olduğundan emin olmaktır.

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.