क्या मुझे किसी फ़ंक्शन में विशिष्ट कार्यक्षमता को निकालना चाहिए और क्यों?


29

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

जाहिर है, यह मुख्य फ़ंक्शन में कोड की कम पंक्तियाँ बनाएगा, लेकिन अतिरिक्त फ़ंक्शन की घोषणाएँ होंगी, इसलिए मेरी कक्षा में अतिरिक्त विधियाँ होंगी, जिनका मानना ​​है कि यह अच्छा नहीं है, क्योंकि यह कक्षा को और अधिक जटिल बना देगा।

क्या मुझे ऐसा करना चाहिए, इससे पहले कि मैं सभी कोड लिखूं या मुझे इसे तब तक छोड़ देना चाहिए जब तक कि सब कुछ पूरा न हो जाए और फिर फ़ंक्शन निकालें?


19
"मैं इसे तब तक छोड़ देता हूं जब तक कि सब कुछ नहीं हो जाता है" आमतौर पर "यह कभी नहीं किया जाएगा" का पर्याय है।
व्यंग्यात्मक

2
यह आम तौर पर सच है, लेकिन YAGNI के विपरीत सिद्धांत को भी याद रखें (जो इस मामले में लागू नहीं होता है, क्योंकि आपको पहले से ही इसकी आवश्यकता है)।
jhocking


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

जवाबों:


35

यह एक पुस्तक है जिसे मैं अक्सर लिंक करता हूं, लेकिन यहां मैं फिर से जाता हूं: रॉबर्ट सी। मार्टिन का क्लीन कोड , अध्याय 3, "फ़ंक्शंस"।

जाहिर है, यह मुख्य फ़ंक्शन में कोड की कम पंक्तियाँ बनाएगा, लेकिन अतिरिक्त फ़ंक्शन की घोषणाएँ होंगी, इसलिए मेरी कक्षा में अतिरिक्त विधियाँ होंगी, जिनका मानना ​​है कि यह अच्छा नहीं है, क्योंकि यह कक्षा को और अधिक जटिल बना देगा।

क्या आप +150 लाइनों के साथ एक फ़ंक्शन पढ़ना पसंद करते हैं, या 3 +50 लाइन फ़ंक्शन को फ़ंक्शन करना पसंद करते हैं? मुझे लगता है कि मैं दूसरा विकल्प पसंद करता हूं।

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

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

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

अंत में, और जो मैंने अभी लिखा है, उसके विपरीत नहीं है, अपने आप से पूछें कि क्या आपको वास्तव में इस रीफैक्टरिंग को करने की आवश्यकता है, " जब रिफ्लेक्टर करना है ?" (यह भी, "रीफैक्टरिंग" पर एसओ प्रश्नों की खोज करें, और अधिक हैं और उत्तर पढ़ने के लिए दिलचस्प हैं)

क्या मुझे ऐसा करना चाहिए, इससे पहले कि मैं सभी कोड लिखूं या मुझे इसे तब तक छोड़ देना चाहिए जब तक कि सब कुछ पूरा न हो जाए और फिर फ़ंक्शन निकालें?

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


10
दरअसल, बॉब मार्टिन ने कई बार दिखाया है कि वह 15 फ़ंक्शन के साथ एक फ़ंक्शन पर 2 से 3 लाइनों के साथ 7 फ़ंक्शंस पसंद करता है (यहां साइटें देखें। URLsite/unclebobconsultingllc/… )। और यही कारण है कि बहुत से अनुभवी देवता भी विरोध कर रहे हैं। व्यक्तिगत रूप से, मुझे लगता है कि उन "अनुभवी देवों" में से बहुतों को यह स्वीकार करने में परेशानी होती है कि वे कोडिंग के 10 वर्षों के बाद भी इस तरह की बुनियादी चीज़ों में सुधार कर सकते हैं जैसे कि कार्यों के साथ सार का निर्माण करना।
डॉक ब्राउन

+1 केवल एक पुस्तक का संदर्भ देने के लिए, जो मेरे मामूली विचार के लिए, किसी भी सॉफ्टवेयर कंपनी की अलमारियों में होनी चाहिए।
फैबियो मारकोलिनी

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

आप बिल्कुल सही कह रहे है!
जलयंत्र

निर्भर करता है कि तीन अलग-अलग कार्यों को आपस में जोड़ा गया है। कोड के एक ब्लॉक का पालन करना आसान हो सकता है जो कोड के तीन ब्लॉकों की तुलना में एक ही स्थान पर है जो बार-बार एक दूसरे पर भरोसा करते हैं।
user253751

