“False” olan boolean işlev argümanlarına koymak için doğru yorum?


19

Bazı açık kaynak projelerinden, aşağıdaki kodlama stilini topladım

void someFunction(bool forget);

void ourFunction() {
  someFunction(false /* forget */);
}    

falseBurada ne anlama geldiğinden her zaman şüphem var. "Unut" anlamına mı geliyor, yoksa "unutma" karşılık gelen parametresine mi (yukarıdaki durumda olduğu gibi) atıfta bulunuyor ve "yanlış" ise onu reddetmek anlamına mı geliyor?

En çok hangi stil kullanılır ve belirsizlikten kaçınmanın en iyi yolu (veya daha iyi yollarından bazıları) nedir?


38
yerine enums kullanın (sadece 2 seçenek olsa bile)
Esailija

21
Bazı diller adlandırılmış argümanları destekler. Bu dillerde kullanabilirsinizsomeFunction(forget: true);
Brian

3
Martin Fowler'in Bayrak Argümanları hakkındaki argümanlarını sunmakla yükümlü olduğumu hissediyorum (ayrıca boolean setters hakkında konuşuyor). Genel olarak, bunlardan kaçınmaya çalışın.
FGreg

3
Açıkça söylemek gerekirse, yorumlar yalan söyleyebilir. Bazı değişecek çünkü Böylece, her zaman daha iyi kod self-documenting yapmaktır trueiçin falseve yorumu güncelleme değil. API'yı değiştiremiyorsanız, bunu yorumlamanın en iyi yolusomeFunction( false /* true=forget, false=remember */)
Mark Lakata

1
@Bakuriu - aslında, muhtemelen hala ortak API iki ayrı yöntem var ( sortAscendingve sortDescending, veya benzer). Şimdi, içeride , her ikisi parametre bu tür olabilir aynı özel yöntem, çağırabilir. Aslında, dil destekliyorsa, muhtemelen geçeceğim şey sıralama yönünü içeren bir lambda işlevi olurdu ...
Clockwork-Muse

Yanıtlar:


33

Gönderdiğiniz örnek kodda forget, bir bayrak argümanı gibi görünüyor . (Emin değilim çünkü fonksiyon tamamen varsayımsaldır.)

Bayrak argümanları bir kod kokusudur. Bir işlevin birden fazla şey yaptığını ve iyi bir işlevin sadece bir şey yapması gerektiğini belirtirler.

Bayrak argümanından kaçınmak için, işlevi işlev adındaki farkı açıklayan iki işleve ayırın.

Bayrak argümanı

serveIceCream(bool lowFat)

Bayrak argümanı yok

serveTraditionalIceCream()
serveLowFatIceCream()

edit: İdeal olarak, flag parametresi ile bir fonksiyonun çevresinde kalmanıza gerek yoktur. Ne çizgisinde durumlar vardır Fowler bir dolaşık uygulama çağırır tamamen fonksiyonlarının ayrılması çoğaltılamaz kodunu oluşturur. Bununla birlikte, parametrelenen fonksiyonun siklomatik karmaşıklığı ne kadar yüksek olursa, ondan kurtulma argümanı o kadar güçlüdür.


Bu sadece bir önsezi, ancak forgetkıskançlık gibi sesler adlı bir parametre . Arayan neden başka bir nesneye bir şey unutmasını söylesin ki? Daha büyük bir tasarım sorunu olabilir.


4
+17, kask açık. Cesetler neye benziyor serveTraditionalIceCreamve serveLowFatIceCreamneye benziyor? 14 çeşit dondurma ile bir sayım var.
JohnMark13

13
Herkese açık yöntemler için bu kural iyidir, ancak JohnMark'ın ifade ettiği gibi, SRP'nin diğer yarısı “ne yaptığını yapan tek yöntem iyi bir yöntem olmalıdır”. Bu yöntemin N + 1 varyantları olduğunu görüyorum; Hiçbir parametre içermeyen N herkese açıktır; bunların tümü, göstermekten kaçınmaya çalıştığınız parametre ile tek bir özel yöntem çağırır. Bir noktada, sadece lanet parametresini bırakıp ortaya çıkarırsınız. Kod kokuları mutlaka kodun yeniden düzenlenmesi gerektiği anlamına gelmez; kod incelemesinde ikinci kez bakmayı hak eden şeyler bunlar.
KeithS

@Aaron "Feature envy" ile ne demek istediniz?
Geek

27

Layman'ın sözleriyle:

  • false bir değişmezdir.
  • tam anlamıyla geçiyorsun false
  • someFunctionunutmamasını söylüyorsun
  • Eğer anlatıyorsun someFunctionparametredir unutmakfalse
  • someFunctionhatırlamanı söylüyorsun

Bence işlev böyle olsaydı daha iyi olurdu:

void someFunction(bool remember);

onu arayabilirsin

void ourFunction() {
  someFunction(true);
} 

veya eski adı koruyun ancak sarma işlevinizi şu şekilde değiştirin:

void ourFunctionWithRemember() {
  someFunction(false);
} 

DÜZENLE:

@Vorac'ın belirttiği gibi, her zaman olumlu kelimeler kullanmaya çalışın . Çift olumsuzlama kafa karıştırıcı.


15
Pozitif kelimeleri kullanmak için her zaman çaba gösterme fikri için +1. Çift olumsuzlama kafa karıştırıcı.
Vorac

1
Anlaşıldı, harika fikir. Sisteme bir şey yapmamalarını söylemek kafa karıştırıcıdır. Bir boolean parametresini kabul ediyorsanız, pozitif olarak ifade edin.
Brandon

Çoğu durumda, rememberişlev adı remember çok açık hale gelmedikçe, bundan daha spesifik olmak isteyeceğinizi düşünüyorum . rememberToCleanUp* or *persistya da başka birşey.
itsbruce

14

Parametre iyi adlandırılmış olabilir; işlevin adını bilmeden söylemek zor. Ben açıklama işlevinin asıl yazarın yazılmış olduğunu varsayalım ve bu geçen şeyin bir hatırlatma oldu falseiçine someFunctionaraçlarla ama kimse sonradan birlikte geldiğiniz için, ilk bakışta biraz belirsiz.

Pozitif bir değişken adı kullanmak ( Kod Tamamlandı bölümünde önerilmektedir ), bu snippet'in okunmasını kolaylaştıracak en basit değişiklik olabilir;

void someFunction(boolean remember);

sonra ourFunctionolur:

void ourFunction() {
    someFunction(true /* remember */);
}

Bununla birlikte, bir enum kullanmak, işlev çağrısını, bazı destek kodu pahasına, anlaşılmasını daha da kolaylaştırır:

public enum RememberFoo {
    REMEMBER,
    FORGET
}

...

void someFunction(RememberFoo remember);

...

void ourFunction() {
    someFunction(RememberFoo.REMEMBER);
}

Herhangi bir someFunctionnedenden dolayı imzasını değiştiremiyorsanız, geçici bir değişken kullanmak da kodu okumayı kolaylaştırır, kodun insanlar tarafından ayrıştırılmasını kolaylaştırmaktan başka bir nedenden ötürü bir değişken sunarak koşulların basitleştirilmesi gibi .

void someFunction(boolean remember);

...

void ourFunction() {
    boolean remember = false;
    someFunction(remember);
}

1
Doğruya ayarlamak rememberunutmak demektir (örneğinizde someFunction(true /* forget */);)?
Brian

2
Bu enumaçık ara en iyi çözümdür. Bir tür sırf edebilirsiniz bir şekilde temsil edilmesi bool; yani onlar izomorf-it vardır o anlamına gelmez gerektiği gibi temsil edilebilir. Aynı argüman stringve hatta geçerlidir int.
Jon Purdy

10

Bir bool değeri anlamlı olacak şekilde değişkeni yeniden adlandırın.

Bu, bir işleve argümanları açıklamak için bir açıklama eklemekten bir milyon kat daha iyidir çünkü ad belirsizdir.


3
Bu soruya cevap vermiyor. Metot tanımlandığında ve aynı dosyada 4 satır arayla çağrıldığında her şey açıktır. Peki ya şu anda tüm gördüğünüz arayan varsa? Birden fazla boolean varsa ne olur? Bazen basit bir satır içi yorum uzun bir yol kat eder.
Brandon

@Brandon Bu, boolean doNotPersist (veya daha iyisi Persist) çağrılmasına karşı bir argüman değildir. Ne unutacağını söylemeden "unut" demek açıkçası yararsızdır. Oh, ve bir seçenek olarak birkaç boolean alan bir yöntem yüksek cennete kokuyor.
itsbruce

5

Daha açıklayıcı bir adla yerel bir boole oluşturun ve bu değere atayın. Bu şekilde anlam daha açık olacak.

void ourFunction() {
    bool takeAction = false;  /* false means to forget */
    someFunction( takeAction );
}    

Değişkeni yeniden adlandıramazsanız, yorum biraz daha etkileyici olmalıdır:

void ourFunction() {
    /* false means that the method should forget what was requested */
    someFunction( false );
}    

