मुझे अमान्य उपयोगकर्ता इनपुट को कैसे संभालना चाहिए?


12

मैं कुछ समय से इस मुद्दे के बारे में सोच रहा था और मैं अन्य डेवलपर्स से राय लेने के लिए उत्सुक था।

मेरे पास प्रोग्रामिंग की एक बहुत ही रक्षात्मक शैली है। मेरा विशिष्ट ब्लॉक या तरीका इस तरह दिखता है:

T foo(par1, par2, par3, ...)
{
    // Check that all parameters are correct, return undefined (null)
    // or throw exception if this is not the case.

    // Compute and (possibly) return result.
}

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

इसे और अधिक अमूर्त तरीके से रखने के लिए, मेरा दृष्टिकोण है

if all input is OK --> compute result
else               --> do not compute result, notify problem

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

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

सारांश

गलत इनपुट से निपटने के लिए आप दोनों में से कौन सा दृष्टिकोण सुझाएगा?

Inconsistent input --> no action + notification

या

Inconsistent input --> undefined behaviour or crash

संपादित करें

उत्तर और सुझाव के लिए धन्यवाद। मैं अनुबंध से भी डिजाइन का प्रशंसक हूं। लेकिन यहां तक ​​कि अगर मुझे उस व्यक्ति पर भरोसा है जिसने मेरे तरीकों को कॉल करने वाले कोड को लिखा है (शायद यह खुद है), अभी भी बग हो सकते हैं, जिससे गलत इनपुट हो सकता है। इसलिए मेरा दृष्टिकोण यह है कि किसी विधि को सही इनपुट पारित न किया जाए।

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

वैसे भी, मैं वास्तव में आश्चर्यचकित था कि कई लोग विपरीत दृष्टिकोण का पालन करते हैं: उन्होंने एप्लिकेशन को "ऑन-उद्देश्य" को क्रैश कर दिया क्योंकि वे बनाए रखते हैं कि इससे परीक्षण के दौरान बग ढूंढना आसान हो जाएगा।


हमेशा रक्षात्मक रूप से कोड। आखिरकार, प्रदर्शन के कारण, आप रिलीज़ मोड में कुछ परीक्षणों को अक्षम करने के लिए स्विच लगा सकते हैं।
deadalnix

आज मैंने एक लापता NULL पॉइंटर चेक से संबंधित बग तय किया है। एप्लिकेशन लॉग आउट के दौरान कुछ ऑब्जेक्ट बन गए और कंस्ट्रक्टर ने किसी अन्य ऑब्जेक्ट को एक्सेस करने के लिए एक गेट्टर का उपयोग किया जो कि कोई और नहीं था। वस्तु उस बिंदु पर निर्मित होने के लिए नहीं थी। इसे किसी अन्य बग के कारण बनाया गया था: लॉग आउट के दौरान कुछ टाइमर बंद नहीं किया गया था -> एक सिग्नल भेजा गया था -> प्राप्तकर्ता ने एक ऑब्जेक्ट बनाने की कोशिश की -> कंस्ट्रक्टर ने किसी अन्य ऑब्जेक्ट को क्वेरी और उपयोग किया -> NULL पॉइंटर -> क्रैश )। मैं वास्तव में यह पसंद नहीं करूंगा कि ऐसी खराब स्थिति मेरे आवेदन को क्रैश कर दे।
जियोर्जियो

1
मरम्मत का नियम: जब आपको असफल होना चाहिए, तब तक और जितनी जल्दी हो सके असफल हो जाएं।
deadalnix

"मरम्मत का नियम: जब आपको असफल होना चाहिए, तब तक और जितनी जल्दी हो सके असफल हो जाएं।": मुझे लगता है कि वे सभी विंडोज 'बीएसओडी' इस नियम का एक अनुप्रयोग हैं। :-)
जियोर्जियो

जवाबों:


8

आपने इसे ठीक कर लिया है। पागल हो। अन्य कोड पर भरोसा न करें, भले ही यह आपका अपना कोड हो। आप चीजों को भूल जाते हैं, आप बदलाव करते हैं, कोड विकसित होता है। कोड के बाहर भरोसा मत करो।

ऊपर एक अच्छा बिंदु बनाया गया था: क्या होगा यदि इनपुट अमान्य हैं लेकिन प्रोग्राम क्रैश नहीं होता है? फिर आपको डेटाबेस में कचरा मिलता है और लाइन के नीचे त्रुटियां होती हैं।

जब एक नंबर (डॉलर या इकाइयों की संख्या में मूल्य) के लिए कहा जाता है, तो मुझे "1e9" दर्ज करना पसंद है और देखें कि कोड क्या करता है। यह हो सकता है।

चार दशक पहले, UCBerkeley से कंप्यूटर साइंस में बीएस करने के बाद, हमें बताया गया कि एक अच्छा प्रोग्राम 50% एरर हैंडलिंग है। पागल हो।


हां, IMHO यह उन कुछ स्थितियों में से एक है जिसमें पंगु होना एक विशेषता है और समस्या नहीं है।
जियोर्जियो

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

हां, लेकिन - मेरा कहना यह है कि कार्यक्रम को अमान्य इनपुट से बचना चाहिए, और इसके साथ सामना करना चाहिए। यदि इनपुट की जाँच नहीं की जाती है, तो यह सिस्टम में काम करेगा और खराब चीजें बाद में आएंगी। यहां तक ​​कि दुर्घटनाग्रस्त भी बेहतर है!
एंडी कैनफील्ड

मैं आपके साथ पूरी तरह से सहमत हूं: मेरा विशिष्ट तरीका या फ़ंक्शन यह सुनिश्चित करने के लिए चेक के अनुक्रम से शुरू होता है कि इनपुट डेटा सही है।
जियोर्जियो

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

