प्रोग्रामर को अपने कोड को "दस्तावेज़" करने के लिए बूलियन चर का उपयोग करना चाहिए?


79

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

if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) || 
   (elementIndex == lastElementIndex)){
       ...
}

उसने सुझाव दिया:

finished = ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
repeatedEntry = (elementIndex == lastElementIndex);
if(finished || repeatedEntry){
   ...
}

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


@Paul आर - वूप्स, धन्यवाद। मैंने स्व-प्रलेखन के साथ शुरुआत की और महसूस किया कि इसके लिए कोई टैग नहीं था, इसलिए इसे स्व-दस्तावेजीकरण में बदलने की कोशिश की, जो पहले से मौजूद था। :)
फ्रैडी

क्या केवल इस बात पर टिप्पणी नहीं कर रहा है कि परीक्षण में क्या बेहतर है?
JS

3
जब उपयुक्त हो, मैं यह करने की कोशिश करता हूं, खासकर अगर मुझे विधि के विभिन्न भागों में स्थिति (ओं) के लिए जांच करनी है। यह बहुत अधिक वर्णनात्मक है।
जिफचांग

"यह मुझे तार्किक, अच्छे अभ्यास और बहुत स्व-दस्तावेजीकरण के रूप में प्रभावित करता है।" बस अपने अनुभव के आधार पर, संभावना है कि यह अन्य प्रोग्रामर द्वारा आसानी से समझा जाएगा जो पहली बार इसके पार आते हैं।

2
यह प्रश्न अभी भी क्यों खुला है?
ऑरेंजपाइप्स

जवाबों:


55

एक अभिव्यक्ति को विभाजित करना, जो स्थानीय चर को सौंपे गए सरल उप-अभिव्यक्तियों में बहुत ही नेस्टेड और जटिल है, फिर से एक साथ रखा जाता है, काफी सामान्य और लोकप्रिय तकनीक है - काफी स्वतंत्र रूप से कि क्या उप-अभिव्यक्तियाँ और / या समग्र अभिव्यक्ति बूलियन या सरल हैं बस किसी भी अन्य प्रकार के बारे में। अच्छी तरह से चुने गए नामों के साथ, इस तरह का एक स्वादिष्ट अपघटन पठनीयता को बढ़ा सकता है, और एक अच्छे संकलक को कोड उत्पन्न करने में कोई परेशानी नहीं होनी चाहिए जो मूल, जटिल अभिव्यक्ति के बराबर है।

कुछ भाषाओं में "से असाइनमेंट" की अवधारणा नहीं होती है, जैसे कि हास्केल, यहां तक ​​कि आपको " whereसबमिशन को एक नाम देना" तकनीक का उपयोग करने के लिए विशेष निर्माणों का परिचय देता है ( हास्केल में खंड) - कुछ के लिए लगता है प्रश्न में तकनीक के लिए लोकप्रियता! -)


6
अगर यह सरल और पढ़ने में आसान है, तो मैं कहता हूं कि यह जीत-जीत का बहुत स्पष्ट मामला है :)
djcouchycouch

मैं सहमत हूँ। बहुत सारे मामलों में आप शायद एक छोटी टिप्पणी के साथ दूर हो सकते हैं, लेकिन मैं नहीं देखता कि यह वास्तव में कैसे चोट पहुंचा
मैक्स ई।

16

मैंने इसे इस्तेमाल किया है, हालांकि सामान्य रूप से बूलियन लॉजिक को एक पुन: प्रयोज्य विधि में लपेटना (यदि इसे कई स्थानों से कहा जाता है)।

यह पठनीयता में मदद करता है और जब तर्क बदलता है, तो इसे केवल एक स्थान पर बदलने की आवश्यकता होती है।

अन्य इसे समझेंगे और इसे अजीब नहीं पाएंगे (केवल उन लोगों को छोड़कर जो कभी हजार लाइन फ़ंक्शन लिखते हैं, वह है)।


