वैज्ञानिक पुस्तकालयों में त्रुटियों की सूचना कैसे दी जानी चाहिए?


11

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

  1. सूचक तर्क द्वारा दिए गए परिणाम के साथ एक त्रुटि कोड लौटाएं। पेट्सक यही करता है।
  2. प्रहरी मूल्य द्वारा वापसी त्रुटियों। उदाहरण के लिए, मॉलॉक NULL लौटाता है यदि यह मेमोरी आवंटित नहीं कर सकता है, sqrtतो NaN लौटाएगा यदि आप एक ऋणात्मक संख्या में गुजरते हैं, आदि। इस दृष्टिकोण का उपयोग कई परिवाद कार्यों में किया जाता है।
  3. अपवाद फेंको। डील में इस्तेमाल किया। II, ट्रिलिनो, आदि।
  4. एक प्रकार की वापसी; उदाहरण के लिए C ++ फ़ंक्शन जो किसी प्रकार की वस्तु लौटाता है Resultयदि वह सही ढंग से चलता है और Errorयह कैसे विफल हो जाता है इसका वर्णन करने के लिए एक प्रकार का उपयोग करता है std::variant<Error, Result>
  5. मुखर और दुर्घटना का उपयोग करें। P4est और igraph के कुछ भागों में उपयोग किया जाता है।

प्रत्येक दृष्टिकोण के साथ समस्याएं:

  1. हर त्रुटि के लिए जाँच करने से बहुत सारे अतिरिक्त कोड मिलते हैं। जिन मूल्यों में परिणाम संग्रहीत किया जाएगा उन्हें हमेशा पहले घोषित करना होगा, बहुत सारे अस्थायी चर पेश किए जाएंगे जो केवल एक बार उपयोग किए जा सकते हैं। यह दृष्टिकोण बताता है कि क्या त्रुटि हुई, लेकिन यह निर्धारित करना कठिन हो सकता है कि क्यों, या, एक गहरी कॉल स्टैक के लिए, कहां।
  2. त्रुटि मामले को अनदेखा करना आसान है। यदि उत्पादन के प्रकारों की पूरी श्रृंखला एक प्रशंसनीय परिणाम है, तो उसके शीर्ष पर, कई कार्यों का सार्थक प्रहरी मूल्य भी नहीं हो सकता है। # 1 जैसी ही कई समस्याएं।
  3. केवल C ++, Python आदि में ही संभव है, C या Fortran में नहीं। सेटजम्प / लॉन्गजम्प टोना या लिबुनविंड का उपयोग करके सी में नकल की जा सकती है ।
  4. केवल C ++, Rust, OCaml इत्यादि में ही संभव है, C या Fortran में नहीं। मैक्रो टोना का उपयोग करके सी में नकल की जा सकती है।
  5. संभवतः सबसे अधिक जानकारीपूर्ण। लेकिन अगर आप इस दृष्टिकोण को अपनाते हैं, तो एक सी लाइब्रेरी, जिसे आप तब के लिए पायथन रैपर लिखते हैं, एक सरणी में एक आउट-ऑफ-बाउंड्स इंडेक्स पास करने जैसी मूर्खतापूर्ण गलती पायथन दुभाषिया को दुर्घटनाग्रस्त कर देगी।

त्रुटि-हैंडलिंग के बारे में इंटरनेट पर अधिकांश सलाह ऑपरेटिंग सिस्टम, एम्बेडेड विकास या वेब अनुप्रयोगों के दृष्टिकोण से लिखी गई हैं। दुर्घटनाएं अस्वीकार्य हैं और आपको सुरक्षा के बारे में चिंता करनी होगी। वैज्ञानिक अनुप्रयोगों में ये समस्याएँ लगभग एक ही सीमा तक नहीं होती हैं, यदि हो।

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

वैज्ञानिक पुस्तकालयों को त्रुटियों की रिपोर्ट कैसे करनी चाहिए और उनसे निपटने की अपेक्षा करनी चाहिए? मुझे निश्चित रूप से पता है कि यह इस बात पर निर्भर करता है कि लाइब्रेरी किस भाषा में लागू की गई है। लेकिन जहाँ तक मैं बता सकता हूँ कि किसी भी पर्याप्त रूप से उपयोगी पुस्तकालय के लिए, लोग इसे जिस भाषा में लागू करते हैं, उसके अलावा कुछ अन्य भाषा से इसे कॉल करना चाहेंगे।