13

हाँ, ज़ाहिर है। यदि एकल फ़ंक्शन के विभिन्न "कार्यों" को देखना और अलग करना आसान है।

  1. पठनीयता - अच्छे नामों वाले कार्य यह स्पष्ट करते हैं कि किस कोड को उस कोड को पढ़ने की आवश्यकता नहीं है।
  2. पुन: प्रयोज्यता - ऐसे फ़ंक्शन का उपयोग करना आसान है जो कई स्थानों पर एक कार्य करता है, जो कि उन फ़ंक्शन की तुलना में जिनकी आपको आवश्यकता नहीं है।
  3. परीक्षणशीलता - फ़ंक्शन का परीक्षण करना आसान है, जिसमें एक परिभाषित "फ़ंक्शन" है, जिसमें से उनमें से कई हैं

लेकिन इसके साथ समस्याएं हो सकती हैं:

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

5

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

क्या लंबे कार्यों और विधियों को छोटे लोगों में विभाजित करना ठीक है, भले ही उन्हें किसी और चीज से नहीं बुलाया जाएगा?

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

समर्थक:

  • एक बार जब आप इसे पढ़ लेते हैं, तो आपको उन सभी ऑप्रेशनों पर पूर्ण विचार होता है जो फ़ंक्शन करता है (आप इसे एक पुस्तक के रूप में पढ़ सकते हैं);
  • यदि आप इसे डीबग करना चाहते हैं, तो आप इसे बिना किसी छलांग के किसी भी अन्य फ़ाइल / फ़ाइल के हिस्से पर चरण दर चरण निष्पादित कर सकते हैं;
  • आपको फ़ंक्शन के किसी भी चरण में घोषित किसी भी चर का उपयोग / उपयोग करने की स्वतंत्रता है;
  • एल्गोरिथ्म फ़ंक्शन फ़ंक्शन को पूरी तरह से फ़ंक्शन (निहित) में निहित करता है;

कॉन्ट्रा:

  • यह आपकी स्क्रीन के कई पृष्ठ लेता है;
  • इसे पढ़ने में लंबा समय लगता है;
  • सभी विभिन्न चरणों को याद रखना आसान नहीं है;

अब कल्पना करें कि लंबे फ़ंक्शन को कई उप-कार्यों में विभाजित करें और उन्हें एक व्यापक संभावना के साथ देखें।

समर्थक:

  • छुट्टी-कार्यों को छोड़कर, प्रत्येक फ़ंक्शन शब्दों (उप-कार्यों के नाम) के साथ किए गए विभिन्न चरणों का वर्णन करता है;
  • प्रत्येक एकल फ़ंक्शन / उप-फ़ंक्शन को पढ़ने के लिए बहुत कम समय लगता है;
  • यह स्पष्ट है कि प्रत्येक उप-फ़ंक्शन (चिंताओं को अलग करना) पर क्या पैरामीटर और चर प्रभावित होते हैं;

कॉन्ट्रा:

  • यह कल्पना करना आसान है कि "पाप ()" जैसा कोई फ़ंक्शन क्या करता है, लेकिन यह कल्पना करना आसान नहीं है कि हमारे उप-कार्य क्या करते हैं;
  • एल्गोरिथ्म अब गायब हो गया है, यह अब उप-कार्यों (कोई अवलोकन) में वितरित किया जा सकता है;
  • जब यह कदम दर कदम डिबगिंग करता है, तो आप जिस गहराई स्तर के फंक्शन कॉल को भूल जाते हैं, उसे भूल जाना आसान होता है (यहां और अपने मोबाइल फोन में कूदकर);
  • विभिन्न उप-कार्यों को पढ़ते समय आप आसानी से संदर्भ को ढीला कर सकते हैं;

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


2

