क्या निरर्थक स्थिति सर्वोत्तम प्रथाओं के खिलाफ जाँच कर रही है?


16

मैं पिछले तीन वर्षों से सॉफ्टवेयर विकसित कर रहा हूं, लेकिन मैं अभी हाल ही में जाग गया हूं कि मैं अच्छी प्रथाओं से कितना अनभिज्ञ हूं। इससे मुझे पुस्तक क्लीन कोड पढ़ना शुरू करना पड़ा है , जो मेरे जीवन को बेहतर बनाने के लिए उल्टा हो रहा है, लेकिन मैं अपने कार्यक्रमों को लिखने के लिए कुछ सर्वोत्तम तरीकों में अंतर्दृष्टि प्राप्त करने के लिए संघर्ष कर रहा हूं।

मेरे पास एक पायथन कार्यक्रम है जिसमें मैं ...

  1. required=Trueदो तर्कों को लागू करने के लिए argparse का उपयोग करें , जो दोनों फ़ाइल नाम हैं। पहला इनपुट फ़ाइल नाम है, दूसरा आउटपुट फ़ाइल नाम है
  2. एक फ़ंक्शन है readFromInputFileजो पहले यह देखने के लिए जांचता है कि इनपुट फ़ाइल नाम दर्ज किया गया था
  3. एक फ़ंक्शन है writeToOutputFileजो पहले यह देखने के लिए जांचता है कि आउटपुट फ़ाइल नाम दर्ज किया गया था

मेरा कार्यक्रम इतना छोटा है कि मुझे विश्वास है कि # 2 और # 3 में जाँच निरर्थक है और इसे हटा दिया जाना चाहिए, इस प्रकार दोनों कार्यों को अनावश्यक ifस्थिति से मुक्त किया जाएगा । हालांकि, मुझे यह विश्वास करने के लिए भी प्रेरित किया गया है कि "डबल-चेकिंग ठीक है" और एक कार्यक्रम में सही समाधान हो सकता है जहां फ़ंक्शन को एक अलग स्थान से बुलाया जा सकता है जहां तर्कों की पार्सिंग नहीं होती है।

(इसके अलावा, यदि पढ़ने या लिखने में विफल रहता है, तो मेरे पास एक try exceptउपयुक्त त्रुटि संदेश जुटाने के लिए प्रत्येक फ़ंक्शन में है।)

मेरा सवाल यह है: क्या सभी अनावश्यक स्थिति की जाँच से बचना सबसे अच्छा है? क्या एक कार्यक्रम का तर्क इतना ठोस होना चाहिए कि चेक की जरूरत केवल एक बार हो? क्या ऐसे कोई अच्छे उदाहरण हैं, जो इस या इसके बारे में बताते हैं?

संपादित करें: आप सभी के जवाब के लिए धन्यवाद! मैंने प्रत्येक से कुछ सीखा है। इतने सारे दृष्टिकोणों को देखने से मुझे इस समस्या से निपटने और मेरी आवश्यकताओं के आधार पर समाधान निर्धारित करने की बेहतर समझ मिलती है। धन्यवाद!


यहाँ आपके प्रश्न का एक सामान्यीकृत संस्करण है: softwareengineering.stackexchange.com/questions/19549/… । मैं यह नहीं कहूंगा कि यह डुप्लिकेट है क्योंकि इसमें काफी बड़ा फोकस है, लेकिन शायद यह मदद करता है।
डॉक्टर ब्राउन

जवाबों:


15

आप जो पूछ रहे हैं उसे "मजबूती" कहा जाता है, और कोई सही या गलत जवाब नहीं है। यह कार्यक्रम के आकार और जटिलता, उसमें काम करने वाले लोगों की संख्या और विफलताओं का पता लगाने के महत्व पर निर्भर करता है।

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

आपके मामले में, आपको अपने लिए तय करना होगा कि आप अपने कार्यक्रम के लिए किस तरह के जीवन चक्र की उम्मीद करते हैं। क्या यह एक ऐसा कार्यक्रम है जिसका आप वर्षों से उपयोग और रखरखाव की उम्मीद करते हैं? फिर एक निरर्थक चेक जोड़ना शायद बेहतर है, क्योंकि यह संभावना नहीं होगी कि आपका कोड भविष्य में फिर से सक्रिय हो जाएगा और आपके readऔर writeकार्यों को एक अलग संदर्भ में उपयोग किया जा सकता है।

या यह केवल सीखने या मजेदार उद्देश्यों के लिए एक छोटा कार्यक्रम है? फिर वे दोहरे चेक आवश्यक नहीं होंगे।

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

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

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

