Neden kod sözleşmelerini kullanmalıyım?


26

Geçenlerde Microsoft'un kod sözleşmeleri çerçevesine rastladım.

Belgeleri biraz okudum ve sürekli şunu sorarak buldum: “Statik bir analiz yapıp yapamadığı ve sık sık yapamadığı için neden bunu yapmak isteyeyim?”.

Şimdi, zaten bunun gibi istisnalar dışında bir çeşit savunma programlama tarzım var:

if(var == null) { throw new NullArgumentException(); }

Ayrıca NullObject Pattern'i çok kullanıyorum ve nadiren sorun yaşıyorum. Buna Birim Testleri ekleyin ve hepiniz hazırsınız.

Asla iddiaları kullanmadım ve onları hiç özlemedim. Tam tersine. İçinde bir sürü anlamsız iddia içeren koddan nefret ediyorum, bu sadece benim için gürültü yapıyor ve beni gerçekten görmek istediklerimden uzaklaştırıyor. Kod sözleşmeleri, en azından Microsoft yöntemi aynıdır - ve daha da kötüsü. Koda çok fazla gürültü ve karmaşıklık eklerler. % 99'da yine de bir istisna atılacak - bu yüzden iddiadan / sözleşmeden mi, yoksa gerçek sorundan mı umrumda değil. Çok çok, program durumlarının gerçekten bozulduğu durumlar çok az.

Açıkçası, kod sözleşmelerini kullanmanın faydası nedir? Hiç var mı? Zaten birim testleri ve kodları kullanıyorsanız, sözleşmeleri uygulamaya koymanın sadece maliyete değmeyeceğini ve kodun ne yaptığını göremediğimde yaptığım gibi, bu yöntemi güncellerken bir koruyucunun lanet edeceği paraziti ortaya koyduğunu düşünüyorum yararsız iddialar yüzünden. Bu bedeli ödemek için henüz iyi bir neden görmedim.



1
Neden “statik bir analiz yapmıyor ve sık sık yapamıyor” diyorsunuz? Bunun, projenin en önemli noktalarından biri olduğunu düşündüm (sadece Varlıklar veya savunma istisna atışı kullanmak yerine)?
Carson63000

@ Carson63000 Belgeleri dikkatlice okuyun; statik denetleyicinin yalnızca çok sayıda ve çok sayıda uyarıda bulunacağını göreceksiniz, çoğu gereksiz (geliştiriciler böyle olduğunu kabul ediyor) ve çoğu tanımlanmış sözleşmenin sadece bir istisna atacağını ve bunun dışında hiçbir şey yapmayacağını .
Falcon

@ Yonca: garip, benim deneyimim tamamen farklı. Statik analiz kusursuz değil, fakat oldukça iyi çalışıyor ve 4. seviye (en yüksek) uyarı seviyelerinde çalışırken bile nadiren gereksiz uyarılar görüyorum.
Arseni Mourzenko 13:13

Sanırım nasıl davrandığını bulmak için denemek zorunda kalacağım.
Falcon

Yanıtlar:


42

Statik yazmanın dinamik yazmadan daha iyi olduğunu sormuş olabilirsiniz. Yıllarca süren, tartışmasız bir tartışma. Dinamik ve Statik olarak yazılmış dil çalışmaları gibi sorulara bir göz atın

Ancak, temel argüman, derleme zamanında, aksi takdirde üretime girebilecek sorunları bulma ve çözme potansiyeli olacaktır.

Sözleşmelere Karşı Koruma

Gardiyanlar ve istisnalar olsa bile, sistemin bazı durumlarda amaçladığı görevi yerine getirememesi sorunu ile karşı karşıya kalırsınız. Muhtemelen oldukça kritik ve başarısız olması gereken maliyetli bir örnek.

Sözleşmeler vs. Birim testleri

Bu konudaki olağan argüman, testlerin hataların varlığını kanıtladığı, tiplerin (sözleşmelerin) yokluğunu kanıtladığıdır. F.ex. Bir tür kullanarak, programdaki hiçbir yolun muhtemelen geçersiz girdi sağlayamayacağını, bir test ise yalnızca kapsanan yolun doğru girişi sağladığını söyleyebilir.

