बूलियन फ़ंक्शन तर्कों के लिए सही टिप्पणी करें जो "झूठे" हैं?


19

कुछ ओपन सोर्स प्रोजेक्ट्स से, मैंने निम्नलिखित कोडिंग शैली एकत्र की

void someFunction(bool forget);

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

मुझे हमेशा इस बारे में संदेह है कि falseयहां क्या मतलब है। क्या इसका मतलब है "भूल जाना", या क्या "भूल" इसके संबंधित पैरामीटर (जैसे ऊपर के मामले में) को संदर्भित करता है, और "झूठे" का मतलब इसे नकारना है?

किस शैली का सबसे अधिक बार उपयोग किया जाता है और अस्पष्टता से बचने के लिए सबसे अच्छा तरीका क्या है (या कुछ बेहतर तरीके)?


38
बूल के बजाय
एनम का

21
कुछ भाषाएं तर्कों के नाम का समर्थन करती हैं। ऐसी भाषाओं में, आप उपयोग कर सकते हैंsomeFunction(forget: true);
ब्रायन

3
मैं फ्लैग आर्ग्युमेंट्स पर मार्टिन फाउलर की दलीलें प्रदान करने के लिए बाध्य महसूस करता हूं (बूलियन सेटर्स के बारे में भी बात करता है)। सामान्य तौर पर, उनसे बचने की कोशिश करें।
FGreg

3
स्पष्ट को स्पष्ट करने के लिए, टिप्पणियां झूठ बोल सकती हैं। इस प्रकार, हमेशा बेहतर अपने कोड स्वयं कुछ दस्तावेज़ीकृत बनाने के लिए है क्योंकि कुछ बदल जाएगा trueकरने के लिए falseऔर टिप्पणी अद्यतन नहीं। यदि आप एपीआई को नहीं बदल सकते हैं, तो यह टिप्पणी करने का सबसे अच्छा तरीका हैsomeFunction( false /* true=forget, false=remember */)
मार्क Lakata

1
@ बकुरीउ - वास्तव में, मैं शायद अभी भी सार्वजनिक एपीआई के दो अलग-अलग तरीके ( sortAscendingऔर sortDescending, या इसी तरह) होंगे। अब, अंदर , वे दोनों एक ही निजी पद्धति को कॉल कर सकते हैं, जिसमें इस तरह का पैरामीटर हो सकता है। वास्तव में, अगर भाषा ने इसका समर्थन किया, तो शायद मैं जो पास करूँगा वह एक लंबो फ़ंक्शन होगा जिसमें छँटाई दिशा शामिल होगी ...
क्लॉकवर्क-म्यूज़िक

जवाबों:


33

आपके द्वारा पोस्ट किए गए नमूना कोड में, ऐसा लगता है forgetकि एक ध्वज तर्क है। (मैं निश्चित नहीं हो सकता क्योंकि फ़ंक्शन विशुद्ध रूप से काल्पनिक है।)

ध्वज तर्कों एक कोड गंध है। वे संकेत देते हैं कि एक कार्य एक से अधिक कार्य करता है, और एक अच्छे कार्य को केवल एक ही कार्य करना चाहिए।

ध्वज तर्क से बचने के लिए, फ़ंक्शन को दो कार्यों में तोड़ दें जो फ़ंक्शन नाम में अंतर को स्पष्ट करते हैं।

झंडे का तर्क

serveIceCream(bool lowFat)

कोई झंडा तर्क नहीं

serveTraditionalIceCream()
serveLowFatIceCream()

संपादित करें: आदर्श रूप में, आपको ध्वज पैरामीटर के साथ किसी फ़ंक्शन को रखने की आवश्यकता नहीं है। फाउलर एक पेचीदा कार्यान्वयन को कॉल करता है, जहां की तर्ज पर ऐसे मामले होते हैं जहां फ़ंक्शन को पूरी तरह से अलग करके डुप्लिकेट कोड बनाया जाता है। हालांकि, पैरामीटर किए गए फ़ंक्शन के साइक्लोमैटिक जटिलता जितनी अधिक होती है, उतनी ही मजबूत होती है इससे छुटकारा पाने के लिए तर्क।


यह केवल एक कूबड़ है, लेकिन एक पैरामीटर जिसका नाम forgetफीचर ईर्ष्या है। एक कॉलर किसी वस्तु को कुछ भूलने के लिए क्यों कहेगा? एक बड़ा डिजाइन मुद्दा हो सकता है।


