क्या एक विधि को उन तर्कों के साथ माफ़ किया जाना चाहिए जो पारित हो गए हैं? [बन्द है]


21

मान लीजिए कि हमारे पास एक ऐसा तरीका है foo(String bar)जो केवल कुछ मानदंडों को पूरा करने वाले तारों पर संचालित होता है; उदाहरण के लिए, यह लोअरकेस होना चाहिए, खाली नहीं होना चाहिए या केवल व्हाट्सएप होना चाहिए, और पैटर्न से मेल खाना चाहिए [a-z0-9-_./@]+। विधि के लिए प्रलेखन इन मानदंडों को बताता है।

क्या इस मानदंड से विधि और सभी विचलन को अस्वीकार करना चाहिए , या क्या विधि को कुछ मानदंडों के बारे में अधिक क्षमा करना चाहिए? उदाहरण के लिए, यदि प्रारंभिक विधि है

public void foo(String bar) {
    if (bar == null) {
        throw new IllegalArgumentException("bar must not be null");
    }
    if (!bar.matches(BAR_PATTERN_STRING)) {
        throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
    }
    this.bar = bar;
}

और दूसरी क्षमा करने की विधि है

public void foo(String bar) {
    if (bar == null) {
        throw new IllegalArgumentException("bar must not be null");
    }
    if (!bar.matches(BAR_PATTERN_STRING)) {
        bar = bar.toLowerCase().trim().replaceAll(" ", "_");
        if (!bar.matches(BAR_PATTERN_STRING) {
            throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
        }
    }
    this.bar = bar;
}

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

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


1
यह संभवतः आपके उपयोग के मामले पर बहुत अधिक निर्भर करता है। या तो एक उचित हो सकता है, और मैंने ऐसी कक्षाएं भी देखी हैं जो दोनों तरीके प्रदान करती हैं और उपयोगकर्ता को तय करती हैं। क्या आप इस बारे में विस्तार से बता सकते हैं कि यह विधि / वर्ग / क्षेत्र क्या करने वाला है, इसलिए हम कुछ वास्तविक सलाह दे सकते हैं?
23

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

7
आप यह तर्क दे सकते हैं कि सेपरेशन ऑफ कॉन्सर्न का कहना है कि यदि आवश्यक हो, तो आपके पास एक सख्त fooफ़ंक्शन होना चाहिए जो इसे स्वीकार करने वाले तर्कों में कठोर हो, और एक दूसरा सहायक फ़ंक्शन हो जो एक तर्क को "क्लीन" करने की कोशिश कर सकता है foo। इस तरह, प्रत्येक विधि को अपने दम पर कम करना पड़ता है, और वे अधिक सफाई से प्रबंधित और एकीकृत कर सकते हैं। यदि उस मार्ग से नीचे जा रहे हैं, तो यह संभवतः अपवाद-भारी डिज़ाइन से दूर जाने में भी सहायक होगा; आप Optionalइसके बजाय कुछ का उपयोग कर सकते हैं , और फिर ऐसे कार्य हैं जो fooआवश्यक होने पर फेंक अपवादों का उपभोग करते हैं ।
gntskn

1
यह पूछने जैसा है कि "किसी ने मेरे साथ अन्याय किया, क्या मुझे उन्हें माफ कर देना चाहिए?" स्पष्ट रूप से ऐसी परिस्थितियां हैं जहां या तो एक या दूसरे उपयुक्त हैं। प्रोग्रामिंग मानवीय रिश्तों की तरह जटिल नहीं हो सकता है, लेकिन यह निश्चित रूप से पर्याप्त जटिल है कि इस तरह एक कंबल पर्चे काम नहीं कर रहा है।
किलन फ़ॉथ

2
@Boggin मैं आपको रोबस्टनेस सिद्धांत पर पुनर्विचार करने के लिए भी कहूंगा । कठिनाई तब आती है जब आपको कार्यान्वयन का विस्तार करने की आवश्यकता होती है और माफ करने वाला कार्यान्वयन विस्तारित कार्यान्वयन के साथ अस्पष्ट मामले की ओर जाता है।

जवाबों:


47

आपकी विधि को वही करना चाहिए जो वह कहता है।

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

उस ने कहा, यदि परिभाषित तर्क उपयोगकर्ता के अनुकूल नहीं है, तो शायद इसे सुधारना चाहिए।


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

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

20

कुछ बिंदु हैं:

  1. आपके कार्यान्वयन को वही करना चाहिए जो दस्तावेज अनुबंधित स्थिति में है, और इससे अधिक कुछ नहीं करना चाहिए।
  2. सादगी महत्वपूर्ण है, दोनों अनुबंध और कार्यान्वयन के लिए, हालांकि पूर्व के लिए अधिक।
  3. गलत इनपुट के लिए सही करने की कोशिश करने से जटिलता आती है, काउंटर-सहजता से न केवल अनुबंध और कार्यान्वयन के लिए, बल्कि उपयोग करने के लिए भी।
  4. त्रुटियों को केवल तभी पकड़ा जा सकता है यदि यह डिबगैबिलिटी को बेहतर बनाता है और दक्षता से बहुत अधिक समझौता नहीं करता है।
    याद रखें कि डिबग-मोड में तर्क त्रुटियों के निदान के लिए डिबग-अभिकथन हैं, जो ज्यादातर किसी भी प्रदर्शन-चिंताओं को कम करता है।
  5. दक्षता, जहां तक ​​उपलब्ध समय और धन की सादगी से बहुत अधिक समझौता किए बिना अनुमति है, हमेशा एक लक्ष्य होता है।

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


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


Sendmail के लेखक द्वारा एक और महत्वपूर्ण टुकड़ा:

15

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

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

  • कच्ची कार्यक्षमता, बिना किसी पूर्वप्रक्रिया के।
  • स्वयं के द्वारा पूर्वप्रकरण चरण ।
  • कच्ची कार्यक्षमता और प्रीप्रोसेसिंग का संयोजन।

अंतिम वैकल्पिक है; यदि आप बड़ी संख्या में कॉल का उपयोग करेंगे, तो आपको इसे प्रदान करना चाहिए।

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


2
पूर्वानुमान के लिए +1। और सरल के लिए एक और +1 (मैं चाहता हूं)। मैं बहुत ज्यादा मदद करूंगा कि आप मुझे छिपाने की कोशिश करने की बजाय मेरी गलतियों को सुधारने में मदद करें।
जॉन एम गेंट

4

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

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

दूसरी ओर, यदि इनपुट से आ रहा था, तो कहो, तकनीकी लोगों द्वारा इकट्ठी की गई संपत्तियों की फाइलें, जिन्हें यह समझना चाहिए कि "Fred Mertz" != "FredMertz", मैं मैचिंग स्टिकटर बनाने और विकास लागत को बचाने के लिए अधिक इच्छुक हूं।

मुझे लगता है कि किसी भी मामले में अग्रणी और अनुगामी स्थानों की ट्रिमिंग और अवहेलना में मूल्य है, हालांकि - मैंने देखा है कि उन प्रकार के मुद्दों को डीबग करने में कई घंटे बर्बाद होते हैं।


3

आप कुछ ऐसे संदर्भ का उल्लेख करते हैं जिनसे यह प्रश्न आता है।

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

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

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

यहां बड़ा जोर स्पष्टता है और कोड क्या करता है यह दस्तावेज करना है


-1
  1. आप doSomething (), takeBackUp () जैसी क्रिया के अनुसार एक विधि को नाम दे सकते हैं।
  2. इसे बनाए रखना आसान बनाने के लिए आप विभिन्न प्रक्रियाओं पर सामान्य अनुबंध और सत्यापन रख सकते हैं। उपयोग मामलों के अनुसार उन्हें कॉल करें।
  3. रक्षात्मक प्रोग्रामिंग: आपकी प्रक्रिया इनपुट की विस्तृत श्रृंखला को शामिल करती है (न्यूनतम चीजें जो उपयोग किए जाने वाले मामले हैं उन्हें वैसे भी कवर किया जाना चाहिए)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.