Bir yöntem, iletilen argümanlarla bağışlayıcı olmalı mı? [kapalı]


21

Diyelim foo(String bar)ki sadece belirli kriterleri karşılayan tellerde çalışan bir yöntemimiz var; örneğin, küçük harflerle yazılmalı, boş olmamalı veya yalnızca beyaz alana sahip olmalı ve desenle eşleşmelidir [a-z0-9-_./@]+. Yöntemin dokümantasyonu bu kriterleri belirtir.

Yöntem, bu kriterlerden sapmaların tümünü ve hepsini reddetmeli mi, yoksa yöntem bazı kriterler için daha bağışlayıcı olmalı? Örneğin, eğer ilk yöntem

public void foo(String bar) {
    if (bar == null) {
        throw new IllegalArgumentException("bar must not be null");
    }
    if (!bar.matches(BAR_PATTERN_STRING)) {
        throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
    }
    this.bar = bar;
}

Ve ikinci bağışlama yöntemi

public void foo(String bar) {
    if (bar == null) {
        throw new IllegalArgumentException("bar must not be null");
    }
    if (!bar.matches(BAR_PATTERN_STRING)) {
        bar = bar.toLowerCase().trim().replaceAll(" ", "_");
        if (!bar.matches(BAR_PATTERN_STRING) {
            throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
        }
    }
    this.bar = bar;
}

Dokümantasyon, dönüştürüleceğini ve mümkünse dönüştürülen değere ayarlanacağını belirtmeli mi, yoksa yöntem mümkün olduğunca basit tutulmalı mı ve tüm sapmaları reddetmeli mi? Bu durumda, barbir uygulamanın kullanıcısı tarafından ayarlanabilir.

Bunun birincil kullanım durumu, depodaki nesnelere belirli bir dize tanımlayıcısı ile erişen kullanıcılar olacaktır. Depodaki her nesne, onu tanımlamak için benzersiz bir dizeye sahip olmalıdır. Bu depolar, nesneleri çeşitli şekillerde (sql sunucusu, json, xml, binary, vb.) Saklayabilir ve çoğu adlandırma kurallarına uyan en düşük ortak paydayı belirlemeye çalıştım.


1
Bu muhtemelen kullanım durumunuza büyük ölçüde bağlıdır. Her ikisi de makul olabilir ve her iki yöntemi de sağlayan ve kullanıcının karar vermesini sağlayan sınıflar bile gördüm. Bu yöntem / sınıf / alanın ne yapması gerektiğine dikkat eder misiniz, böylece gerçek bir tavsiyede bulunabiliriz?
Ixrec

1
Yöntemi çağıran herkesi tanıyor musunuz? Olduğu gibi, değiştirirseniz, tüm müşterileri güvenilir bir şekilde tanımlayabilir misiniz? Öyleyse, performans endişelerinin izin verdiği ölçüde izin verici ve bağışlayıcı olarak giderdim. Belgeleri de silebilirim. Olmazsa ve bir kütüphane API'sinin parçasıysa, kodun tam olarak reklamı yapılan API'yi uyguladığından emin olurum, aksi halde kodu gelecekteki belgelerle eşleştirmek için değiştirerek hata raporları oluşturmaya uygundur.
Jon Chesterfield

7
Endişelerin Ayrılmasının, eğer gerekliyse, foohangi argümanları kabul ettiği konusunda katı olan katı bir işleve sahip olmanız gerektiğini ve kullanılabilecek bir argümanı "temizlemeye" çalışabilecek ikinci bir yardımcı işleve sahip olmanız gerektiğini söyleyebilirsiniz foo. Bu şekilde, her yöntemin kendi başına yapması gereken daha az şey vardır ve daha temiz bir şekilde yönetilebilir ve entegre edilebilirler. Bu rotadan aşağı inerseniz, istisnai ağır bir tasarımdan uzaklaşmak da muhtemelen yardımcı olacaktır; gibi bir şey kullanabilirsiniz Optionalyerine ve sonra tüketmek fonksiyonlara sahip foogerekirse atış istisnalar.
gntskn,

1
Bu, "birileri beni haksızlaştırdı, onları affetmeli miyim?" Diye sormak gibidir. Açıkçası, birinin ya da diğerinin uygun olduğu durumlar var . Programlama insan ilişkileri kadar karmaşık olmayabilir, ancak bunun gibi bir battaniye reçetesinin işe yaramayacağı kesinlikle karmaşıktır.
Kilian Foth,

2
@Boggin Sizi Yeniden İncelenen Sağlamlık Prensibi'ne de işaret ederim . Zorluk, uygulamayı genişletmeniz gerektiğinde ortaya çıkar ve bağışlayıcı uygulama, genişletilmiş uygulama ile belirsiz bir duruma yol açar.

Yanıtlar:


47

Yönteminiz ne diyorsa onu yapmalı.

Bu, böceklerin hem kullanımını hem de koruyucuları daha sonra davranışları değiştirmesini önler. Zaman kazandırır çünkü bakıcıların neler olup bittiğini anlamak için çok zaman harcamasına gerek kalmaz.

Bu, eğer tanımlanan mantık kullanıcı dostu değilse, belki de iyileştirilmesi gerektiğini söyledi.


8
Anahtar bu. Eğer yönteminiz tam olarak ne diyorsa onu yaparsa, yönteminizi kullanan kodlayıcı kendi özel durumlarını telafi edecektir. Hiç faydalı olmadığını düşündüğünüzden, yöntemle belgelenmemiş bir şey yapmayın. Değiştirmeniz gerekirse, bir kap yazın veya belgeleri değiştirin.
Nelson,

@ Nelson'ın yorumuna, yöntemin bir vakumda tasarlanmaması gerektiğini eklerdim. Kodlayıcılar kullanacaklarını ancak telafi edeceklerini ve tazminatlarının genel amaçlı değere sahip olduğunu söylerse, bunları sınıfın bir parçası yapmayı düşünün. (Örneğin, ikincisinin foofooForUncleanString
öncekine

20

Birkaç nokta var:

  1. Uygulamanız belgelenen sözleşmenin gerektirdiği şeyi yapmalı ve daha fazlasını yapmamalıdır.
  2. Sadelik, hem sözleşme hem de uygulama için, eskisi için daha fazla olsa da önemlidir.
  3. Hatalı girdiyi düzeltmeye çalışmak, yalnızca sözleşme ve uygulama için değil kullanım için de sezgisel olarak sezgisel olarak karmaşıklık ekler.
  4. Hatalar ancak bu hata ayıklanabilirliği artırır ve verimliliği çok fazla ödün vermezse erken yakalanmalıdır.
    Unutmayın ki, hata ayıklama modundaki mantık hatalarını tanılamada hata ayıklama iddiaları vardır, bu da çoğunlukla performans kaygılarını azaltır.
  5. Verimlilik, mevcut zaman ve paranın basitliği çok fazla ödün vermeksizin izin verdiği ölçüde, daima bir amaçtır.

Bir kullanıcı arayüzü uygularsanız, arkadaşça hata mesajları (öneriler ve diğer yardımlar dahil) iyi tasarımın bir parçasıdır.
Ancak API'lerin son kullanıcılar için değil programcılar için olduğunu unutmayın.


Girdide bulanık ve izinli olmanın gerçek yaşam deneyi HTML'dir.
Bu, herkesin onu biraz farklı yapmasıyla sonuçlandı ve bu özelliğin belgelenmesiyle özel vakalarla dolu bir mamut olduğu ortaya çıktı. Postel yasasına
bakınız (" Yaptığınız işte muhafazakar olun, başkalarından kabul ettiğiniz şeylerde liberal olun. ") Ve buna değinen bir eleştirmen ( ya da MichaelT'nin beni daha iyi tanıdığı biri ).


Sendmail yazarı tarafından yazılan bir diğer kritik eser: The Robustness Principle Reconsidered

15

Bir yöntemin davranışı net, sezgisel, öngörülebilir ve basit olmalıdır. Genel olarak, olması gerektiği çok bir arayanın girişine ekstra işlem yapmak için tereddüt. Arayanın kaçınılmaz olarak amaçladığı hakkında bu tür tahminler, istenmeyen davranışlar ortaya çıkaran çok sayıda ileri vakaya sahiptir. Bir işlemi dosya yoluna katılmak kadar basit olarak düşünün. Katılan yollardan biri köklü görünüyorsa, birçok (veya belki de çoğu) dosya yolu birleştirme işlevi, önceki yolları sessizce atar! Örneğin, ile /abc/xyzkatılmak /evilsadece sonuç verecektir /evil. Bu, dosya yollarına katıldığımda asla niyetlendiğim şey değildir , ancak bu şekilde davranmayan bir arabirim olmadığı için , bu durumları kapsayan ya da hataya sahip olmak ya da fazladan kod yazmak zorunda kalıyorum.

Yani, "bağışlayıcı" bir yöntem olması için mantıklı zaman nadir durumlar söz konusudur, dedi ama gerektiği zaman karar vermek arayanın gücü dahilinde zaman ve ister bu işlem aşamaları kendi durumum için geçerli. Bu nedenle, çeşitli durumlarda bağımsız değişkenlere uygulamak istediğiniz ortak bir ön işleme adımı tanımladığınızda, aşağıdakiler için arabirimleri göstermelisiniz:

  • Ham işlevsellik, herhangi bir ön işleme tabi tutulmadan.
  • Ön işleme adımı kendi başına .
  • Ham işlevsellik ve ön işleme kombinasyonu.

Sonuncusu isteğe bağlıdır; yalnızca çok sayıda arama kullanacaksa sağlamalısınız.

İşlenmemiş işlevselliği açığa çıkarmak, arayan kişiye ihtiyaç duyduğu zaman ön işleme basamağı olmadan kullanma yeteneği verir. Önişlemci adımının kendi başına gösterilmesi, arayan kişinin, işlevi çağırmadığı durumlarda veya işlevi çağırmadan önce bir girdiyi önceden işlemek istediği durumlar için kullanmasına izin verir ( önce başka bir işleve geçmek istediklerinde olduğu gibi). Kombinasyonun sağlanması, arayanların her ikisini de zorlamadan çağırmasını sağlar; bu, çoğu arayan bunu bu şekilde kullanacaksa yararlıdır.


2
Tahmin edilebilir için +1. Ve basit bir +1 (keşke). Onları saklamamaya çalışmak yerine hatalarımı bulmama ve düzeltmeme yardım etmeni tercih ederim.
John M Gant,

4

Diğerlerinin de dediği gibi, "affetmek" ile eşleşen bir dizge yapmak, ek karmaşıklık sağlamak anlamına gelir. Bu, eşleştirmeyi uygulamada daha fazla çalışma anlamına gelir. Mesela şimdi daha birçok test vakanız var. Ad alanında anlamsal olarak eşit adların bulunmadığından emin olmak için ek çalışmalar yapmanız gerekir. Daha fazla karmaşıklık ayrıca gelecekte daha fazla yanlış yapılması anlamına geliyor. Bisiklet gibi daha basit bir mekanizma, araba gibi daha karmaşık olandan daha az bakım gerektirir.

Öyleyse, esnek dize tüm bu ek maliyete değiyor mu? Diğerlerinin de belirttiği gibi, kullanım durumuna bağlıdır. Dizeleri üzerinde hiçbir kontrole sahip harici giriş çeşit vardır ve kesin bir avantaj hoşgörülü eşleme varsa, o olabilir değerinde olması. Belki de girdi, boşluk karakterleri ve büyük harf kullanımı konusunda çok vicdan sahibi olmayabilecek son kullanıcılardan geliyor ve ürününüzü daha kolay kullanabilmeniz için güçlü bir teşvikiniz var.

Öte yandan, eğer girdi girdiyse, teknik insanlar tarafından toplanan özellik dosyalarının, eğer bunu anlaması "Fred Mertz" != "FredMertz"gerekiyorsa, eşleştirmeyi daha katı hale getirmek ve geliştirme maliyetinden tasarruf etmek için daha fazla eğimli olacağımı düşünürdüm.

Her halükarda, öndeki ve sondaki alanların kırpılması ve göz ardı edilmesinin bir değeri olduğunu düşünüyorum, ancak bu tür sorunların hatalarını ayıklamak için çok fazla zaman harcadım.


3

Bu sorunun geldiği bağlamın bazılarından bahsediyorsunuz.

Buna göre, yöntemin sadece bir şeyi yapmasını istiyorum, dizgede gerekli olanları belirtiyor, buna dayanarak çalışmasına izin veriyor - buraya dönüştürmeye çalışmazdım. Basit tutun ve açık tutun; belgeleyin ve belgeleri ve kodları birbiriyle senkronize etmeye çalışın.

Kullanıcı veritabanından gelen verileri biraz daha affedici bir şekilde dönüştürmek istiyorsanız, bu işlevi ayrı bir dönüştürme yöntemine yerleştirin ve bağlı olan işlevi belgeleyin .

Bir noktada, fonksiyonun gereksinimleri karşılanmalı, açıkça belgelenmeli ve uygulama devam etmelidir. Bu noktada "affetmek" biraz dilsizdir, bu bir tasarım kararıdır ve fonksiyonun tartışmasını değiştirmemesini savunuyorum. İşlevin mutasyona tabi tutulması, istemciden istenen onaylamanın bir kısmını gizler. Mutasyonu yapan bir işleve sahip olmak müşterinin doğru yapmasına yardımcı olur.

Buradaki büyük vurgu netlik ve kodun ne yaptığını belgelemek .


-1
  1. DoSomething (), takeBackUp () gibi bir işleme göre bir yöntemi adlandırabilirsiniz.
  2. Bakımını kolaylaştırmak için, ortak sözleşmeleri ve farklı prosedürlerle ilgili onaylamaları saklayabilirsiniz. Kullanım durumlarına göre onları arayın.
  3. Savunma programlaması: prosedürünüz aşağıdakiler de dahil olmak üzere çok çeşitli girdilerin üstesinden gelir (Kullanım koşulları olan asgari şeyler her durumda ele alınmalıdı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.