4
+17, हेलमेट पर। के शरीर serveTraditionalIceCreamऔर क्या serveLowFatIceCreamदिखते हैं? मेरे पास 14 प्रकार की आइसक्रीम के साथ एक एनम है।
जॉनमेर

13
सार्वजनिक तरीकों के लिए, यह सम्मेलन अच्छा है, लेकिन जॉनमार्क के दृष्टिकोण के अनुसार, SRP का दूसरा भाग "एक अच्छा तरीका एकमात्र तरीका होना चाहिए जो यह करता है"। मैं देखता हूं कि इस विधि के N + 1 संस्करण हैं; बिना किसी मापदण्ड के एन जनता, जिनमें से सभी एक निजी पद्धति को उस पैरामीटर के साथ कहते हैं जिसे आप उजागर करने से बचने की कोशिश कर रहे हैं। कुछ बिंदु पर, आप बस लानत पैरामीटर को छोड़ देते हैं और उजागर करते हैं। कोड की गंध जरूरी नहीं है कि कोड को फिर से भरना चाहिए; वे एक कोड समीक्षा में दूसरे लुक के लायक हैं।
कीथ

@Aaron "फीचर ईर्ष्या" से आपका क्या मतलब है?
Geek

27

आम आदमी के शब्दों में:

  • false एक शाब्दिक है।
  • आप एक शाब्दिक पारित कर रहे हैं false
  • आप someFunctionभूल नहीं करने के लिए कह रहे हैं
  • आप बता रहे हैं someFunctionकि पैरामीटर भूल हैfalse
  • आप someFunctionयाद करने के लिए कह रहे हैं

मेरी राय में यह बेहतर होगा यदि फ़ंक्शन इस प्रकार था:

void someFunction(bool remember);

आप इसे कॉल कर सकते हैं

void ourFunction() {
  someFunction(true);
} 

या पुराना नाम रखें लेकिन अपने रैपर फ़ंक्शन को बदल दें

void ourFunctionWithRemember() {
  someFunction(false);
} 

संपादित करें:

जैसा कि @ वोरैक ने कहा, हमेशा सकारात्मक शब्दों का उपयोग करने का प्रयास करें। दोहरा नकार भ्रामक है।


15
हमेशा सकारात्मक शब्दों का उपयोग करने के लिए विचार करने के लिए +1। दोहरा नकार भ्रामक है।
वोरैक सिप

1
सहमत, महान विचार। कुछ नहीं करने के लिए सिस्टम को बताना भ्रामक है। यदि बूलियन पैरामीटर को स्वीकार करते हैं, तो इसे सकारात्मक रूप से व्यक्त करें।
ब्रैंडन

ज्यादातर मामलों में, मुझे लगता है कि आप rememberतब तक और अधिक विशिष्ट होना चाहेंगे , जब तक कि फ़ंक्शन नाम remember बहुत स्पष्ट नहीं हो जाता। rememberToCleanUp* or *persistया कुछ और।
इसका

14

पैरामीटर अच्छी तरह से नामित हो सकता है; फ़ंक्शन का नाम जाने बिना बताना मुश्किल है। मुझे लगता है कि टिप्पणी समारोह के मूल लेखक द्वारा लिखी गई थी, और यह इस बात की याद दिलाता था कि किस अर्थ falseमें गुजर रहा someFunctionहै, लेकिन बाद में आने वाले किसी भी व्यक्ति के लिए, यह पहली नज़र में थोड़ा अस्पष्ट है।

एक सकारात्मक चर नाम ( कोड पूर्ण में सुझाया गया ) का उपयोग करना सबसे सरल परिवर्तन हो सकता है जो इस स्निपेट को पढ़ने में आसान बना देगा, जैसे

void someFunction(boolean remember);

फिर ourFunctionबन जाता है:

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

हालाँकि, कुछ सपोर्टिंग कोड की कीमत पर, एनम का उपयोग करने से फंक्शन कॉल को समझना और भी आसान हो जाता है:

public enum RememberFoo {
    REMEMBER,
    FORGET
}

...

void someFunction(RememberFoo remember);

...

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

यदि आप किसी someFunctionभी कारण से हस्ताक्षर बदलने में असमर्थ हैं , तो अस्थायी चर का उपयोग करने से कोड को पढ़ने में आसानी होती है, जैसे कि बिना किसी अन्य कारण के एक चर को शुरू करके सशर्त को सरल बनाने के समान है, जिससे कोड को मनुष्यों द्वारा पार्स करना आसान हो सके। ।