Sözleşmeler vs. Null Nesne kalıbı

Şimdi bu en azından aynı top parkında. Scala ve Haskell gibi diller, boş referansları tamamen programlardan kaldırmaya yönelik bu yaklaşımla büyük başarı elde etti. (Scala resmen null değerine izin verse bile, sözleşme onları asla kullanmamaktır)

NRE'leri ortadan kaldırmak için bu modeli zaten kullanıyorsanız, temelde en büyük çalışma zamanı hatası kaynağını kaldırdınız, sözleşmelerin bunu yapmanıza izin verdiği şekilde temelde var.

Aradaki fark, sözleşmelerin boş bırakmamak için tüm kodunuzu otomatik olarak isteme seçeneğine sahip olması ve bu deseni derlemeyi geçmek için daha fazla yerde kullanmaya zorlaması olabilir.

Buna ek olarak, sözleşmeler ayrıca null dışındaki şeyleri hedef alma esnekliği sunar. Dolayısıyla, artık hatalarınızda herhangi bir NRE görmüyorsanız, sahip olabileceğiniz en yaygın sorunu boğmak için sözleşmeleri kullanmak isteyebilirsiniz. Teker teker mi? Dizin aralık dışında mı?

Fakat...

Bütün bunlar söyleniyor. Kurallara eklenen sözdizimsel gürültü (ve hatta yapısal gürültü) sözleşmelerinin oldukça önemli olduğu ve analizin yapım süreniz üzerindeki etkisinin hafife alınmaması gerektiğine katılıyorum. Bu nedenle, sisteminize sözleşmeler eklemeye karar verirseniz, muhtemelen hangi böcek sınıfını ele almaya çalıştığımıza odaklanarak çok dikkatli bir şekilde yapmak akıllıca olacaktır.


6
Programcılar için ilk büyük cevap. Topluluğa katılmana sevindim.

13

"Statik bir analiz yapıp yapamadığı ve sık sık yapamayacağı" iddiasının nereden geldiğini bilmiyorum. İddianın ilk kısmı açıkça yanlıştır. İkincisi, "sık sık" ne demek istediğine bağlı. Sık sık statik analizler yaptığını ve nadiren de başarısız olduğunu söylerdim . Sıradan iş uygulamalarında, nadiren hiç olmadığı kadar yaklaşır .

Yani burada geliyor, ilk yararı:

Fayda 1: statik analiz

Sıradan iddiaların ve argüman kontrolünün bir dezavantajı vardır: kod çalıştırılana kadar ertelenirler. Diğer taraftan, kod sözleşmeleri, kodlama aşamasında ya da başvuruyu derlerken kendilerini çok daha erken bir düzeyde ortaya koymaktadır. Bir hatayı ne kadar erken yakalarsanız, düzeltmesi o kadar az masraflıdır.

Fayda 2: Her zaman güncel belgeler

Kod sözleşmeleri ayrıca her zaman güncel olan bir tür belge sunar . Yöntemin XML yorumu, bunun üstün veya sıfıra eşit olması gerektiğini SetProductPrice(int newPrice)söylerse newPrice, belgelerin güncel olduğunu umabilirsiniz, ancak birinin yöntemi newPrice = 0atması için ArgumentOutOfRangeExceptiondeğiştirdiğini ancak karşılık gelen belgelerin değişmediğini keşfedebilirsiniz . Kod sözleşmeleri ile kodun kendisi arasındaki korelasyon göz önüne alındığında, senkronizasyon dışı dokümantasyon probleminiz yoktur.

Kod sözleşmelerinin sağladığı dokümantasyon türleri, XML yorumlarının kabul edilebilir değerleri iyi açıklamadığı bir şekilde de değerlidir. Kaç kere merak eğer oldu nullya string.Emptyya \r\nbir yöntem için yetkili bir değerdir ve XML yorumlarının bu konuda sessiz oldu!

Sonuç olarak, kod sözleşmeleri olmadan, birçok kod parçası şöyledir:

Bazı değerleri kabul ediyorum, ancak diğerlerini kabul edemem, ancak varsa belgeleri tahmin etmek veya okumak zorunda kalırsınız. Aslında, belgeleri okumayın: güncel değil. Basitçe tüm değerler arasında dolaşın ve beni istisnalar attıranları göreceksiniz. Ayrıca geri getirilebilecek değerler aralığını da tahmin etmelisiniz, çünkü onlar hakkında size biraz daha fazla şey söylesem bile, son yıllarda bana yapılan yüzlerce değişiklik göz önüne alındığında bu doğru olmayabilir.

Kod sözleşmeleri ile, olur:

Başlık argümanı, uzunluğu 0..500 olan boş olmayan bir dize olabilir. İzleyen tamsayı, yalnızca dize boş olduğunda sıfır olabilen pozitif bir değerdir. Sonunda, bir IDefinitionnesneyi geri döndüreceğim , asla boş.

Fayda 3: Arayüz sözleşmeleri

Üçüncü bir fayda, kod sözleşmelerinin arayüzleri güçlendirmesidir. Diyelim ki şöyle bir şeyiniz var:

public interface ICommittable
{
    public ICollection<AtomicChange> PendingChanges { get; }

    public void CommitChanges();

    ...
}

Yalnızca varsayım ve istisnalar kullanarak, yalnızca boş olmadığı CommitChangeszaman aranabilecek garantiyi nasıl elde edersiniz PendingChanges? Bunun PendingChangesasla olmadığını nasıl garanti edersin null?

Fayda 4: Bir yöntemin sonuçlarını uygulamak

Son olarak, dördüncü fayda Contract.Ensuresonuçlara ulaşabilmektir. Bir tamsayı döndüren bir yöntem yazarken, değerin hiçbir zaman aşağı veya sıfıra eşit olmadığından emin olmak istersem? Beş yıl sonra, birçok geliştiriciden gelen çok fazla değişiklikten sonra? Bir yöntem birden fazla geri dönüş noktasına sahip Assertolur olmaz, bunun için bir bakım kabusu olur.


Kod sözleşmelerini yalnızca kodunuzun doğruluğu anlamına gelmez, aynı zamanda kod yazmanın daha katı bir yolu olarak düşünün. Benzer şekilde, yalnızca dinamik dilleri kullanan bir kişi neden dil düzeyinde türler uyguladığınızı sorabilirken, gerektiğinde iddialarda aynı şeyi yapabilirsiniz. Yapabilirsiniz, ancak statik yazmanın kullanımı daha kolaydır, birçok iddiaya kıyasla daha az hataya eğilimlidir ve kendi kendini belgelemektedir.

Dinamik yazma ve statik yazma arasındaki fark, normal programlama ve sözleşmeyle programlama arasındaki farka son derece yakındır.


3

Bunun soruya biraz geç kaldığını biliyorum, ancak söz konusu olan Sözleşmelerin bir başka faydası var.

Sözleşmeler yöntem dışında kontrol edilir

Metodumuzda koruma koşullarına sahip olduğumuzda, kontrolün gerçekleştiği ve hataların bildirildiği yer burasıdır. Ardından hatanın asıl kaynağının nerede olduğunu bulmak için yığın izlemesini araştırmamız gerekebilir.

Kod sözleşmeleri yöntem içinde bulunur, ancak bir şey bu yöntemi çağırmaya çalıştığında, ön koşullar yöntemin dışında denetlenir. Sözleşmeler yöntemin bir parçası haline gelir ve aranıp aranmayacağını belirler. Bu, sorunun asıl kaynağına daha yakın bir rapor aldığımız anlamına gelir.

Pek çok yer için çağrılan bir sözleşmeyle korunan yönteminiz varsa, bu gerçek bir avantaj olabilir.


2

Gerçekten iki şey:

  1. Takım desteği, VS kontrat verilerini istihbarat dışında yapabilir, böylece otomatik tamamlama yardımının bir parçasıdır.
  2. Bir alt sınıf bir yöntemi geçersiz kıldığında, tüm çeklerinizi kaybedersiniz (ki bu LSP'yi izlerseniz hala geçerli olmalıdır) sözleşmelerle alt sınıflarını otomatik olarak takip ederler.
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.