c++ - मुझे दावे क्यों करना चाहिए?




performance assertions (12)

"अपरिहार्य केल्विन और बूब्स" के उद्धरण का विरोध नहीं कर सकते। 180:

इस तरह एक खड़ी पहाड़ी से नीचे जाने से पहले, हमेशा अपने स्लेज को एक सुरक्षा जांच देना चाहिए।
सही।
सीट बेल्ट ? कोई नहीं।
संकेत? कोई नहीं।
ब्रेक? कोई नहीं।
स्टीयरिंग? कोई नहीं।
WHEEEEEE

मुझे कभी भी इस बात का विचार नहीं आया - आप कभी भी उनका उपयोग क्यों करें?

मेरा मतलब है, मान लें कि मैं एक सूत्र चालक था और सभी मुखर सुरक्षा बेल्ट, हेलमेट आदि जैसी चीजें थीं।

परीक्षण (डिबग में) सभी ठीक थे, लेकिन अब हम रेसिंग (रिलीज़) करना चाहते हैं! क्या हमें सभी सुरक्षा को छोड़ देना चाहिए, क्योंकि परीक्षण के दौरान कोई समस्या नहीं थी?

मैं उन्हें कभी नहीं हटाऊंगा। मुझे लगता है कि दावा करने वाले अधिकांश लोग यह दावा करते हैं कि मुखर करने के लिए तुलनीय चीज को हटाने से उनके कोड को कभी भी अप्रूव्ड नहीं किया गया या मुखर पूर्ण विस्थापित नहीं हुए। मैंने विशेष रूप से 80/20 नियम के संबंध में कोई वास्तविक प्रदर्शन लाभ नहीं देखा है।

तो, क्या मुझे किसी तरह की बात याद आ रही है, या कोई मुझे बता सकता है, मुझे क्यों जोर देना चाहिए? वैसे, मैं यूनिट परीक्षणों का उपयोग कर रहा हूं।


अपनी पोस्ट से, ऐसा लगता है कि आप मुखरता का उपयोग करने के विचार से असहमत नहीं हैं, बल्कि डिबग में जोर देने और उन्हें उत्पादन में सक्रिय नहीं होने के विचार से सहमत हैं।

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

अभिकथन का उपयोग करने से आप डिबग और रिलीज़ के बीच के व्यवहार को बदल सकते हैं।

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


कोड पूरा 2 से: "उन स्थितियों के लिए त्रुटि-हैंडलिंग का उपयोग करें, जो आप होने की उम्मीद करते हैं; उन स्थितियों के लिए दावे का उपयोग करें जो कभी नहीं होनी चाहिए।"

आम तौर पर उद्धृत उदाहरण एक विभाजन से पहले हर में शून्य के लिए जाँच कर रहा है।

आपसे अपेक्षा है कि उत्पादन कोड से अभिकथन करें। वे गलतियों को पकड़ने में आपकी मदद करने के लिए विकास के दौरान वहां हैं।

इकाई परीक्षण जोर के लिए एक प्रतिस्थापन नहीं हैं।


कोड में पूर्ण एक ऐसा खंड है जो कुछ ऐसा कहता है। हर बार जब आप लिखते हैं तो बिना किसी और चीज़ के आपको कुछ याद आ रहा है।

यह इस कोड की तरह है

int i = 1
i = i++ 

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

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

मैं आपसे सहमत हूं कि उत्पादन कोड में अक्षम दावे, बल्कि बेकार कर देते हैं। और जावा vm के मामले में डिफ़ॉल्ट दावे से मेरी राय में खतरा है।


जब आप ऐसा कुछ करते हैं तो मुखरता का उपयोग किया जाना चाहिए

a = set()
a.add('hello')
assert 'hello' in a

या

a = 1;
assert a == 1; // if ram corruption happened and flipped the bit, this is the time to assert

अपवादों के रूप में, यह ऐसा कुछ है जिससे आप प्रोग्राम करते हैं:

while True:
  try:
    data = open('sample.file').read()
    break // successfully read
  except IOError:
    // disk read fail from time to time.. so retry
    pass

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


मुझे लगता है कि रिफ्लेक्टर करते समय दावे अमूल्य हैं। यदि आप एल्‍गोरिथम 1 () को अल्‍गोरिदम 2 () से बदलना चाहते हैं, तो आप उन दोनों के परिणाम बराबर होने पर जोर दे सकते हैं। आप फिर धीरे-धीरे एल्गोरिदम 1 () का चरण समाप्त कर सकते हैं

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

यह बहस का विषय है कि क्या मैक्रोज़ या रिलीज़ में लाइक के ज़रिए ऐसेट्स छीन लिए जाएं, लेकिन मैंने अब तक जिन प्रोजेक्ट्स में काम किया है, उनमें यही किया गया है।


मैं इसे ज्यादातर विकास के दौरान परीक्षणों के लिए उपयोग करता हूं। उदाहरण के लिए, यहां मेरी utf-8 लाइब्रेरी का स्मोक टेस्ट है। जब भी मैं लाइब्रेरी कोड में बदलाव करता हूं, तो मैं परीक्षण चलाता हूं और यदि बग को पेश किया जाता है तो एक ट्रिगर होगा। बेशक, मैं एक पूर्ण विकसित इकाई परीक्षण ढांचे का उपयोग कर सकता था, लेकिन मेरे उद्देश्यों के लिए सिर्फ ठीक हैं।


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

