क्या मुझे सामान्य रास्ते का अनुसरण करना चाहिए या जल्दी असफल होना चाहिए?


73

से कोड पूर्ण पुस्तक निम्नलिखित उद्धरण आता है:

"के बाद के ifबजाय सामान्य मामले रखो else"

जिसका अर्थ है कि मानक पथ से अपवाद / विचलन को elseमामले में डाल दिया जाना चाहिए ।

लेकिन द प्रोगैमैटिक प्रोग्रामर हमें "क्रैश जल्दी" (पी। 120) सिखाता है।

मुझे किस नियम का पालन करना चाहिए?


15
@gnat डुप्लिकेट नहीं
Bћовић

16
दो परस्पर अनन्य नहीं हैं, कोई अस्पष्टता नहीं है।
jwenting

6
मुझे इतना यकीन नहीं है कि कोड-कम्पलीट उद्धरण इतनी बढ़िया सलाह है। संभवत: यह पठनीयता बढ़ाने का एक प्रयास है, लेकिन निश्चित रूप से ऐसी परिस्थितियां हैं जहां आप असामान्य मामलों को पाठकीय रूप से पहले चाहते हैं। ध्यान दें कि यह एक उत्तर नहीं है; मौजूदा उत्तर पहले से ही आपके प्रश्न को अच्छी तरह से उपजा भ्रम को समझाते हैं।
ईमोन नेरबोन

14
क्रैश जल्दी, क्रैश कठिन! यदि आपकी एक ifशाखा वापस आती है, तो पहले इसका उपयोग करें। और elseबाकी कोड के लिए बचें , यदि आप पूर्व-शर्तें विफल हैं तो आप पहले ही लौट चुके हैं। कोड पढ़ना आसान है, कम इंडेंटेशन ...
CodeAngry

5
क्या यह सिर्फ मुझे लगता है कि इसका पठनीयता से कोई लेना-देना नहीं है, लेकिन इसके बजाय शायद स्थैतिक शाखा की भविष्यवाणी के अनुकूलन के लिए केवल एक भ्रामक प्रयास था?
मेहरदाद

जवाबों:


189

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

एक if/ elseनिर्माण में, केवल एक ब्लॉक निष्पादित होता है, इसलिए न तो "पहले" या "बाद में" कदम का गठन करने के लिए कहा जा सकता है। इसलिए उन्हें कैसे ऑर्डर किया जा सकता है यह पठनीयता का सवाल है, और "जल्दी असफल" निर्णय में प्रवेश नहीं करता है।


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

7
@ एंकेटर, ग्रैन्युलैरिटी का वह स्तर जितना आम तौर पर अभिप्रेत होता है, उससे कहीं अधिक छोटा होता है जब वाक्यांश "जल्दी असफल" होता है।
रिवलॉक २०'१४ को १

2
@Encaitar प्रोग्रामिंग की कला है। जब कई जांचों का सामना करना पड़ता है, तो विचार सबसे पहले सच होने की कोशिश करना है। हालाँकि, उस जानकारी को डिज़ाइन के समय पर नहीं बल्कि ऑप्टिमाइज़ेशन स्टेज पर जाना जा सकता है, लेकिन प्रीमेच्योर ऑप्टिमाइज़ेशन से सावधान रहें।
बीपीयूघ

निष्पक्ष टिप्पणी। यह एक अच्छा जवाब था और मैं केवल भविष्य के संदर्भ के लिए इसे बेहतर बनाने में मदद करने की कोशिश करना चाहता था
एंकेटर

जावास्क्रिप्ट, पायथन, पर्ल, पीएचपी, बैश आदि जैसी स्क्रिप्टिंग भाषाएं अपवाद हैं क्योंकि उनकी रेखीय व्याख्या की जाती है। छोटे if/elseनिर्माणों में यह शायद मायने नहीं रखता। लेकिन प्रत्येक ब्लॉक में एक लूप या कई बयानों के साथ बुलाए गए लोग पहले सबसे सामान्य स्थिति के साथ तेजी से दौड़ सकते हैं।
DocSalvager

116

यदि आपके elseबयान में केवल विफलता कोड है, तो सबसे अधिक संभावना है, यह नहीं होना चाहिए।