मेरे लिए कार्यों में कोड ब्लॉक निकालने के चार कारण हैं:

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

  • यह एक कॉलबैक है : यह एक घटना हैंडलर या किसी प्रकार का उपयोगकर्ता कोड एक पुस्तकालय या एक फ्रेम कॉल है। (कार्य किए बिना मैं शायद ही इसकी कल्पना कर सकता हूं।)

  • आप मानते हैं कि इसे पुन: उपयोग किया जाएगा , वर्तमान परियोजना में या शायद कहीं और: आपने सिर्फ एक ब्लॉक लिखा है जो दो सरणियों की सबसे लंबी सामान्य गणना की गणना करता है। यहां तक ​​कि अगर आपका कार्यक्रम केवल एक बार इस फ़ंक्शन को कॉल करता है, तो मुझे विश्वास है कि मुझे इस फ़ंक्शन को अंततः अन्य परियोजनाओं में भी आवश्यकता होगी।

  • आप स्व-दस्तावेजीकरण कोड चाहते हैं : इसलिए कोड के एक ब्लॉक पर टिप्पणी की एक पंक्ति लिखने के बजाय यह क्या करता है, आप पूरी बात को एक फ़ंक्शन में निकालते हैं, और इसे नाम देते हैं जो आप एक टिप्पणी में लिखते हैं। हालाँकि मैं इसका प्रशंसक नहीं हूं, क्योंकि मुझे इस्तेमाल किए गए एल्गोरिदम का नाम लिखना पसंद है, यही वजह है कि मैंने उस एल्गोरिदम को चुना है, आदि फ़ंक्शन नाम तब बहुत लंबे होंगे ...


1

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

इसके अलावा, फ़ंक्शन तार्किक प्रवाह के कंटेनर हैं। इसमें केवल एक ही रास्ता है, तरीके स्पष्ट रूप से चिह्नित हैं, और यदि फ़ंक्शन पर्याप्त रूप से छोटा है, तो आंतरिक प्रवाह स्पष्ट होना चाहिए। इसमें साइक्लोमैटिक जटिलता को कम करने का प्रभाव है जो दोषों की दर को कम करने का एक विश्वसनीय तरीका है।


0

इसके अलावा: मैंने इसे डैलिन के सवाल (अब बंद) के जवाब में लिखा था, लेकिन मुझे अभी भी लगता है कि यह किसी के लिए मददगार हो सकता है इसलिए वह यहां आता है


मुझे लगता है कि एटमाइजिंग कार्यों का कारण 2 गुना है, और @jozefg उल्लेख के रूप में इस्तेमाल की जाने वाली भाषा पर निर्भर है।

चिंताओ का विभाजन

ऐसा करने का मुख्य कारण कोड के अलग-अलग टुकड़ों को अलग-अलग रखना है, इसलिए कोड का कोई भी ब्लॉक जो सीधे फ़ंक्शन के वांछित परिणाम / इरादे में योगदान नहीं करता है, एक अलग चिंता है और इसे निकाला जा सकता है।

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

जावास्क्रिप्ट में कहें कि आपके पास एक फ़ंक्शन getMyData () है, जो 1) मापदंडों से एक साबुन संदेश बनाता है, 2) एक सेवा संदर्भ को प्रारंभ करता है, 3) साबुन संदेश के साथ सेवा को कॉल करता है, 4) परिणाम को पार्स करता है, 5) परिणाम देता है। उचित लगता है, मैंने इस सटीक फ़ंक्शन को कई बार लिखा है - लेकिन वास्तव में इसे 3 निजी कार्यों में विभाजित किया जा सकता है जिसमें केवल 3 और 5 के लिए कोड शामिल है (यदि ऐसा है) तो अन्य कोड में से कोई भी सेवा से डेटा प्राप्त करने के लिए सीधे जिम्मेदार नहीं है। ।

बेहतर डिबगिंग अनुभव

यदि आपके पास पूरी तरह से परमाणु कार्य हैं, तो आपका स्टैक ट्रेस एक कार्य सूची बन जाता है, सभी सफलतापूर्वक निष्पादित कोड को सूचीबद्ध करता है, अर्थात:

  • मेरा डेटा प्राप्त करें
    • साबुन संदेश बनाएँ
    • प्रारंभिक सेवा संदर्भ
    • पार्स की गई सेवा प्रतिक्रिया - ERROR

अधिक दिलचस्प होगा तो यह पता लगाना कि डेटा प्राप्त करते समय कोई त्रुटि थी। लेकिन कुछ उपकरण विस्तृत कॉल ट्री को डीबग करने के लिए और भी उपयोगी होते हैं, उदाहरण के लिए, Microsofts Debugger Canvas को लें

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

FYI करें - यह उन लोगों में से एक है "जैसा कि मैं कहता हूं कि मैं ऐसा नहीं करता हूं", कोड को परमाणु रखना तब तक बेकार है जब तक कि आपका निर्दयतापूर्वक यह IMHO के अनुरूप नहीं है, जो मैं नहीं हूं।

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