1
Kesinlikle iyi bir tavsiye, ama /* forget */yorumun ele alınması konusuna hitap ettiğini düşünmüyorum , yani önünüzdeki fonksiyon bildirimi olmadan, neyin ayarlandığını hatırlamak zor olabilir false. (Bu yüzden @ Esailija'nın bir enum ekleme tavsiyesinin daha iyi olduğunu ve neden adlandırılmış parametrelere izin veren dilleri sevdiğimi düşünüyorum.)
Robot Gort

@StevenBurnap - teşekkürler! Eski cevabımın OP'nin sorusunu ele alırken yeterince açık olmadığı konusunda haklısın. Daha anlaşılır olması için düzenledim.

3

Qt-Style API'lara atıfta bulunduğundan, bu durumdan bahseden iyi bir makale vardır. Orada, Boole Parametre Tuzağı denir ve okumaya değer.

Bunun özü:

  1. Boole ihtiyaç duyulmaması için işlevi aşırı yüklemek
  2. Bir numaralandırma kullanmak (Esailija'nın önerdiği gibi) en iyisidir

2

Bu tuhaf bir yorum.

Derleyicinin bakış açısından, someFunction(false /* forget */);aslında someFunction(false);(yorum çıkarılır). Yani, bu hattın yaptığı someFunctionilk (ve sadece) argüman olarak ayarlanmış olarak çağırmaktır false.

/* forget */sadece parametrenin adıdır. Muhtemelen orada olması gerekmeyen hızlı (ve kirli) bir hatırlatmadan başka bir şey değildir. Sadece daha az belirsiz bir parametre adı kullanın ve yoruma hiç ihtiyacınız olmayacak.


1

Temiz kodun önerilerinden biri , gereksiz yorumlar 1 sayısını en aza indirgemek (çürümeye yatkın olmaları nedeniyle) ve işlevleri ve yöntemleri düzgün adlandırmaktır.

Bunu takiben, yorumu kaldıracağım. Sonuçta, modern IDE'ler (eclipse gibi), bir fareyi işlevin üzerine getirdiğinizde kodlu bir kutu açar. Kodu görmek belirsizliği ortadan kaldırmalıdır.


1 Bazı karmaşık kodları yorumlamak sorun değildir.


btw Kim böyle bir şey söyledi: "en kötü programcının sorunu değişken adı nasıl adlandırılır ve bir tarafından dengelenir"?
BЈовић

4
Muhtemelen kaynağı olarak martinfowler.com/bliki/TwoHardThings.html'yi arıyorsunuz . "Bilgisayar Bilimlerinde sadece iki zor şey var: önbellek geçersiz kılma, bir şeyleri adlandırma ve bir hata nedeniyle kapalı" diye duydum.

1

Açıkça söylemek gerekirse, yorumlar yalan söyleyebilir. Bazı kişi (belki) değişecek çünkü Böylece açıklamaya yorumlarla başvurmadan kodunuzu kendini documenting yapmak her zaman daha iyidir trueetmek falseve yorumu güncelleme değil.

API'yi değiştiremiyorsanız, 2 seçeneğe başvuruyorum

  • Açıklamayı, koddan bağımsız olarak her zaman doğru olacak şekilde değiştirin. Bunu sadece bir kez ararsanız, bu iyi bir çözümdür, çünkü belgeyi yerel tutar.
     someFunction (yanlış / * true = unut, yanlış = hatırla * /); `
  • #Defines kullanın, özellikle birden çok kez çağırırsanız.
     #define UNUT doğru
     #define REMEMBER yanlış
     birFonksiyon (HATIRLANMASI);

1

Ben yorum her zaman doğru yapma ile ilgili cevap gibi , ama iyi olsa da bu kod ile temel sorunu özledim düşünüyorum - tam anlamıyla çağrılıyor.

Yöntemleri çağırırken değişmez değerler kullanmaktan kaçınmalısınız. Yerel değişkenler, isteğe bağlı parametreler, adlandırılmış parametreler, numaralandırmalar - bunlardan en iyi nasıl kaçınacağınız dile ve mevcut olana bağlı olacaktır, ancak bunlardan kaçınmaya çalışın. Değişmez değerler vardır, ancak bir anlamı yoktur.


-1

C # 'da, bunu daha net hale getirmek için adlandırılmış parametreleri kullandım

someFunction(forget: false);

Veya enum:

enum Memory { Remember, Forget };

someFunction(Memory.Forget);

Veya aşırı yükler:

someFunctionForget();

Veya polimorfizm ':

var foo = new Elephantine();

foo.someFunction();

-2

Adlandırma, booleanların belirsizliğini her zaman çözmelidir. Ben her zaman boolean 'isThis' veya 'shouldDoThat' gibi bir şey adlandırıyorum, örneğin:

void printTree(Tree tree, bool shouldPrintPretty){ ... }

ve bunun gibi. Ancak başka birinin koduna başvururken, değerleri geçerken yorum bırakmak en iyisidir.


bu soru sorulan cevabı nasıl?
gnat

@gnat Belirsizliği boole parametreleriyle çözme konusundaki sorusunu yanıtlıyordum. Belki sorusunu yanlış okudum.
dchhetri
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.