ऐसा करने के बजाय:

if file.exists() :
  if validate(file) :
    # do stuff with file...
  else :
    throw foodAtMummy
else :
  throw toysOutOfPram

यह करो

if not file.exists() :
  throw toysOutOfPram

if not validate(file) :
  throw foodAtMummy

# do stuff with file...

आप केवल त्रुटि जाँच को शामिल करने के लिए अपने कोड को गहराई से घोंसला नहीं बनाना चाहते हैं।

और, जैसा कि बाकी सभी ने पहले ही कहा है, सलाह के दो टुकड़े विरोधाभासी नहीं हैं। एक निष्पादन आदेश के बारे में है , दूसरा कोड आदेश के बारे में है ।


4
वर्थ स्पष्ट है कि ब्लॉक में सामान्य प्रवाह डालने के बाद सलाह ifऔर ब्लॉक में असाधारण प्रवाह के बाद elseलागू नहीं होता है यदि आपके पास ए नहीं है else! इस तरह के गार्ड स्टेटमेंट सबसे कोडिंग स्टाइल में त्रुटि की स्थिति से निपटने के लिए पसंदीदा फॉर्म है।
जूल्स

+1 यह एक अच्छा बिंदु है और वास्तव में त्रुटि स्थितियों के साथ सामान ऑर्डर करने के वास्तविक प्रश्न का उत्तर देता है।
ashes999

निश्चित रूप से बहुत स्पष्ट और बनाए रखने में आसान है। यह मुझे ऐसा करना पसंद है।
जॉन

27

आपको दोनों का अनुसरण करना चाहिए।

"क्रैश जल्दी" / प्रारंभिक सलाह विफल होने का मतलब है कि आपको जल्द से जल्द संभावित त्रुटियों के लिए अपने इनपुट का परीक्षण करना चाहिए।
उदाहरण के लिए, यदि आपकी विधि किसी ऐसे आकार या गिनती को स्वीकार करती है, जिसे सकारात्मक माना जाता है (> 0), तो असफल प्रारंभिक सलाह का अर्थ है कि आप उस स्थिति के लिए सही तरीके से परीक्षण कर रहे हैं, जो कि विधि के निर्माण के लिए एल्गोरिथ्म का इंतजार करने की बजाय आपके लिए सही है। परिणाम है।

पहले सामान्य मामले को डालने की सलाह का मतलब है कि यदि आप किसी स्थिति के लिए परीक्षण करते हैं, तो सबसे अधिक संभावना पथ पहले आना चाहिए। यह प्रदर्शन में मदद करता है (क्योंकि प्रोसेसर की शाखा भविष्यवाणी अक्सर अधिक सही होगी) और पठनीयता, क्योंकि आपको कोड के ब्लॉक पर छोड़ना नहीं पड़ता है जब यह पता लगाने की कोशिश की जाती है कि फ़ंक्शन सामान्य स्थिति में क्या कर रहा है।
यह सलाह वास्तव में लागू नहीं होती है जब आप एक पूर्व शर्त के लिए परीक्षण करते हैं और तुरंत (asserts या if (!precondition) throwconstructs का उपयोग करके ) जमानत करते हैं , क्योंकि कोड को पढ़ने के दौरान छोड़ने के लिए कोई त्रुटि हैंडलिंग नहीं है।


1
क्या आप शाखा भविष्यवाणी भाग पर विस्तार से बता सकते हैं? मुझे ऐसे कोड की उम्मीद नहीं होगी, जो उस मामले में जाने की संभावना है, जो कोड की तुलना में तेज़ी से चलेगा, जो दूसरे मामले में जाने की अधिक संभावना है। मेरा मतलब है, यह शाखा की भविष्यवाणी का पूरा बिंदु है, है ना?
रोमन रेनर

@ user136712: आधुनिक (तेज) प्रोसेसर में, पहले के निर्देश समाप्त होने के बाद निर्देश प्राप्त होते हैं। शाखा भविष्यवाणी का उपयोग इस संभावना को बढ़ाने के लिए किया जाता है कि सशर्त शाखा को निष्पादित करते समय प्राप्त किए गए निर्देश भी निष्पादित करने के लिए सही निर्देश हैं।
बार्ट वैन इनगेन शेनौ