एक तरफ के रूप में, मुझे लगता है कि सार्वजनिक पुस्तकालय के हिस्से के रूप में एक वैश्विक पुस्तकालय हैंडलर फ़ंक्शन पॉइंटर को परिभाषित करने पर # 5 को सी लाइब्रेरी के लिए काफी सुधार किया जा सकता है। अभिकर्ता हैंडलर रिपोर्टिंग फ़ाइल / लाइन नंबर और दुर्घटनाग्रस्त होने के लिए डिफ़ॉल्ट होगा। इस लाइब्रेरी के लिए C ++ बाइंडिंग एक नए मुखर हैंडलर को परिभाषित करेगा जो इसके बजाय C ++ अपवाद फेंकता है। इसी तरह, पायथन बाइंडिंग एक मुखर हैंडलर को परिभाषित करेगा जो पायथन अपवाद को फेंकने के लिए सीपीथॉन एपीआई का उपयोग करता है। लेकिन मुझे ऐसा कोई उदाहरण नहीं पता है जो इस दृष्टिकोण को ले।


एक और विचार प्रदर्शन प्रभाव है। ये विभिन्न विधियां सॉफ्टवेयर की गति को कैसे प्रभावित करती हैं? क्या हमें कोड के "नियंत्रण" भागों में विभिन्न त्रुटि हैंडलिंग (जैसे इनपुट फ़ाइलों को संसाधित करना) बनाम कम्प्यूटेशनल रूप से महंगे "इंजन" का उपयोग करना चाहिए?
लेडहेड

ध्यान दें कि सबसे अच्छा उत्तर भाषा से अलग होगा।
चिरलीस-स्ट्राइक-

जवाबों:


10

मैं आपको अपना दृष्टिकोण दूंगा, जो कि आपके संदर्भ में डील.II प्रोजेक्ट में एन्कोडेड है।

सबसे पहले, दो प्रकार की त्रुटि स्थितियां हैं: त्रुटियां जिनसे पुनर्प्राप्त किया जा सकता है, और उन त्रुटियों से जिन्हें पुनर्प्राप्त नहीं किया जा सकता है।

  • पूर्व है, उदाहरण के लिए, यदि कोई इनपुट फ़ाइल नहीं पढ़ी जा सकती है - उदाहरण के लिए यदि आप किसी फ़ाइल से जानकारी पढ़ रहे हैं जैसे $HOME/.dealiiकि मौजूद हो सकती है या हो सकती है। रीडिंग फ़ंक्शन को बाद के लिए कॉलिंग फ़ंक्शन पर वापस जाना चाहिए ताकि यह पता चल सके कि क्या करना है। यह भी हो सकता है कि एक संसाधन इस समय उपलब्ध नहीं है, लेकिन एक मिनट में फिर से हो सकता है (दूरस्थ रूप से माउंट की गई फ़ाइल सिस्टम)।

  • उत्तरार्द्ध, उदाहरण के लिए, यदि आप 10 के आकार के वेक्टर को 20 के वेक्टर में जोड़ने का प्रयास कर रहे हैं: जैसा कि आप कर सकते हैं, कोशिश करें, इस बारे में कुछ भी नहीं किया जा सकता है - कोड में एक बग है जिसके कारण वह बिंदु जहां हमने इसके अतिरिक्त प्रयास किया।

इन दो स्थितियों को अलग तरह से व्यवहार किया जाना चाहिए, भले ही आप जिस प्रोग्रामिंग भाषा का उपयोग कर रहे हों:

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

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

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

मैं ध्यान दूंगा कि कुछ सिस्टम सिर्फ क्रैश नहीं होने चाहिए, यहां तक ​​कि उन मामलों में भी जहां त्रुटियां पुनर्प्राप्त करने योग्य नहीं हैं। एक उदाहरण यह है कि कार्यों के एक सेट को कई प्रश्नों के लिए बार-बार कहा जाता है - कहते हैं, सांख्यिकीय नमूनाकरण योजना में दिए गए इनपुट के लिए संभावना फ़ंक्शन का मूल्यांकन करने के लिए। हो सकता है कि मूल्यांकनकर्ता नकारात्मक मूल्यों से निपट नहीं सकता क्योंकि समस्या उस स्थिति में कोई मतलब नहीं रखती है (जैसे, मोटाई की धातु की प्लेट की कठोरता का मूल्यांकन करनाएक्स), लेकिन चूंकि मूल्यांकनकर्ता को बार-बार कॉल करने की आवश्यकता होती है, इसलिए इसे केवल क्रैश नहीं करना चाहिए, बल्कि बस एक अपवाद फेंकना चाहिए। ऐसे मामलों में, भले ही एक नकारात्मक मूल्य में गुजरने योग्य नहीं है, किसी को कार्यक्रम को रद्द करने के बजाय एक अपवाद फेंक देना चाहिए। मैंने कुछ साल पहले इस रुख से असहमति जताई थी, लेकिन एक्सएसडीके कम्युनिटी सॉफ्टवेयर दिशानिर्देशों की आवश्यकता के कारण मेरा मन बदल गया है कि प्रोग्राम को कभी भी क्रैश नहीं होना चाहिए (या कम से कम दुर्घटना से अपवाद को स्विच करने का एक तरीका होना चाहिए - इसलिए सौदा। II में अब Assertकॉल करने के बजाय एक अपवाद फेंकने का विकल्प है abort()।)