क्या इससे आपको दो स्थानों पर अपना दोहरा सत्यापन बदलने की आवश्यकता है? शायद नहीं, इस तरह की आवश्यकता से कॉल करते समय एक परिवर्तन होता है argparse, लेकिन इसमें कोई परिवर्तन नहीं होता है writeToOutputFile: उस फ़ंक्शन को अभी भी फ़ाइल नाम की आवश्यकता होगी। इसलिए आपके मामले में, मैं इनपुट सत्यापन को दो बार करने के लिए मतदान करूंगा, क्योंकि दो जगहों पर बदलाव की वजह से रखरखाव की समस्या होने का जोखिम आईएमएचओ को बहुत कम जांचों की वजह से नकाबपोश त्रुटियों के कारण रखरखाव की समस्याओं के जोखिम से कम है।


"... सार्वजनिक APIs के रूप में घटकों के बीच की सीमाएं ..." मैं देखता हूं कि "कक्षाएं लीप सीमाएं" इसलिए बोलने के लिए। तो क्या जरूरत है एक वर्ग है; एक सुसंगत व्यापार डोमेन वर्ग। मैं इस ओपी का उल्लेख कर रहा हूं कि "सरल है, इसलिए कक्षा की आवश्यकता नहीं है" का सर्वव्यापी सिद्धांत यहां काम पर है। "प्राथमिक ऑब्जेक्ट" को लपेटने वाला एक साधारण वर्ग हो सकता है, "एक फ़ाइल का एक नाम होना चाहिए" जैसे व्यावसायिक नियमों को लागू करना, जो न केवल मौजूदा कोड को DRYs करता है, बल्कि भविष्य में इसे DRY रखता है।
राडारबॉब

@ ब्रैडबॉब: मैंने जो लिखा है वह कक्षाओं के रूप में ओओपी या घटकों तक ही सीमित नहीं है। यह सार्वजनिक API, ऑब्जेक्ट ओरिएंटेड या नहीं के साथ मनमानी पुस्तकालयों पर भी लागू होता है।
Doc Brown

5

अतिरेक पाप नहीं है। अनावश्यक अतिरेक है।

  1. तो readFromInputFile()और writeToOutputFile()कर रहे हैं एक सार्वजनिक कार्य (और अजगर सम्मेलनों वे कर रहे हैं के बाद से उनके नाम दो अंडरस्कोर से शुरू नहीं किया नामकरण से) तो कार्यों किसी दिन कोई है जो argparse पूरी तरह बचना द्वारा इस्तेमाल किया जा सकता है। इसका मतलब है कि जब वे तर्कों को छोड़ देते हैं तो उन्हें आपके कस्टम अर्गपर्स एरर मैसेज देखने को नहीं मिलते हैं।

  2. यदि readFromInputFile()और writeToOutputFile()स्वयं मापदंडों की जांच करते हैं, तो आपको फिर से एक कस्टम त्रुटि संदेश दिखाना होगा जो फ़ाइल नाम की आवश्यकता को बताता है।

  3. अगर readFromInputFile()और writeToOutputFile()खुद मापदंडों की जांच नहीं करते हैं, तो कोई कस्टम त्रुटि संदेश नहीं दिखाया गया है। उपयोगकर्ता को अपने आधार पर परिणामी अपवाद का पता लगाना होगा।

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

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


4

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

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

ध्यान दें कि इसका मतलब यह हो सकता है कि आप एक ही जानकारी को एक से अधिक बार मान्य कर रहे हैं। लेकिन यह ठीक है। प्रत्येक घटक इसके अपने तरीके से मान्यता के लिए जिम्मेदार है । यह DRY का उल्लंघन नहीं है, क्योंकि सत्यापन स्वतंत्र युग्मित घटकों द्वारा किया जाता है, और एक में मान्यता का परिवर्तन जरूरी नहीं कि दूसरे में बिल्कुल दोहराया जाए। यहां कोई अतिरेक नहीं है। X की यह ज़िम्मेदारी है कि वह अपनी ज़रूरतों के लिए इनपुट्स की जाँच करे और कुछ को Y पास करे। Y की यह ज़िम्मेदारी है कि वह अपनी ज़रूरतों के लिए स्वयं इनपुट्स की जाँच करे ।


1

मान लें कि आपका कोई फ़ंक्शन है (C में)

void readInputFile (const char* path);

और आपको पथ के बारे में कोई दस्तावेज नहीं मिल रहा है। और फिर आप कार्यान्वयन को देखते हैं और यह कहते हैं