7

आपके पास पहले से ही सही विचार है

गलत इनपुट से निपटने के लिए आप दोनों में से कौन सा दृष्टिकोण सुझाएगा?

असंगत इनपुट -> कोई क्रिया + सूचना नहीं

या और अच्छा

असंगत इनपुट -> उचित कार्रवाई

आप वास्तव में प्रोग्रामिंग के लिए एक कुकी कटर दृष्टिकोण नहीं ले सकते हैं (आप कर सकते हैं) लेकिन आप एक फार्मूलाबद्ध डिज़ाइन के साथ समाप्त करेंगे जो कि सचेत विकल्प के बजाय चीजों को आदत से बाहर करता है।

व्यावहारिकता के साथ स्वभावपूर्ण डामरवाद।

स्टीव मैककोनेल ने इसे सबसे अच्छा कहा

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

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


2
सार्वजनिक करने के बजाय, मैं सुझाव दूंगा कि सभी गैर-निजी तरीके रक्षात्मक भाषाओं को कवर करने, साझा करने, या एक्सेस प्रतिबंध की कोई अवधारणा नहीं है (सब कुछ सार्वजनिक है, संक्षेप में)।
जस्टिन 44

3

यहां कोई "सही" उत्तर नहीं है, विशेष रूप से भाषा, कोड के प्रकार, और उत्पाद के प्रकार के बिना जो कोड में जा सकता है। विचार करें:

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

  • पागल होना अनुचित, अनुचित संदेह या अविश्वास है। यह शायद लोगों के लिए सॉफ्टवेयर से बेहतर नहीं है।

  • आपकी चिंता का स्तर कोड में जोखिम के स्तर और किसी भी समस्या की पहचान करने की संभावित कठिनाई के साथ कम होना चाहिए। सबसे खराब स्थिति में क्या होता है? उपयोगकर्ता प्रोग्राम को पुनरारंभ करता है और जारी रखता है कि वे कहाँ से छूटे हैं? कंपनी का लाखों डॉलर का नुकसान?

  • आप हमेशा खराब इनपुट की पहचान नहीं कर सकते। आप धार्मिक रूप से अपने संकेत की तुलना शून्य से कर सकते हैं, लेकिन यह केवल 2 ^ 32 संभावित मानों में से एक को पकड़ता है , जिनमें से लगभग सभी खराब हैं।

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

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


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

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

1

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

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

अधिक अंत-उपयोगकर्ता से संबंधित नोट पर, कुछ वर्णनात्मक अभी तक सरल वापस करना सबसे अच्छा है ताकि कोई भी इसे समझ सके। यदि आपका क्लाइंट कॉल करता है और कहता है "प्रोग्राम क्रैश हो गया है, तो इसे ठीक करें", आपके पास अपने हाथों पर बहुत सारे काम हैं जो नीचे ट्रैक करते हैं कि क्या गलत हुआ और क्यों, और उम्मीद है कि आप समस्या को पुन: उत्पन्न कर सकते हैं। अपवादों के उचित हैंडलिंग का उपयोग करके न केवल दुर्घटना को रोका जा सकता है, बल्कि बहुमूल्य जानकारी भी प्रदान की जा सकती है। क्लाइंट के एक कॉल में "प्रोग्राम मुझे एक त्रुटि दे रहा है। यह कहता है कि 'XYZ मेथड M के लिए मान्य इनपुट नहीं है, क्योंकि Z बहुत बड़ा है", या कुछ ऐसी चीज, भले ही उनके पास कोई विचार न हो कि इसका क्या मतलब है, आप पता है कि कहाँ देखना है। इसके अतिरिक्त, आपकी / आपकी कंपनी की व्यावसायिक प्रथाओं के आधार पर, हो सकता है कि आप भी इन समस्याओं को ठीक नहीं कर रहे हों, इसलिए उन्हें एक अच्छा नक्शा छोड़ना सबसे अच्छा है।

तो मेरे जवाब का संक्षिप्त संस्करण यह है कि आपका पहला विकल्प सबसे अच्छा है।

Inconsistent input -> no action + notify caller

1

प्रोग्रामिंग में विश्वविद्यालय की कक्षा से गुजरने के दौरान मैंने इसी मुद्दे पर संघर्ष किया। मैं पागल की तरफ झुक गया और सब कुछ जांचने लगा लेकिन बताया गया कि यह गलत व्यवहार था।

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

कार्यक्रम की शुद्धता (पूर्व शर्त, आवधिकता, पोस्ट की स्थिति का सत्यापन) को सत्यापित करने के लिए बिल्ड पुनरावृत्तियों के दौरान उपयोग किया जाना चाहिए। तब संकलन उत्पादन संकलन में बदल जाएगा।


0

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

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

संपादित करें: बस यह जोड़ने के लिए कि यदि आप Oracle JDK पर उदाहरण के लिए देखते हैं, तो आप देखेंगे कि वे "null" के लिए कभी जाँच नहीं करते हैं और कोड को क्रैश होने देते हैं। चूंकि यह वैसे भी एक NullPointerException को फेंकने जा रहा है, क्यों अशक्त की जाँच करने और एक स्पष्ट अपवाद को फेंकने से परेशान है। मुझे लगता है कि यह कुछ समझ में आता है।


जावा में आपको एक शून्य सूचक अपवाद मिलता है। C ++ में एक null पॉइंटर एप्लीकेशन को क्रैश कर देता है। शायद अन्य उदाहरण हैं: शून्य से विभाजन, सीमा से बाहर सूचकांक, और इसी तरह।
जियोर्जियो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.