मैं बस इसके विपरीत की सिफारिश करूंगा: जब स्थिति को नियंत्रित नहीं किया जा सकता है तो एक अपवाद को फेंक दें और जब इसे संभाला जा सकता है तो त्रुटि कोड लौटाएं। समस्या यह है कि फेंके गए अपवादों से निपटना मुश्किल है: एप्लिकेशन प्रोग्रामर को उन्हें पकड़ने और संभालने के लिए सभी संभावित अपवादों का प्रकार पता होना चाहिए, अन्यथा कार्यक्रम बस दुर्घटनाग्रस्त हो जाएगा। दुर्घटनाग्रस्त होना ठीक है और यहां तक ​​कि उन परिस्थितियों के लिए भी स्वागत है जिन्हें संभाला नहीं जा सकता है, क्योंकि दुर्घटनाग्रस्त बिंदु को अजगर के साथ आउट-ऑफ-द-बॉक्स बताया जाता है, उदाहरण के लिए, लेकिन उन परिस्थितियों के लिए जिन्हें संभाला जा सकता है, यह (ज्यादातर) स्वागत नहीं है।
cdalitz

@ LCDalitz: यह C ++ का डिज़ाइन दोष है जिसे आप किसी भी प्रकार की वस्तुओं को फेंक सकते हैं। लेकिन कोई भी उचित सॉफ्टवेयर (ट्रिलिनो को बाहर रखा गया) केवल अपवाद हैं जो कि व्युत्पन्न हैं std::exception, और ये व्युत्पन्न प्रकार को जाने बिना संदर्भ द्वारा पकड़े जा सकते हैं।
वोल्फगैंग बैंगर्थ

1
लेकिन मैं मूल प्रश्न में उल्लिखित कारणों के लिए एक त्रुटि कोड वापस करने से दृढ़ता से असहमत हूं: (i) त्रुटि कोड को बहुत बार नजरअंदाज कर दिया जाता है, और परिणामस्वरूप त्रुटियों को बिल्कुल भी नियंत्रित नहीं किया जाता है; (ii) कई मामलों में, कोई असाधारण मूल्य नहीं है जो कि यथोचित रूप से वापस किया जा सकता है ताकि फ़ंक्शन का रिटर्न प्रकार तय हो; (iii) फ़ंक्शन के अलग-अलग रिटर्न प्रकार होते हैं, और आपको प्रत्येक मामले में अलग-अलग परिभाषित करना होगा कि "असाधारण" मूल्य क्या होगा जो एक त्रुटि का प्रतिनिधित्व करता है।
वोल्फगैंग बैंगर्थ

WB ने लिखा (क्षमा करें, '@' चाल किसी कारण से काम नहीं करती है और उपयोगकर्ता नाम किसी कारण से StackExchage द्वारा हटा दिया जाता है): "त्रुटि कोड को बहुत बार अनदेखा किया जाता है"। अपवाद पकड़ने के लिए यह और भी अधिक है: बहुत से सॉफ्टवेयर डेवलपर्स एक कोशिश / कैच ब्लॉक में हर फ़ंक्शन कॉल को ब्रैकेट करने की परेशानी नहीं लेते हैं। लेकिन यह ज्यादातर स्वाद का मामला है: जब तक प्रलेखन स्पष्ट रूप से बताता है कि क्या और कौन सा अपवाद एक कार्य फेंकता है, मैं इसे संभाल सकता हूं। लेकिन फिर से यह कहा जा सकता है: प्रलेखन लिखने के लिए कर्तव्य को बहुत बार नजरअंदाज कर दिया जाता है ;-)
cdalitz

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