इससे भी महत्वपूर्ण बात, मैंने कोड लिखा है जहाँ अभिकथनों ने कोड के आकार के लिए दसियों प्रतिशत अंक का अंतर किया। जब स्मृति पदचिह्न एक मुद्दा है, तो रिलीज कोड में जोर शायद एक अस्वीकार्य अपव्यय है।


यह एक विवादास्पद विषय है। कई लोग, खुद की तरह, वास्तव में उन्हें उत्पादन कोड में छोड़ना पसंद करते हैं। यदि आपका कार्यक्रम वैसे भी मातम में जा रहा है, तो आपके पास इसमें जोर भी हो सकता है, ताकि आपका ग्राहक कम से कम आपको लाइन नंबर और फ़ाइल नाम दे सके (या जो भी जानकारी या क्रिया आप करने के लिए मुखर को कॉन्फ़िगर करते हैं)। यदि आपने दावे को छोड़ दिया, तो सभी ग्राहक आपको रिपोर्ट कर सकते हैं कि "यह दुर्घटनाग्रस्त हो गया"।

इसका मतलब है कि आपको अपने मुखर जांचों में महंगा ऑपरेशन नहीं करना चाहिए, या कम से कम यह देखने के लिए कि क्या वे प्रदर्शन समस्याओं का कारण बनने जा रहे हैं।


रिलीज़ के दौरान ज़रूरी नहीं कि विकास के दौरान स्थितियों को जाँचने के लिए ही आवेषण का उपयोग किया जाना चाहिए।

यहाँ एक बहुत ही सरल उदाहरण है कि कैसे विकास में जोर दिया जा सकता है।

A(char* p)
{
    if(p == NULL)
        throw exception;

    B(p);
    C(p);

}

B(char* p)
{
    assert(p != NULL);
    D(p);
    do stuff;
}

C(char* p)
{
    assert(p != NULL);
    D(p);
    do stuff;
}

D(char* p)
{
    assert(p != NULL);
    do stuff;
}

कॉल करने के बजाय "if (p == NULL) अपवाद छोड़ें?" 5 बार, आप इसे केवल एक बार कॉल करते हैं ताकि आप पहले से ही जानते हों कि यह B (), C (), और D () दर्ज करने पर NULL नहीं है। अन्यथा, एक जोर विकास चरण में निकल जाएगा क्योंकि आपने "कोड बदल दिया है!" एक "उपयोगकर्ता के इनपुट" के कारण नहीं।

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


सबसे पहले, प्रदर्शन अंतर बहुत बड़ा हो सकता है। एक परियोजना में हमारे जोर-जोर से एक 3x मंदी का कारण बना। लेकिन उन्होंने हमें कुछ वास्तव में अजीब बग को उजागर करने में मदद की।

जो बिल्कुल बिंदु है।

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

यहां तक ​​कि त्रुटि को पकड़ना और अपवाद को फेंकना वास्तव में समाधान नहीं है। कार्यक्रम का तर्क त्रुटिपूर्ण है, और भले ही हम अपवाद को संभाल लें, लेकिन कार्यक्रम अभी भी टूटा हुआ है।

मूल रूप से जो उबलता है, वह यह है कि "परेशान करने वाली त्रुटियों को क्यों आप संभाल नहीं सकते?"

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

मुझे कभी भी इस बात का विचार नहीं आया - आप कभी भी उनका उपयोग क्यों करें?

मेरा मतलब है, मान लें कि मैं एक सूत्र चालक था और सभी मुखर सुरक्षा बेल्ट, हेलमेट आदि जैसी चीजें थीं।

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

लेकिन जांच के बारे में क्या देखना है कि इंजन स्थापित है? क्या हमें दौड़ के दौरान जांचने की आवश्यकता है?

बिलकूल नही। यदि हम बिना इंजन के दौड़ में शामिल हो जाते हैं, तो हम घबरा जाते हैं, और यदि हम त्रुटि का पता लगाते हैं, तो भी इसके बारे में कुछ भी करने में देर हो जाती है।

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

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

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

चार के वर्गमूल को कभी तीन का मूल्यांकन नहीं करना चाहिए। त्रुटि बस असंभव है। यदि ऐसा होता है, तो आपका प्रोग्राम तर्क बस टूट गया है। इससे कोई फर्क नहीं पड़ता कि हम अपने चारों ओर कितनी त्रुटि को संभालते हैं, यह ऐसा कुछ है जिसे विकास के दौरान पकड़ा जाना चाहिए या बिल्कुल नहीं। यदि हमने इस त्रुटि की जांच करने और इसे संभालने के लिए अपवाद हैंडलिंग का उपयोग किया है, तो अपवाद क्या होने जा रहा है? उपयोगकर्ता को बताएं "कार्यक्रम मौलिक रूप से टूट गया है। कभी इसका उपयोग न करें"?

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

लेकिन कुछ त्रुटियां, जैसे पढ़ने के लिए फ़ाइल खोलने में असमर्थ होना, संभव है । भले ही यह एक बुरी चीज हो सकती है अगर ऐसा होता है, तो हमें यह स्वीकार करना होगा कि यह हो सकता है। इसलिए हमें इसे संभालने की जरूरत है।

जोर लगाने वाले त्रुटियों को पकड़ने के लिए हैं जो संभवतः नहीं हो सकते हैं।


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

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

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






assertions