जवाब के लिए धन्यवाद! पुन: प्रयोज्य तरीकों के बारे में, जिसके पास एक और (असंबंधित) वैध कारण होने की बात है ... तो मुझे लगता है कि मेरा प्रश्न वास्तव में है यदि आपको एक बार की बूलियन अभिव्यक्तियों को समझना चाहिए, जब पठनीयता के अलावा कोई कारण नहीं है। (जो निश्चित रूप से अपने आप में एक बड़ा पर्याप्त कारण है :)) कि बाहर इशारा करने के लिए धन्यवाद।
फ्रैडी

+1 कोड को कम करने के लिए आवश्यक होता है जब तर्क बदलता है, और हजार-लाइन-फ़ंक्शन प्रोग्रामर का मजाक उड़ाता है।
जेफरी एल व्हाइटलेज

9

मैं जहां भी संभव हो ऐसा करने की कोशिश करता हूं। ज़रूर, आप कोड की "अतिरिक्त लाइन" का उपयोग कर रहे हैं, लेकिन साथ ही, आप यह वर्णन कर रहे हैं कि आप दो मानों की तुलना क्यों कर रहे हैं।

आपके उदाहरण में, मैं कोड देखता हूं, और अपने आप से पूछता हूं "ठीक है कि मूल्य देखने वाला व्यक्ति 0 से कम क्यों है?" दूसरे में आप मुझे स्पष्ट रूप से बता रहे हैं कि ऐसा होने पर कुछ प्रक्रियाएँ समाप्त हो गई हैं। दूसरे में कोई अनुमान नहीं है कि आपका इरादा क्या था।

मेरे लिए एक बड़ा तब है जब मुझे एक तरीका दिखाई देता है जैसे: DoSomeMethod(true); यह अपने आप सही क्यों हो जाता है? यह बहुत अधिक पठनीय है

bool deleteOnCompletion = true;

DoSomeMethod(deleteOnCompletion);

7
मैं इस कारण से बूलियन मापदंडों को नापसंद करता हूं। आपको "createOrder (सत्य, असत्य, सत्य, सत्य, असत्य)" जैसे कॉल प्राप्त होते हैं और इसका क्या अर्थ है? मैं एनम का उपयोग करना पसंद करता हूं, इसलिए आप "createOrder (Source.MAIL_ORDER, BackOrder.NO, CustomOrder.CUSTOM, PayType.CREDIT)" जैसा कुछ कहते हैं।
जय

लेकिन अगर आप केविन के उदाहरण का अनुसरण करते हैं, तो यह आपके बराबर है। इससे क्या फर्क पड़ता है कि चर 2 मान या 2 से अधिक ले सकता है?
मार्क रूज़ोन

2
जेई के साथ आपको निश्चित उदाहरणों में स्पष्ट होने का फायदा हो सकता है। उदाहरण के लिए, PayType के उपयोग में। यदि यह एक बूलियन था तो पैरामीटर को संभावित नाम दिया जाएगा, isPayTypeCredit। आपको नहीं पता कि परिवर्तनशील क्या है। एनम के साथ आप स्पष्ट रूप से देख सकते हैं कि PayType क्या विकल्प है: क्रेडिट, चेक, कैश और सही एक का चयन करें।
kemiller2002

++ भी एक संज्ञा शून्य असाइनमेंट की अनुमति नहीं देता है, इसलिए मूल्य नियंत्रण काफी शाब्दिक रूप से पूरा हो गया है, और
एनम

ऑब्जेक्टिव-सी और स्मॉलटाक वास्तव में इस समस्या को हल करते हैं, ऑब्जेक्टिव-सी में:[Object createOrderWithSource:YES backOrder:NO custom:YES type:kCreditCard];
ग्रांट पॉल

5

प्रदान नमूना:

finished = ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
repeatedEntry = (elementIndex == lastElementIndex);
if(finished || repeatedEntry){
   ...
}