2
मुझे पता है कि शाखा की भविष्यवाणी क्या है। यदि मैं आपकी पोस्ट को सही ढंग से पढ़ता हूं तो आप कहते हैं कि शाखा की भविष्यवाणी के कारण if(cond){/*more likely code*/}else{/*less likely code*/}तेजी से चलती है if(!cond){/*less likely code*/}else{/*more likely code*/}। मुझे लगता है कि शाखा की भविष्यवाणी ifया तो elseकथन का पक्षपाती नहीं है और केवल इतिहास को ध्यान में रखता है। इसलिए यदि elseऐसा होने की अधिक संभावना है, तो यह अनुमान लगाने में सक्षम होना चाहिए कि बस ठीक है। क्या यह धारणा झूठी है?
रोमन रेनर

18

मुझे लगता है कि @JackAidley ने पहले ही कहा था , लेकिन मुझे इसे इस तरह तैयार करना चाहिए:

अपवाद के बिना (जैसे C)

नियमित कोड प्रवाह में, आपके पास:

if (condition) {
    statement;
} else if (less_likely_condition) {
    less_likely_statement;
} else {
    least_likely_statement;
}
more_statements;

"जल्दी आउट होने की" स्थिति में, आपका कोड अचानक पढ़ता है:

/* demonstration example, do NOT code like this */
if (condition) {
    statement;
} else {
    error_handling;
    return;
}

आप इस पद्धति का पता है - एक returnएक में else(या if) ब्लॉक, इसे तुरंत फिर से काम तो सवाल में कोड है नहीं एक है elseब्लॉक:

/* only code like this at University, to please structured programming professors */
function foo {
    if (condition) {
        lots_of_statements;
    }
    return;
}

वास्तविक दुनिया में…

/* code like this instead */
if (!condition) {
    error_handling;
    return;
}
lots_of_statements;

यह बहुत गहरे घोंसले के शिकार से बचा जाता है और "ब्रेक आउट अर्ली" केस को पूरा करता है (दिमाग को रखने में मदद करता है - और कोड का प्रवाह - स्वच्छ) और " ifभाग में अधिक संभावना वाली चीज़" का उल्लंघन नहीं करता है क्योंकि बस कोई elseहिस्सा नहीं है ।

C और सफाई

इसी तरह के एक प्रश्न के उत्तर से प्रेरित होकर (जो कि यह गलत है), यहां आप सी के साथ सफाई कैसे करते हैं। आप वहां एक या दो निकास बिंदुओं का उपयोग कर सकते हैं, यहां दो निकास बिंदुओं के लिए एक है:

struct foo *
alloc_and_init(size_t arg1, int arg2)
{
    struct foo *res;

    if (!(res = calloc(sizeof(struct foo), 1)))
        return (NULL);

    if (foo_init1(res, arg1))
        goto err;
    res.arg1_inited = true;
    if (foo_init2(&(res->blah), arg2))
        goto err;
    foo_init_complete(res);
    return (res);

 err:
    /* safe because we use calloc and false == 0 */
    if (res.arg1_inited)
        foo_dispose1(res);
    free(res);
    return (NULL);
}

यदि आप कम सफाई करते हैं, तो आप उन्हें एक निकास बिंदु में ध्वस्त कर सकते हैं:

char *
NULL_safe_strdup(const char *arg)
{
    char *res = NULL;

    if (arg == NULL)
        goto out;

    /* imagine more lines here */
    res = strdup(arg);

 out:
    return (res);
}

यह उपयोग gotoपूरी तरह से ठीक है, अगर आप इससे निपट सकते हैं; उपयोग करने से दूर रहने की सलाह gotoउन लोगों पर निर्देशित की जाती है जो अभी तक स्वयं तय नहीं कर सकते हैं कि क्या उपयोग अच्छा, स्वीकार्य, बुरा, स्पेगेटी कोड, या कुछ और है।

अपवाद

उपरोक्त अपवादों के बिना भाषाओं के बारे में बात करते हैं, जो मैं खुद को बहुत पसंद करता हूं (मैं स्पष्ट रूप से बेहतर हैंडलिंग त्रुटि का उपयोग कर सकता हूं, और बहुत कम आश्चर्य के साथ)। Igli बोली के लिए:

<igli> exceptions: a truly awful implementation of quite a nice idea.
<igli> just about the worst way you could do something like that, afaic.
<igli> it's like anti-design.
<mirabilos> that too… may I quote you on that?
<igli> sure, tho i doubt anyone will listen ;)

लेकिन यहाँ एक सुझाव है कि आप इसे अपवाद वाली भाषा में कैसे अच्छा करते हैं, और जब आप उन्हें अच्छी तरह से उपयोग करना चाहते हैं:

अपवादों का सामना करने में त्रुटि

आप returnअपवाद को फेंकने के साथ अधिकांश शुरुआती एस को बदल सकते हैं। हालाँकि , आपका सामान्य प्रोग्राम फ्लो, अर्थात कोई भी कोड प्रवाह जिसमें प्रोग्राम का सामना नहीं हुआ, ठीक है, एक अपवाद ... एक त्रुटि स्थिति या सोमेसिक, कोई अपवाद नहीं बढ़ाएगा।

इस का मतलब है कि…

# this page is only available to logged-in users
if not isLoggedIn():
    # this is Python 2.5 style; insert your favourite raise/throw here
    raise "eh?"

… ठीक है, लेकिन…

/* do not code like this! */
try {
    openFile(xyz, "rw");
} catch (LockedException e) {
    return "file is locked";
}
closeFile(xyz);
return "file is not locked";

… नहीं है। असल में, एक अपवाद एक नियंत्रण प्रवाह तत्व नहीं है । इससे ऑपरेशन भी आपको अजीब लगते हैं ("उन जावा ™ प्रोग्रामर हमेशा हमें बताते हैं कि ये अपवाद सामान्य हैं") और डिबगिंग में बाधा डाल सकते हैं (उदाहरण के लिए आईडीई को किसी भी अपवाद को तोड़ने के लिए कहें)। अपवाद को अक्सर ट्रेसबैक का उत्पादन करने के लिए स्टैक को खोलने के लिए रन-टाइम वातावरण की आवश्यकता होती है, आदि इसके खिलाफ संभवतः अधिक कारण हैं।

यह उबलता है: अपवादों का समर्थन करने वाली भाषा में, मौजूदा तर्क और शैली से जो भी मेल खाता है उसका उपयोग करें और प्राकृतिक महसूस करें। यदि स्क्रैच से कुछ लिखना है, तो इस पर जल्दी सहमत हों। यदि स्क्रैच से लाइब्रेरी लिखना है, तो अपने उपभोक्ताओं के बारे में सोचें। (कभी भी, abort()पुस्तकालय में उपयोग न करें ...) लेकिन आप जो भी करते हैं, अंगूठे के नियम के रूप में नहीं करते हैं, यदि अपवाद सामान्य रूप से इसके बाद भी (कम या ज्यादा) जारी रहता है, तो इसका अपवाद है।

सामान्य सलाह। अपवाद

पहले पूरी देव टीम द्वारा सहमत किए गए अपवादों के सभी इन-प्रोग्राम उपयोग को प्राप्त करने का प्रयास करें। मूल रूप से, उन्हें योजना। इनका भरपूर मात्रा में उपयोग न करें। कभी-कभी, C ++, Java ™, पायथन में भी, एक त्रुटि वापसी बेहतर होती है। कभी-कभी यह नहीं है; विचार के साथ उनका उपयोग करें।


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

1
@ डनमैन: मेरा लेख सी के साथ लिखा गया था ... मैं आमतौर पर अपवाद का उपयोग नहीं करता हूं। लेकिन मैंने लेख को एक के साथ बढ़ाया है (उफ़, यह बहुत लंबा हो गया) सुझाव wrt। अपवाद; संयोग से, कल कंपनी की आंतरिक देव मेलिंग सूची पर हमारा वही सवाल था ...
मिराबिलोस

इसके अलावा, एक-पंक्ति ifs और fors पर भी ब्रेसिज़ का उपयोग करें। आप goto fail;पहचान में छिपा दूसरा नहीं चाहते हैं ।
ब्रूनो किम