void someFunction(boolean remember);

...

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

1
स्थापना rememberको सही साधनों पर (के अपने उदाहरण में भूल जाते हैं someFunction(true /* forget */);)?
ब्रायन

2
enumअब तक का सबसे अच्छा समाधान कर रहा है। सिर्फ इसलिए कि एक प्रकार को एक आइई के रूप में दर्शाया जा सकता है bool, वे आइसोमॉर्फिक हैं - इसका मतलब यह नहीं है कि इसे इस तरह से प्रस्तुत किया जाना चाहिए। यही तर्क stringयहां तक ​​कि लागू होता है int
जॉन प्यूडी

10

चर का नाम बदलें तो एक बूल मान समझ में आता है।

यह एक फ़ंक्शन के लिए तर्कों को समझाने के लिए टिप्पणी जोड़ने से लाख गुना बेहतर है क्योंकि नाम अस्पष्ट है।


3
इस सवाल का जवाब नहीं है। जब सभी विधि स्पष्ट हो जाती है, तो विधि को परिभाषित किया जाता है और एक ही फाइल 4 लाइनों में अलग से बुलाया जाता है। लेकिन क्या होगा यदि आप इस समय कॉल करने वाले को देखते हैं? क्या होगा अगर इसमें कई बूलियन हों? कभी-कभी एक सरल इन-लाइन टिप्पणी एक लंबा रास्ता तय करती है।
ब्रैंडन

@ ब्रेंडन कि बूलियन doNotPersist (या, बेहतर, Persist) को कॉल करने के खिलाफ एक तर्क नहीं है। इसे "भूल जाना" कहना बिना भूल जाने के स्पष्ट रूप से अनहेल्दी है। ओह, और एक विधि जो एक विकल्प के रूप में कई बुलियन लेती है वह उच्च स्वर्ग में बदबू मारती है।
इसका

5

अधिक विवरणात्मक नाम के साथ एक स्थानीय बूलियन बनाएं, और इसके लिए मान निर्दिष्ट करें। इस तरह से अर्थ अधिक स्पष्ट होगा।

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

यदि आप चर का नाम नहीं बदल सकते हैं, तो टिप्पणी थोड़ी अधिक अभिव्यंजक होनी चाहिए:

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

1
निश्चित रूप से अच्छी सलाह, लेकिन मुझे नहीं लगता कि यह उस मुद्दे को संबोधित करता है जो /* forget */टिप्पणी करने के लिए है, जो यह है कि आपके सामने फ़ंक्शन घोषणा के बिना, यह याद रखना मुश्किल है कि क्या सेट किया जा रहा है false। (यही कारण है कि मुझे लगता है कि @ एसमेलिजा को एक एनम जोड़ने की सलाह बेहतर है, और मुझे ऐसी भाषाएं क्यों पसंद हैं जो नामांकित मापदंडों की अनुमति देती हैं।)
रोबोट

@StevenBurnap - धन्यवाद! आप सही हैं कि ओपी के प्रश्न को संबोधित करने में मेरा पुराना उत्तर पर्याप्त नहीं था। इसे और अधिक स्पष्ट करने के लिए मैंने इसे संपादित किया है।

3

एक अच्छा लेख है जो इस सटीक स्थिति का उल्लेख करता है क्योंकि यह क्यूटी-स्टाइल एपीआई को संदर्भित करता है। वहाँ, इसे बूलियन पैरामीटर ट्रैप कहा जाता है और यह पढ़ने लायक है।

इसका सार है:

  1. फ़ंक्शन को ओवरलोड करना ताकि बूल की आवश्यकता न हो, बेहतर है
  2. एक एनम का उपयोग करना (जैसा कि एस्लेइजा बताते हैं) सबसे अच्छा है

2

यह एक विचित्र टिप्पणी है।

संकलक के दृष्टिकोण से, someFunction(false /* forget */);वास्तव में someFunction(false);(टिप्पणी छीन ली गई है)। तो, वह सब लाइन someFunctionजो पहले (और केवल) तर्क के साथ सेट की गई है false

/* forget */केवल पैरामीटर का नाम है। यह शायद एक त्वरित (और गंदे) अनुस्मारक से ज्यादा कुछ नहीं है, जो वास्तव में वहां होने की आवश्यकता नहीं है। बस एक कम अस्पष्ट पैरामीटर नाम का उपयोग करें, और आपको टिप्पणी की आवश्यकता नहीं होगी।