विधियों का उपयोग करने के लिए फिर से लिखा जा सकता है, जो पठनीयता में सुधार करता है और बूलियन तर्क को संरक्षित करता है (जैसा कि कोनराड ने कहा है):

if (IsFinished(elementIndex) || IsRepeatedEntry(elementIndex, lastElementIndex)){
   ...
}

...

private bool IsFinished(int elementIndex) {
    return ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
}

private bool IsRepeatedEntry(int elementIndex, int lastElementIndex) {
    return (elementIndex == lastElementIndex);
}

यह कीमत पर आता है, ज़ाहिर है, जो दो अतिरिक्त तरीके हैं। यदि आप ऐसा करते हैं, तो यह आपके कोड को अधिक पठनीय बना सकता है, लेकिन आपकी कक्षाएं कम पारदर्शी होती हैं। लेकिन फिर, आप अतिरिक्त तरीकों को सहायक कक्षाओं में भी स्थानांतरित कर सकते हैं।


यदि आपको C # के साथ कोड शोर की एक बहुत कुछ मिला है, तो आप आंशिक कक्षाओं का लाभ भी ले सकते हैं और शोर को आंशिक रूप में ले जा सकते हैं और यदि लोग इस बात में रुचि रखते हैं कि क्या IsFinished जाँच कर रहा है तो कूदना आसान है।
क्रिस मैरिकिक

3

एक ही रास्ता मैं देख सकता था कि यह गलत हो रहा है अगर बूलियन टुकड़ा का कोई नाम नहीं है जो समझ में आता है और किसी भी तरह से एक नाम उठाया जाता है।

//No clue what the parts might mean.
if(price>0 && (customer.IsAlive || IsDay(Thursday)))

=>

first_condition = price>0
second_condition =customer.IsAlive || IsDay(Thursday)

//I'm still not enlightened.
if(first_condition && second_condition)

मैं इसे इंगित करता हूं क्योंकि "अपने सभी कोड को कमेंट करना" जैसे नियम बनाना आम बात है, "सभी प्रकार के मानदंड के लिए बूलियन का उपयोग करें यदि 3 से अधिक भागों के साथ" केवल टिप्पणी पाने के लिए जो निम्न प्रकार के शब्दार्थ से खाली हैं।

i++; //increment i by adding 1 to i's previous value

2
आपने अपने उदाहरण में स्थितियों को गलत तरीके से रखा है, है ना? '&&' की तुलना में तंग बांधता है || अधिकांश भाषाओं में जो उनका उपयोग करते हैं (शेल स्क्रिप्ट एक अपवाद हैं)।
जोनाथन लेफ़लर

Parens गयी। तो यह नामांकित चर को विभाजित करने के खिलाफ एक और हड़ताल होगी, यह एक गैर-स्पष्ट फैशन में समूह को बदलने का अवसर पेश करता है।
मैथ्मार्टिन

2

ऐसा करके

finished = ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
repeatedEntry = (elementIndex == lastElementIndex);
if(finished || repeatedEntry){
   ...
}

आप अपने मस्तिष्क से तर्क को निकालते हैं और इसे कोड में डालते हैं। अब कार्यक्रम जानता है कि आपका क्या मतलब है।
जब भी आप किसी चीज का नाम लेते हैं तो आप उसे भौतिक प्रतिनिधित्व देते हैं। वह मौजूद है।
आप इसमें हेरफेर कर सकते हैं और इसका पुन: उपयोग कर सकते हैं।

आप पूरे ब्लॉक को एक विधेय के रूप में परिभाषित कर सकते हैं:

bool ElementBlahBlah? (elementIndex, lastElementIndex);

और उस फ़ंक्शन में अधिक सामान (बाद में) करें।


और अधिक महत्वपूर्ण बात, कोड को देखने वाले अगले देव को पता चल जाएगा कि आपका क्या मतलब है! यह महान अभ्यास है, और मैं इसे हर समय करता हूं।
क्रिस थॉर्नटन ने

