फ़ंक्शन नामों में तर्कों के नामों को अधिक सामान्य क्यों नहीं रखा गया है? [बन्द है]


47

में स्वच्छ कोड लेखक का एक उदाहरण देता है

assertExpectedEqualsActual(expected, actual)

बनाम

assertEquals(expected, actual)

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


9
मुझे लगता है कि यह एक चर्चा के लिए महान प्रश्न है। लेकिन ऐसा कुछ नहीं जिसे वस्तुनिष्ठ उत्तर के साथ दिया जा सके। तो यह सवाल राय-आधारित के रूप में बंद हो सकता है।
व्यंग्यात्मक

54
बहुत से लोग पहली नामकरण योजना के खिलाफ बहस करेंगे क्योंकि यह अत्यधिक क्रियात्मक है , उस बिंदु से परे जहां यह स्पष्टता को सहायता करेगा। विशेष रूप से assertEquals(), उस पद्धति का उपयोग कोड आधार में सैकड़ों बार किया जाता है ताकि यह उम्मीद की जा सके कि पाठक एक बार सम्मेलन के साथ खुद को परिचित कर लें। विभिन्न रूपरेखाओं में अलग-अलग परंपराएं हैं (उदाहरण के लिए (actual, expected) or an agnostic (बाएं, दाएं) `), लेकिन मेरे अनुभव में यह भ्रम का सबसे मामूली स्रोत है।
आमोन

5
क्योंकि लाभ इतना छोटा है, इसके लाभों की तुलना में, कि कोई भी समझदार शायद दूर चलेगा। यदि आप एक अधिक धाराप्रवाह दृष्टिकोण चाहते हैं, तो आपको प्रयास करना चाहिए assert(a).toEqual(b)(भले ही IMO यह अभी भी अनावश्यक रूप से क्रिया है) जहां आप कुछ संबंधित सिद्धांतों की श्रृंखला कर सकते हैं।
एड्रियानो रेपेती

18
हम कैसे जानते हैं कि वास्तविक और अपेक्षित मूल्य हैं? निश्चित रूप से यह होना चाहिए assertExpectedValueEqualsActualValue? लेकिन रुकिए, हम कैसे याद है कि क्या यह का उपयोग करता है ==या .equalsया Object.equals? क्या यह होना चाहिए assertExpectedValueEqualsMethodReturnsTrueWithActualValueParameter?
user253751

6
यह देखते हुए कि, इस विशेष विधि के लिए, दो तर्कों का क्रम मायने नहीं रखता है, यह इस नामकरण योजना के लाभों को चुनने के लिए एक खराब उदाहरण की तरह लगता है।
स्टीवन रैंड्स

जवाबों:


66

क्योंकि यह टाइप करने के लिए और पढ़ने के लिए अधिक है

सबसे सरल कारण यह है कि लोग कम टाइप करना पसंद करते हैं, और उस जानकारी को एन्कोडिंग करना अधिक टाइपिंग है। इसे पढ़ते समय, हर बार मुझे पूरी बात पढ़नी होती है, भले ही मैं इस बात से परिचित हो कि तर्कों का क्रम क्या होना चाहिए। भले ही तर्कों के क्रम से परिचित न हों ...

कई डेवलपर्स आईडीई का उपयोग करते हैं

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

तर्कों को एन्कोड करने से दोहराव और युग्मन का परिचय होता है

मापदंडों के नाम पहले से ही दस्तावेज होना चाहिए कि वे क्या हैं। विधि नाम में नाम लिखकर, हम उस जानकारी को विधि हस्ताक्षर में भी दोहरा रहे हैं। हम विधि नाम और मापदंडों के बीच एक युग्मन भी बनाते हैं। कहो expectedऔर actualहमारे उपयोगकर्ताओं को भ्रमित कर रहे हैं। से जा रहे हैं assertEquals(expected, actual)करने के लिए assertEquals(planned, real)समारोह का उपयोग कर क्लाइंट कोड को बदलने की आवश्यकता नहीं है। से जा रहे हैं assertExpectedEqualsActual(expected, actual)करने के लिए assertPlannedEqualsReal(planned, real)साधन एपीआई के लिए एक को तोड़ने के परिवर्तन नहीं। या हम विधि का नाम नहीं बदलते हैं, जो जल्दी भ्रमित हो जाता है।

अस्पष्ट तर्कों के बजाय प्रकारों का उपयोग करें

असली मुद्दा यह है कि हमारे पास अस्पष्ट तर्क हैं जो आसानी से बदल जाते हैं क्योंकि वे एक ही प्रकार के होते हैं। इसके बजाय हम सही क्रम को लागू करने के लिए हमारे प्रकार प्रणाली और हमारे संकलक का उपयोग कर सकते हैं:

class Expected<T> {
    private T value;
    Expected(T value) { this.value = value; }
    static Expected<T> is(T value) { return new Expected<T>(value); }
}

class Actual<T> {
    private T value;
    Actual(T value) { this.value = value; }
    static Actual<T> is(T value) { return new Actual<T>(value); }
}

static assertEquals(Expected<T> expected, Actual<T> actual) { /* ... */ }

// How it is used
assertEquals(Expected.is(10), Actual.is(x));

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


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

29
यदि आप assertExpectedEqualsActual"क्योंकि यह टाइप करने के लिए और पढ़ने के लिए अधिक है" पर आपत्ति करते हैं, तो आप कैसे वकालत कर सकते हैं assertEquals(Expected.is(10), Actual.is(x))?
रुख

9
@ruakh यह तुलनीय नहीं है। assertExpectedEqualsActualसही क्रम में तर्कों को निर्दिष्ट करने के लिए अभी भी प्रोग्रामर की देखभाल करने की आवश्यकता है। assertEquals(Expected<T> expected, Actual<T> actual)हस्ताक्षर सही उपयोग है, जो एक पूरी तरह से अलग दृष्टिकोण है लागू करने के लिए संकलक का उपयोग करता है। आप संक्षिप्तता के लिए इस दृष्टिकोण को अनुकूलित कर सकते हैं, उदाहरण के लिए expect(10).equalsActual(x), लेकिन यह सवाल नहीं था ...
होल्गर

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

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

20

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

वर्बोसिटी का मतलब हमेशा अधिक स्पष्टता नहीं होता है। विचार करें

copyFromSourceStreamToDestinationStreamWithoutBlocking(fileStreamFromChoosePreferredOutputDialog, heuristicallyDecidedSourceFileHandle)

बनाम

copy(output, source)

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

क्रियाशीलता जोड़ने का एक लंबा इतिहास है। उदाहरण के लिए, आम तौर पर अलोकप्रिय " हंगेरियन नोटेशन " है, जिसने हमें अद्भुत नाम दिए हैं lpszName। यह आम तौर पर सामान्य प्रोग्रामर आबादी में सड़क के किनारे गिर गया है। हालाँकि, कुछ चर में सदस्य चर नाम (जैसे mNameया m_Nameया name_) के लिए वर्ण जोड़ना जारी है। दूसरों ने पूरी तरह से गिरा दिया। मैं एक भौतिकी सिमुलेशन कोडबेस पर काम करता हूं, जिसकी कोडिंग शैली के दस्तावेजों के लिए आवश्यक है कि कोई भी फ़ंक्शन जो एक वेक्टर लौटाता है, उसे फ़ंक्शन कॉल ( getPositionECEF) में वेक्टर के फ्रेम को निर्दिष्ट करना होगा ।

Apple द्वारा प्रचलित कुछ भाषाओं में आपकी रुचि हो सकती है। ऑब्जेक्टिव-सी में फ़ंक्शन हस्ताक्षर के भाग के रूप में तर्क नाम शामिल हैं (फ़ंक्शन [atm withdrawFundsFrom: account usingPin: userProvidedPin]को प्रलेखन के रूप में लिखा गया है withdrawFundsFrom:usingPin:। यह फ़ंक्शन का नाम है)। स्विफ्ट ने निर्णयों का एक समान सेट किया, जिससे आपको फ़ंक्शन कॉल में तर्क नाम डालने की आवश्यकता होती है ( greet(person: "Bob", day: "Tuesday"))।


13
अन्य सभी बिंदुओं को एक तरफ रख दिया जाए, तो अगर पढ़नाcopyFromSourceStreamToDestinationStreamWithoutBlocking(fileStreamFromChoosePreferredOutputDialog, heuristicallyDecidedSourceFileHandle) लिखा जाए तो यह बहुत आसान हो जाएगा copy_from_source_stream_to_destination_stream_without_blocking(file_stream_from_choose_preferred_output_dialog, heuristically_decided_source_file_handle)देखो कि कितना आसान था ?! ऐसा इसलिए है क्योंकि उस ह्युमंगसूनब्रोकन पासवर्ड के माध्यम से छोटे-छोटे बदलावों को याद रखना बहुत आसान है, और यह पता लगाने में अधिक समय लगता है कि शब्द सीमाएँ कहाँ हैं। मुंहतोड़ जवाब।
tchrist

1
Obj-C सिंटैक्स withdrawFundsFrom: account usingPin: userProvidedPinवास्तव में SmallTalk से उधार लिया गया है।
joH1

14
@ तीर्थयात्री सावधान रहें कि आप पवित्र युद्धों से जुड़े विषयों पर सही हैं। दूसरा पक्ष हमेशा गलत नहीं होता है।
Cort Ammon

3
@tchrist Addingunderscoresnakesthingseasiertoreadnotharderasyouseeतर्क में हेरफेर कर रहा है। यहाँ उत्तर में कैपिटलाइज़ेशन का उपयोग किया गया है, जिसे आप छोड़ रहे हैं। AddingCapitalizationMakesThingsEasyEnoughToReadAsYouCanSeeHere। दूसरे, 10 में से 9 बार, एक नाम से आगे कभी नहीं बढ़ना चाहिए [verb][adjective][noun](जहां प्रत्येक ब्लॉक वैकल्पिक है), एक प्रारूप जो सरल पूंजीकरण का उपयोग करने के लिए अच्छी तरह से पठनीय है:ReadSimpleName
Flater

5
@tchrist - आपके अध्ययन का विज्ञान ( मुफ्त पूर्ण पाठ लिंक ) बस दिखाता है कि अंडरस्कोर शैली का उपयोग करने के लिए प्रशिक्षित प्रोग्रामर ऊंट मामले की तुलना में अंडरस्कोर शैली पढ़ने में तेज हैं। आंकड़ों से यह भी पता चलता है कि अंतर अधिक अनुभवी विषयों के लिए छोटा है (और अधिकांश विषयों के छात्रों का सुझाव है कि वे भी विशेष रूप से अनुभवी नहीं थे)। इसका मतलब यह नहीं है कि ऊंट मामले का उपयोग कर अधिक समय बिताने वाले प्रोग्रामर भी वही परिणाम देंगे।
जूल्स

8

"क्लीन कोड" के लेखक एक वैध समस्या की ओर इशारा करते हैं, लेकिन उनका सुझाया हुआ समाधान असंगत है। अस्पष्ट विधि नामों को बेहतर बनाने के लिए आमतौर पर बेहतर तरीके हैं।

वह सही है कि assertEquals(xUnit शैली इकाई परीक्षण पुस्तकालयों से) यह स्पष्ट नहीं करता है कि कौन सा तर्क अपेक्षित है और कौन सा वास्तविक है। यह भी मुझे थोड़ा है! कई इकाई परीक्षण पुस्तकालयों ने इस मुद्दे को नोट किया है और वैकल्पिक वाक्यविन्यास पेश किए हैं, जैसे:

actual.Should().Be(expected);

या इसी के समान। जो निश्चित रूप से बहुत स्पष्ट है, assertEqualsलेकिन उससे भी बेहतर है assertExpectedEqualsActual। और यह एक बहुत अधिक रचना है।


1
मैं गुदा हूं और मैं अनुशंसित आदेश का पालन करता हूं, लेकिन मुझे ऐसा लगता है कि अगर मुझे परिणाम fun(x)5 होने की उम्मीद है, तो क्या गलत हो सकता है यदि आदेश को उल्टा कर दिया जाए - assert(fun(x), 5)? यह आपको कैसे काटता है?
एमोरी

3
@emory मुझे पता है कि jUnit (कम से कम) के मानों से एक गंभीर त्रुटि संदेश बनाता है expectedऔर actualइसलिए उन्हें उल्टा करने से संदेश सटीक नहीं हो सकता है। लेकिन मैं इस बात से सहमत हूं कि यह अधिक स्वाभाविक लगता है :)
joH1

@ joH1 यह मुझे कमजोर लगता है। असफल कोड विफल हो जाएगा और पासिंग कोड पास हो जाएगा assert(expected, observed)या नहीं assert(observed, expected)। एक बेहतर उदाहरण कुछ ऐसा होगा locateLatitudeLongitude- यदि आप निर्देशांक को उल्टा करते हैं, तो यह गंभीरता से गड़बड़ कर देगा।
एमोरी

1
@ वे लोग जो इकाई परीक्षणों में समझदार त्रुटि संदेशों की परवाह नहीं करते हैं, इसलिए मुझे कुछ पुराने कोड आधारों में "Assert.IsTrue विफल" से निपटना होगा। जिसे डेब्यू करने में जबरदस्त मजा आता है। लेकिन हाँ इस मामले में यह समस्या आवश्यक नहीं हो सकती है (सिवाय अगर हम फजी तुलना करते हैं जहाँ तर्कों का क्रम आम तौर पर मायने रखता है)। धाराप्रवाह दावे वास्तव में इस समस्या से बचने का एक शानदार तरीका है और कोड के तरीके को अधिक अभिव्यंजक बनाते हैं (और बूट करने के लिए बहुत बेहतर त्रुटि संदेश प्रदान करते हैं)।
वू

@emory: तर्क को उलटने से त्रुटि संदेश भ्रामक हो जाएंगे, और डिबगिंग करते समय आपको गलत रास्ते पर भेज देंगे।
जैकब

5

आप स्लैला और चरीबिडिस के बीच अपना रास्ता साफ करने की कोशिश कर रहे हैं, बेकार की वाचालता से बचने की कोशिश कर रहे हैं (जिसे लक्ष्यहीन जुआ भी कहा जाता है) और साथ ही अत्यधिक संक्षिप्तता (क्रिप्टोकरेंसी के रूप में भी जाना जाता है)।

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

  1. क्या कोई अन्य कार्य है जो कि इस पर विचार कर सकता है।
    नहीं, इसलिए नाम ही स्पष्ट है।
  2. किसी भी प्रकार के महत्व हैं?
    नहीं, तो चलिए उनकी अनदेखी करते हैं। आपने ऐसा पहले ही कर दिया था? अच्छा।
  3. क्या यह अपने तर्कों में सममित है?
    लगभग, त्रुटि पर संदेश प्रत्येक तर्क प्रतिनिधित्व को अपने स्थान पर रखता है।

तो, आइए देखें कि क्या छोटा अंतर किसी महत्व का है, और मौजूदा मजबूत सम्मेलनों द्वारा कवर नहीं किया गया है।

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

क्या तर्क आदेश का पालन करते हैं?
मामला लगता है। हालांकि यह सबसे अच्छा एक कमजोर सम्मेलन लगता है।

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


अच्छी तरह से आदेश JUnit, जिनमें से मूल्यों से एक विशिष्ट त्रुटि संदेश बनाता है के साथ बात कर सकते हैं expectedऔर actual(कम से कम स्ट्रिंग्स के साथ)
joH1

मुझे लगता है कि मैंने उस हिस्से को कवर किया ...
डेडुप्लिकेटर

आप इसे उल्लेख किया, लेकिन पर विचार करें: assertEquals("foo", "doo")त्रुटि संदेश देता है ComparisonFailure: expected:<[f]oo> but was:<[d]oo>... मान गमागमन कि लगता है और अधिक, संदेश के अर्थ को उलटने हैं विरोधी सममित मेरे लिए। वैसे भी जैसे आपने कहा कि त्रुटि को हल करने के लिए एक देव के पास अन्य संकेतक हैं, लेकिन यह आईएमएचओ को भ्रमित कर सकता है और थोड़ा और डिबगिंग समय ले सकता है।
joH1

यह विचार कि तर्क आदेशों के लिए एक "सम्मेलन" मजेदार है, यह देखते हुए कि दोनों शिविरों (भाग्य, src बनाम src, भाग्य) ने कम से कम इस बारे में तर्क दिया है कि जब तक एटी एंड टी बनाम इंटेल सिंटैक्स मौजूद है। और यूनिट परीक्षणों में अनपेक्षित त्रुटि संदेश एक प्लेग है जिसे मिटाया नहीं जाना चाहिए। यह लगभग उतना ही बुरा है जितना "Assert.IsTrue विफल" ("अरे आपको इसे डिबग करने के लिए किसी भी तरह यूनिट टेस्ट को निष्पादित करना है, इसलिए बस इसे फिर से चलाएं और वहां एक ब्रेकपॉइंट डालें", "अरे आपको किसी भी तरह कोड को देखना होगा, इसलिए बस जाँच करें कि क्या ऑर्डर सही है ")।
वू

@Voo: मुद्दा यह है कि गलत होने के लिए "नुकसान" मिनीस्कूल है (तर्क इस पर निर्भर नहीं करता है, और संदेश उपयोगिता किसी भी महत्वपूर्ण डिग्री के लिए बिगड़ा नहीं है), और आईडीई लिखते समय आपको मापदंडों का नाम दिखाई देगा और वैसे भी टाइप करें।
डेडुप्लिकेटर

3

अक्सर यह कोई तार्किक स्पष्टता नहीं जोड़ता है।

"Add" की तुलना "AddFirstArgumentToSecondArgument" से करें।

यदि आपको एक अधिभार की आवश्यकता है, जो कहते हैं, तीन मान जोड़ता है। क्या मतलब होगा?

तीन तर्कों के साथ एक और "जोड़ें"?

या

"AddFirstAndSecondAndThirdArgument"?

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


4
Addएक कम्यूटेटिव ऑपरेशन का सुझाव देता है। ओपी उन परिस्थितियों से चिंतित है जहां आदेश मायने रखता है।
रोजी एफ

स्विफ्ट में, आप उदाहरण के लिए कॉल ऐड (5, टू: एक्स) या ऐड (5, प्लस: 7, टू: एक्स) या ऐड (5, प्लस: 7, दे: एक्स) जोड़ेंगे यदि आप ऐड () फ़ंक्शन को परिभाषित करते हैं। तदनुसार।
gnasher729

तीसरे ओवरलोड को "सम" नाम दिया जाना चाहिए
स्टिंगजैक

@StringyJack हम्म .. सुम निर्देश नहीं है, यह एक संज्ञा है जो इसे विधि नाम के लिए कम उपयुक्त बनाती है। लेकिन अगर आपको ऐसा लगता है और यदि आप इसके बारे में एक शुद्धतावादी बनना चाहते हैं, तो दो तर्क संस्करण को भी नाम दिया जाना चाहिए। यदि आपके पास कोई ऐड विधि है, तो इसका एक तर्क होना चाहिए जो ऑब्जेक्ट उदाहरण में स्वयं जोड़ा जाता है (जो एक संख्यात्मक या वेक्टर प्रकार होना होगा)। 2 या अधिक तर्क किस्में (जो भी आप उन्हें नाम देंगे) स्थिर होगी। फिर 3 या अधिक तर्क संस्करण निरर्थक होंगे और हमने एक प्लस ऑपरेटर लागू किया होगा: - |
मार्टिन मेट

1
@Martin रुको क्या? sumएक पूरी तरह से क्रियात्मक क्रिया है । यह "विशेष रूप से संक्षेप में" वाक्यांश में आम है।
वू

2

मैं कुछ और जोड़ना चाहता हूं जो अन्य उत्तरों द्वारा संकेत दिया गया है, लेकिन मुझे नहीं लगता कि स्पष्ट रूप से उल्लेख किया गया है:

@puck कहते हैं, "अभी भी कोई गारंटी नहीं है कि फ़ंक्शन नाम में पहले उल्लेखित तर्क वास्तव में पहला पैरामीटर है।"

@ कॉज़र कहते हैं "अस्पष्ट तर्क के बजाय प्रकार का उपयोग करें"

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

assertExpectedEqualsActual(foo, bar)कुछ विकल्पों (इस पृष्ठ और अन्य जगहों से) की तुलना करें , जैसे:

# Putting the arguments in a labelled structure
assertEquals({expected: foo, actual: bar})

# Using a keyword arguments language feature
assertEquals(expected=foo, actual=bar)

# Giving the arguments different types, forcing us to wrap them
assertEquals(Expected(foo), Actual(bar))

# Breaking the symmetry and attaching the code to one of the arguments
bar.Should().Be(foo)

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

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

जैसे कॉल assertEqual(expected, actual)उतने ही समझ में आता है assertEqual(actual, expected), इसलिए हमारे लिए उन्हें मिश्रित करना और मशीन के लिए आगे बढ़ना और गलत काम करना आसान है। यदि हम assertExpectedEqualsActualइसके बजाय उपयोग करते हैं, तो इससे हमें गलती होने की संभावना कम हो सकती है, लेकिन यह मशीन को कोई अधिक जानकारी नहीं देता है (यह अंग्रेजी नहीं समझ सकता है, और नाम की पसंद शब्दार्थ को प्रभावित नहीं करना चाहिए)।

क्या "संरचित" दृष्टिकोण अधिक बेहतर होता है, जैसे कीवर्ड तर्क, फ़ील्ड, अलग-अलग प्रकार, आदि यह है कि अतिरिक्त जानकारी भी मशीन पठनीय है , इसलिए हमारे पास मशीन स्पॉट गलत उपयोग हो सकते हैं और हमें चीजों को सही करने में मदद कर सकते हैं। assertEqualमामले के बाद से केवल एक समस्या यह गलत संदेशों होगा, बहुत बुरा नहीं है। एक और अधिक भयावह उदाहरण हो सकता है String replace(String old, String new, String content), जिसके साथ भ्रमित करना आसान है String replace(String content, String old, String new)जिसका बहुत अलग अर्थ है। एक सरल उपाय एक जोड़ी लेना [old, new]होगा, जो गलतियों को तुरंत त्रुटि देगा (यहां तक ​​कि बिना प्रकार के)।

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

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


1

क्योंकि यह याद रखने की आवश्यकता को हटा देता है कि तर्क कहाँ जाते हैं

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

यदि आप कोड पढ़ते हैं तो आपको आसानी से देखना चाहिए कि जब पैरामीटर का नाम होना चाहिए तो क्या होता है। copy(source, destination)यह समझने की तुलना में समझने में बहुत आसान है copyFromTheFirstLocationToTheSecondLocation(placeA, placeB)

कोडर पूर्व को क्यों नहीं अपनाता है यदि यह लेखक के रूप में है, तो उत्तरार्द्ध की तुलना में स्पष्ट है?

क्योंकि विभिन्न शैलियों पर अलग-अलग दृष्टिकोण हैं और आप अन्य लेखों के एक्स लेखकों को पा सकते हैं जो इसके विपरीत हैं। तुम पागल हो जाना सब कुछ का पालन करने की कोशिश कर रहा है कहीं ;-)


0

मैं मानता हूं कि फ़ंक्शन नामों में एन्कोडिंग पैरामीटर नाम लेखन और कार्यों का उपयोग करके अधिक सहज ज्ञान युक्त बनाता है।

copyFromSourceToDestination( // "...ahh yes, the source directory goes first"

फ़ंक्शन और शेल कमांड में तर्कों के क्रम को भूलना आसान है और कई प्रोग्रामर इस कारण से आईडीई सुविधाओं या फ़ंक्शन संदर्भों पर भरोसा करते हैं। नाम में वर्णित तर्कों का होना इस निर्भरता का एक शानदार समाधान होगा।

हालाँकि एक बार लिखे जाने के बाद, तर्कों का विवरण अगले प्रोग्रामर के लिए फिर से लिखा जाता है, जिसे कथन को पढ़ना होता है, क्योंकि अधिकांश नाम वाले चर का उपयोग किया जाएगा।

copy(sourceDir, destinationDir); // "...makes sense"

इस की थाह सबसे प्रोग्रामर पर जीत जाएगा और मैं व्यक्तिगत रूप से पढ़ने के लिए आसान लगता है।

संपादित करें: जैसा कि @Brfl ने बताया है, एन्कोडिंग पैरामीटर वह 'सहज' नहीं है क्योंकि आपको पहले स्थान पर फ़ंक्शन का नाम याद रखने की आवश्यकता है। इसके लिए फ़ंक्शन संदर्भ देखने या IDE से सहायता प्राप्त करने की आवश्यकता होती है, जो संभवतः वैसे भी पैरामीटर ऑर्डरिंग जानकारी प्रदान करेगा।


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

@Brfl इसे कॉल करने copyFromSourceToDestinationका बिंदु यह है कि यदि आपको लगता है कि यह copyToDestinationFromSourceसंकलक आपकी बग ढूंढ लेगा, लेकिन यदि इसे कॉल किया गया था copy, तो यह नहीं होगा। कॉपी-रुटीन के परम्स को गलत तरीके से गोल करना आसान है, क्योंकि स्ट्रैची, स्ट्रैकट आदि एक मिसाल कायम करते हैं। और क्या यह पढ़ने में आसान है? क्या mergeLists (listA, listB, listC) listB & listC से listA बनाता है, या listA & listB पढ़ता है और listC लिखता है?
रोजी एफ

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

OTOH, डेस्टिनेयर.कॉपी (sourceDir); // "... अधिक समझ में आता है"
क्रिस्टियन एच।

1
@ क्रिशियन किस दिशा में dir1.copy(dir2)काम करता है ? कोई जानकारी नहीं। किस बारे में dir1.copyTo(dir2)?
मैराटिनस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.