void readInputFile (const char* path)
{
    assert (path != NULL && strlen (path) > 0);

न केवल यह फ़ंक्शन के इनपुट का परीक्षण करता है, बल्कि यह फ़ंक्शन के उपयोगकर्ता को भी बताता है कि पथ को NULL या रिक्त स्ट्रिंग की अनुमति नहीं है।


0

सामान्य तौर पर, डबल-चेकिंग हमेशा अच्छा या बुरा नहीं होता हैआपके विशेष मामले में हमेशा सवाल के कई पहलू होते हैं, जिस पर यह मामला निर्भर करता है। आपके मामले में:

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

0

आपकी डबल-चेक्स उन जगहों पर लगती हैं, जहां उनका उपयोग शायद ही कभी किया जाता है। तो ये चेक आपके प्रोग्राम को और अधिक मजबूत बना रहे हैं:

एक चेक बहुत अधिक चोट नहीं करेगा, एक बहुत कम हो सकता है।

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


और जब से आपके पास यह पहले से ही है, यह हटाने के प्रयास के लायक नहीं है, जब तक कि यह एक लूप या कुछ में नहीं है।
StarWeaver

0

शायद आप अपनी बात बदल सकते हैं:

अगर कुछ गलत होता है, तो परिणाम क्या होता है? क्या यह आपके एप्लिकेशन / उपयोगकर्ता को नुकसान पहुंचाएगा?

बेशक, आप हमेशा तर्क दे सकते हैं, कि कम या ज्यादा जाँच बेहतर या बदतर है लेकिन यह एक बड़ा विद्वान प्रश्न है। और जब से आप वास्तविक विश्व सॉफ्टवेयर के साथ काम कर रहे हैं , वास्तविक दुनिया परिणाम हैं।

आप जो संदर्भ दे रहे हैं, उससे:

  • एक इनपुट फ़ाइल
  • एक आउटपुट फ़ाइल B

मुझे लगता है कि आप से बी में परिवर्तन कर रहे हैं । यदि A और B छोटे हैं और परिवर्तन छोटा है, तो परिणाम क्या होंगे?

1) आप यह निर्दिष्ट करना भूल गए कि कहां से पढ़ना है: फिर परिणाम कुछ भी नहीं है । और निष्पादन का समय उम्मीद से कम होगा। आप परिणाम को देखते हैं - या बेहतर: एक लापता परिणाम की तलाश करें, देखें कि आपने आदेश को गलत तरीके से लागू किया है, फिर से शुरू करें और सभी को फिर से ठीक करें

2) आप आउटपुटफाइल निर्दिष्ट करना भूल गए। इसके परिणामस्वरूप विभिन्न परिदृश्य हैं:

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

b) इनपुट स्टेप बाय स्टेप है। फिर लेखन प्रक्रिया तुरंत (1) की तरह समाप्त हो जाती है और उपयोगकर्ता फिर से शुरू हो जाता है।

कुछ परिस्थितियों में मैला जाँच को ठीक माना जा सकता है। यह पूरी तरह से आपके usecase पर निर्भर करता है और आपका इरादा क्या है।

अतिरिक्त रूप से: आपको व्यामोह से बचना चाहिए और बहुत सारे दोहरे कार्य नहीं करने चाहिए।


0

मैं तर्क दूंगा कि परीक्षण बेमानी नहीं हैं।

  • आपके पास दो सार्वजनिक कार्य हैं जिन्हें इनपुट पैरामीटर के रूप में फ़ाइल नाम की आवश्यकता है। उनके मापदंडों को मान्य करना उचित है। फ़ंक्शंस को संभवतः किसी भी प्रोग्राम में उपयोग किया जा सकता है जो उनकी कार्यक्षमता की आवश्यकता है।
  • आपके पास एक प्रोग्राम है जिसमें दो तर्कों की आवश्यकता होती है जो फ़ाइल नाम होना चाहिए। यह फ़ंक्शन का उपयोग करने के लिए होता है। कार्यक्रम के लिए इसके मापदंडों की जांच करना उचित है।

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

एक अधिक मजबूत समाधान में एक या दो फ़ाइल सत्यापनकर्ता होंगे।

  • इनपुट फ़ाइल के लिए, आप यह सत्यापित कर सकते हैं कि पैरामीटर एक पठनीय फ़ाइल निर्दिष्ट करता है।
  • आउटपुट फ़ाइल के लिए, आप यह सत्यापित करना चाह सकते हैं कि पैरामीटर एक लिखने योग्य फ़ाइल या एक वैध फ़ाइल नाम है जिसे बनाया और लिखा जा सकता है।

क्रिया करने के लिए मैं दो नियमों का उपयोग करता हूं:

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

0

चेक बेमानी है। हालाँकि, इसे ठीक करने के लिए यह आवश्यक है कि आप readFromInputFile और writeToOutputFile को हटा दें और उन्हें readFromStream और writeToStream से बदल दें।

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

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

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