1
@BrunoKim: यह पूरी तरह से आपके द्वारा काम करने वाली परियोजना की शैली / कोडिंग सम्मेलन पर निर्भर करता है। मैं बीएसडी के साथ काम करता हूं, जहां इस पर (अधिक ऑप्टिक अव्यवस्था और ऊर्ध्वाधर स्थान का नुकसान) होता है; $ डेजॉब में हालांकि मैं उन्हें जगह देता हूं क्योंकि हम सहमत थे (जैसा कि आपने कहा था कि नए मुश्किलों के लिए कम, त्रुटियों की संभावना कम है, आदि)।
मिराबिलोस

3

मेरी राय में 'गार्ड कंडीशन' कोड को पठनीय बनाने के सर्वोत्तम और आसान तरीकों में से एक है। मैं वास्तव में नफरत करता हूं जब मैं ifविधि की शुरुआत में देखता हूं और elseकोड नहीं देखता क्योंकि यह स्क्रीन से दूर है। मुझे सिर्फ देखने के लिए नीचे स्क्रॉल करना होगा throw new Exception

चेकों को शुरुआत में रखें ताकि पढ़ने वाले व्यक्ति को इसे पढ़ने के लिए पूरी विधि से कूदना न पड़े, बल्कि इसे हमेशा ऊपर से नीचे तक स्कैन करें।


2

(@mirabilos 'का उत्तर उत्कृष्ट है, लेकिन यहां मैं उसी निष्कर्ष पर पहुंचने के लिए सवाल के बारे में कैसे सोचता हूं :)

मैं अपने (या किसी और के बारे में) बाद में अपने फ़ंक्शन के कोड को पढ़ रहा हूं। जब मैं पहली पंक्ति पढ़ता हूं, तो मैं अपने इनपुट के बारे में कोई धारणा नहीं बना सकता (सिवाय उन लोगों को छोड़कर, जिनकी मैं वैसे भी जाँच नहीं करूंगा)। तो मेरा विचार है "ठीक है, मुझे पता है कि मैं अपने तर्कों के साथ काम करने जा रहा हूं। लेकिन पहले चलो 'उन्हें साफ करें' - यानी नियंत्रण पथ को मारें जिसमें वे मेरी पसंद के अनुसार नहीं हैं।" लेकिन एक ही समय में। , मैं सामान्य मामले को किसी ऐसी चीज के रूप में नहीं देखता हूं, जो मैं सामान्य होने पर जोर देना चाहता हूं।

int foo(int* bar, int baz) {

   if (bar == NULL) /* I don't like you, leave me alone */;
   if (baz < 0) /* go away */;

   /* there, now I can do the work I came into this function to do,
      and I can safely forget about those if's above and make all 
      the assumptions I like. */

   /* etc. */
}

-3

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

दूसरे शब्दों में:

ए। महत्वपूर्ण खंड और कोई चूक नहीं => प्रारंभिक विफलता

B. गैर-महत्वपूर्ण अनुभाग और चूक => किसी अन्य भाग में चूक का उपयोग करें

C. मामलों के बीच => आवश्यकतानुसार प्रति केस तय करें


क्या यह केवल आपकी राय है या आप इसे किसी तरह समझा सकते हैं / वापस कर सकते हैं?
gnat

यह वास्तव में कैसे बैकअप नहीं है, जैसा कि प्रत्येक विकल्प बताता है (वास्तव में कई शब्दों के बिना) इसका उपयोग क्यों किया जाता है?
निकोस एम।

मैं यह कहना नहीं चाहूंगा, लेकिन इस उत्तर में (मेरे) डाउनवोट्स आउट-ऑफ-संदर्भ हैं :)। यह वह प्रश्न है जो ओपी ने पूछा है, क्या आपके पास वैकल्पिक उत्तर है एक और मामला है
निकोस एम।

मैं ईमानदारी से यहां की व्याख्या को देखने में विफल हूं। कहते हैं, अगर कोई अन्य राय लिखता है, जैसे "क्रिटिकल सेक्शन और नो डिफॉल्ट्स => डोंट फेल अर्ली" , तो यह उत्तर कैसे पाठक को दो विरोधी राय लेने में मदद करेगा? दिशानिर्देशों को कैसे उत्तर दें , इसे बेहतर आकार में संपादित करने पर विचार करें
gnat

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