1
इसके अलावा, कि अगले देव अक्सर स्वयं हो सकते हैं, कुछ महीनों (या कुछ सप्ताह) के बाद फिर से कोड को देख रहे हैं और खुशी है कि यह अच्छी तरह से स्व-दस्तावेज था।
लुई

2

यदि अभिव्यक्ति जटिल है, तो मैं या तो इसे किसी अन्य फ़ंक्शन में स्थानांतरित करता हूं जो एक boolउदाहरण देता है , isAnEveningInThePubAGoodIdea(dayOfWeek, sizeOfWorkLoad, amountOfSpareCash)या कोड पर पुनर्विचार करता है ताकि ऐसी जटिल अभिव्यक्ति की आवश्यकता न हो।


2

याद रखें कि इस तरह आप आवश्यकता से अधिक गणना करते हैं। कोड से शर्तों को पूरा करने के कारण, आप हमेशा उन दोनों (कोई शॉर्ट सर्किट) की गणना नहीं करते हैं।

इसलिए कि:

if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) || 
   (elementIndex == lastElementIndex)){
   ...
}

परिवर्तन हो जाने के बाद:

if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) |
   (elementIndex == lastElementIndex)){
   ...
}

अधिकांश मामलों में कोई समस्या नहीं है, लेकिन फिर भी कुछ में इसका मतलब खराब प्रदर्शन या अन्य मुद्दे हो सकते हैं, उदाहरण के लिए, जब 2 वें अभिव्यक्ति में आप मान लेते हैं कि 1 अंक विफल हो गया है।


यह सच है - मैं अभी इसे नोटिस कर रहा था क्योंकि मैं अपने कुछ कोड को वापस करने के लिए गया था अगर इस पद्धति का उपयोग करके कुछ बयानों को वापस लाया जाए। शॉर्ट सर्किट मूल्यांकन का लाभ लेने के लिए एक बयान था अगर && (दूसरा भाग एनपीई फेंकता है, तो पहला भाग गलत है), और मेरा कोड तब विफल हो रहा था जब मैंने इसे फिर से तैयार किया (क्योंकि यह हमेशा दोनों का मूल्यांकन कर रहा था और उन्हें बूलियन में संग्रहीत कर रहा था। चर)। अच्छी बात है, धन्यवाद! लेकिन मैं सोच रहा था कि मैंने यह कोशिश की थी - क्या तर्क में संग्रहित करने का कोई तरीका है और क्या यह वास्तविक मूल्यांकन तक देरी मूल्यांकन है?
froadie

2
मुझे वास्तव में संदेह है कि संकलक इसका समाधान करेगा। यदि दूसरा कॉल प्रभावी नहीं है, तो यह आमतौर पर किसी फ़ंक्शन के कॉल के कारण होता है, और AFAIK संकलक यह निर्धारित करने की कोशिश कर रहा है कि क्या कोई फ़ंक्शन बिना साइड-इफ़ेक्ट के नहीं है।
JS

आप IFs को घोंसला दे सकते हैं, और बाद की गणना तब तक नहीं कर सकते जब तक कि आगे बढ़ने के लिए पहला परीक्षण अपर्याप्त न हो।
Jay

@froadie कोटलिन (और जल्द ही डार्ट) जैसी कुछ भाषाएं "आलसी" चर की अनुमति देती हैं जो केवल उपयोग किए जाने पर गणना की जाएंगी। वैकल्पिक रूप से, एक चर के बजाय एक फ़ंक्शन में तर्क रखने से यहां समान प्रभाव होगा। बस, y'know, यदि आप अभी भी 10 साल बाद जानना चाहते हैं।
हैकर 1024

2