1

स्वच्छ कोड की एक सलाह अनावश्यक टिप्पणियों 1 की संख्या को कम करना है (क्योंकि वे सड़ जाते हैं), और कार्यों और विधियों को ठीक से नाम देने के लिए।

उसके बाद, मैं सिर्फ टिप्पणी को हटा दूंगा। आखिरकार, आधुनिक IDEs (जैसे ग्रहण) कोड के साथ एक बॉक्स को पॉप करते हैं जब आप फ़ंक्शन पर माउस डालते हैं। कोड को देखकर अस्पष्टता को साफ करना चाहिए।


1 कुछ जटिल कोड टिप्पणी करना ठीक है।


btw इस तरह से किसने कहा: "सबसे खराब प्रोग्रामर की समस्या यह है कि चर का नाम कैसे दिया जाए, और एक से ऑफसेट करें"?
B45ови।

4
आप संभवतः इसके स्रोत के रूप में martinfowler.com/bliki/TwoHardThings.html की तलाश कर रहे हैं । मैंने सुना है कि "कंप्यूटर विज्ञान में केवल दो कठिन चीजें हैं: कैश अमान्यकरण, नामकरण चीजें, और एक त्रुटि से दूर।"

1

स्पष्ट को स्पष्ट करने के लिए, टिप्पणियां झूठ बोल सकती हैं। इस प्रकार हमेशा बेहतर, टिप्पणी का सहारा व्याख्या करने के लिए बिना अपने कोड स्वयं कुछ दस्तावेज़ीकृत बनाने के लिए है क्योंकि कुछ व्यक्ति (शायद आप) बदल जाएगा trueकरने के लिए falseऔर टिप्पणी अद्यतन नहीं।

यदि आप एपीआई नहीं बदल सकते हैं, तो मैं 2 विकल्पों का सहारा लेता हूं

  • टिप्पणी बदलें ताकि कोड की परवाह किए बिना यह हमेशा सच हो। यदि आप इसे केवल एक बार कहते हैं, तो यह एक अच्छा समाधान है, क्योंकि यह दस्तावेज़ को स्थानीय रखता है।
     someFunction (झूठा / * सच = भूल, झूठा = याद रखना * /); `
  • #Defines का उपयोग करें, खासकर यदि आप इसे एक से अधिक बार कहते हैं।
     #define भूल जाओ सच
     #define REMEMBER झूठा
     someFunction (याद);

1

मुझे टिप्पणी को हमेशा सच बनाने के बारे में जवाब पसंद है , लेकिन मुझे अच्छा लगता है कि यह इस कोड के साथ मूलभूत समस्या को याद करता है - इसे शाब्दिक रूप से कहा जा रहा है।

तरीकों को कॉल करते समय आपको शाब्दिक उपयोग करने से बचना चाहिए। स्थानीय चर, वैकल्पिक पैरामीटर, नामित पैरामीटर, एनम - आप उनसे कैसे बचते हैं यह भाषा और व्हाट्स पर उपलब्ध निर्भर करेगा, लेकिन उनसे बचने की कोशिश करें। साहित्य में मूल्य हैं, लेकिन उनका कोई अर्थ नहीं है।


-1

C # में, मैंने इसको स्पष्ट करने के लिए नामित मापदंडों का उपयोग किया है

someFunction(forget: false);

या enum:

enum Memory { Remember, Forget };

someFunction(Memory.Forget);

या अधिभार:

someFunctionForget();

या बहुरूपता:

var foo = new Elephantine();

foo.someFunction();

-2

नामकरण हमेशा बूलियंस के लिए अस्पष्टता को हल करना चाहिए। मैं उदाहरण के लिए हमेशा कुछ बूलियन का नाम देता हूं, जैसे 'यह' या 'कंधे पर'।

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

और इसी तरह। लेकिन जब आप किसी और के कोड का संदर्भ दे रहे हैं, तो यह सबसे अच्छा है कि मूल्यों को पारित करते समय टिप्पणी को छोड़ दें।


यह पूछे गए प्रश्न का उत्तर कैसे देता है?
gnat

@gnat मैं बूलियन मापदंडों के साथ अस्पष्टता को हल करने के बारे में उनके सवाल का जवाब दे रहा था। हो सकता है कि मैंने उनके सवाल को गलत पढ़ा हो।
ढेचेरी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.