मुझे लगता है कि अस्थायी चरों के बजाय फ़ंक्शंस / तरीके बनाना बेहतर है। इस तरह से पठनीयता बढ़ जाती है क्योंकि विधियाँ छोटी हो जाती हैं। मार्टिन फाउलर की पुस्तक रिफैक्टिंग में कोड की गुणवत्ता में सुधार के लिए अच्छी सलाह है। आपके विशेष उदाहरण से संबंधित Refactorings को "रिप्लेसमेंट टेंप विद क्वेरी" और "एक्सट्रैक्ट मेथड" कहा जाता है।


2
क्या आप कह रहे हैं कि बहुत सारे वन-ऑफ कार्यों के साथ क्लास-स्पेस को अव्यवस्थित करके, आप पठनीयता बढ़ा रहे हैं? कृपया समझाएँ।
ज़ानो

यह हमेशा एक व्यापार है। मूल फ़ंक्शन की पठनीयता में सुधार होगा। यदि मूल कार्य छोटा है तो यह इसके लायक नहीं हो सकता है।
mkj

इसके अलावा "क्लास-स्पेस को अव्यवस्थित करना" कुछ ऐसा है जो मुझे लगता है कि इस्तेमाल की गई भाषा पर निर्भर करता है और आप अपने कोड को कैसे विभाजित करते हैं।
mkj

2

व्यक्तिगत रूप से, मुझे लगता है कि यह एक महान अभ्यास है। यह कोड के निष्पादन पर प्रभाव कम से कम है, लेकिन यह स्पष्टता कि यह प्रदान कर सकता है, अगर ठीक से उपयोग किया जाता है, तो कोड को बाद में बनाए रखने के लिए अमूल्य है।


1

अगर विधि को सफलता की एक अधिसूचना की आवश्यकता होती है: (c # में उदाहरण) मुझे इसका उपयोग करना पसंद है

bool success = false;

शुरू करना। जब तक मैं इसे नहीं बदलूंगा, तब तक कोड का एक फाल्स:

success = true;

फिर अंत में:

return success;

0

मुझे लगता है, यह इस बात पर निर्भर करता है कि आप / आपकी टीम किस शैली को पसंद करती है। "परिचय चर" रिफैक्टिंगिंग उपयोगी हो सकता है, लेकिन कभी-कभी :)

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

उदाहरण के लिए:

void DoSomeMethod(boolean needDelete) { ... }

// useful
boolean deleteOnCompletion = true;
if ( someCondition ) {
    deleteOnCompletion = false;
}
DoSomeMethod(deleteOnCompletion);

// useless
boolean shouldNotDelete = false;
DoSomeMethod(shouldNotDelete);

0

अपने अनुभव में, मैं अक्सर कुछ पुरानी लिपियों में लौट आया हूं और सोच रहा हूं कि 'आखिर मैं क्या सोच रहा था?' उदाहरण के लिए:

Math.p = function Math_p(a) {
    var r = 1, b = [], m = Math;
    a = m.js.copy(arguments);
    while (a.length) {
        b = b.concat(a.shift());
    }
    while (b.length) {
        r *= b.shift();
    }
    return r;
};

जो उतना सहज नहीं है:

/**
 * An extension to the Math object that accepts Arrays or Numbers
 * as an argument and returns the product of all numbers.
 * @param(Array) a A Number or an Array of numbers.
 * @return(Number) Returns the product of all numbers.
 */
Math.product = function Math_product(a) {
    var product = 1, numbers = [];
    a = argumentsToArray(arguments);
    while (a.length) {
        numbers = numbers.concat(a.shift());
    }
    while (numbers.length) {
        product *= numbers.shift();
    }
    return product;
};

-1। ईमानदार होने के लिए मूल प्रश्न के साथ यह थोड़ा करना है। सवाल एक अलग, बहुत विशिष्ट बात के बारे में है, सामान्य रूप से अच्छा कोड लिखने के बारे में नहीं।
पी शेव्ड

0

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

boolean processElement=false;
if (elementIndex < 0) // Do we have a valid element?
{
  processElement=true;
}
else if (elementIndex==lastElementIndex) // Is it the one we want?
{
  processElement=true;
}
if (processElement)
...

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.