ऐसे कार्य जिन्हें केवल अन्य फ़ंक्शन कहते हैं। क्या यह अच्छा अभ्यास है?


13

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

DataTable reportTable = new DataTable();
void RunReport()
{
    reportTable = DataClass.getReportData();
    largeReportProcessingFunction();
    outputReportToUser();
}

मैं इन बड़े फ़ंक्शंस को छोटे चंक्स में तोड़ने में सक्षम होना चाहता हूं, लेकिन मुझे डर है कि मैं दर्जनों गैर-पुन: प्रयोज्य कार्यों को समाप्त कर दूंगा, और एक समान "यहां सब कुछ करते हैं" फ़ंक्शन जिसका एकमात्र काम है इन सभी छोटे कार्यों को कॉल करें, जैसे:

void largeReportProcessingFunction()
{
    processSection1HeaderData();
    calculateSection1HeaderAverages();
    formatSection1HeaderDisplay();
    processSection1SummaryTableData();
    calculateSection1SummaryTableTotalRow();
    formatSection1SummaryTableDisplay();
    processSection1FooterData();
    getSection1FooterSummaryTotals();
    formatSection1FooterDisplay();

    processSection2HeaderData();
    calculateSection1HeaderAverages();
    formatSection1HeaderDisplay();
    calculateSection1HeaderAverages();
    ...
}

या, अगर हम एक कदम आगे जाते हैं:

void largeReportProcessingFunction()
{
    callAllSection1Functions();

    callAllSection2Functions();

    callAllSection3Functions();
    ...        
}

क्या यह वास्तव में एक बेहतर उपाय है? एक संगठनात्मक दृष्टिकोण से, मुझे लगता है कि यह है (अर्थात सब कुछ बहुत अधिक संगठित है, अन्यथा हो सकता है), लेकिन जहाँ तक कोड पठनीयता मुझे यकीन नहीं है (संभवतः कार्यों की बड़ी श्रृंखला जो केवल अन्य कार्यों को कहते हैं)।

विचार?


दिन के अंत में ... क्या यह अधिक पठनीय है? हां, तो यह एक बेहतर उपाय है।
सिल्वानार

जवाबों:


18

यह आमतौर पर कार्यात्मक अपघटन के रूप में जाना जाता है और आम तौर पर एक अच्छी बात है, अगर सही ढंग से किया जाता है।

इसके अलावा, एक समारोह का कार्यान्वयन अमूर्तता के एकल स्तर के भीतर होना चाहिए। यदि आप लेते हैं largeReportProcessingFunction, तो इसकी भूमिका यह निर्धारित करना है कि किस क्रम में विभिन्न प्रसंस्करण कदम उठाए जाने हैं। उन चरणों में से प्रत्येक का कार्यान्वयन नीचे एक अमूर्त परत पर है और largeReportProcessingFunctionसीधे उस पर निर्भर नहीं होना चाहिए।

कृपया ध्यान दें कि यह नामकरण का एक बुरा विकल्प है:

void largeReportProcessingFunction() {
    callAllSection1Functions();
    callAllSection2Functions();
    callAllSection3Functions();
    ...        
}

आप देखते हैं callAllSection1Functionsकि यह एक ऐसा नाम है जो वास्तव में एक अमूर्तता प्रदान नहीं करता है, क्योंकि यह वास्तव में यह नहीं कहता है कि यह क्या करता है, बल्कि यह कैसे करता है। इसे processSection1बदले में कहा जाना चाहिए या जो भी संदर्भ में वास्तव में सार्थक है।


6
मैं इस उत्तर के साथ प्रमुख रूप से सहमत हूं, सिवाय इसके कि मैं यह नहीं देख सकता कि "processSection1" एक सार्थक नाम कैसे है। यह व्यावहारिक रूप से "callAllSection1Functions" के बराबर है।
एरिक किंग

2
@EricKing: callAllSection1Functionsकार्यान्वयन के बारे में विवरण लीक करता है। बाहर के दृष्टिकोण से, यह कोई फर्क नहीं पड़ता कि processSection1क्या यह "सभी अनुभाग 1 कार्यों" के लिए अपने काम को रोकता है या क्या यह सीधे करता है या क्या यह पिक्सी-डस्ट का उपयोग करता है एक गेंडा को बुलाने के लिए जो वास्तविक काम करेगा। यह सब वास्तव में मामला है, कि कॉल करने के बाद processSection1, अनुभाग 1 को संसाधित माना जा सकता है । मैं मानता हूं कि प्रसंस्करण एक सामान्य नाम है, लेकिन अगर आपके पास उच्च सामंजस्य है (जिसे आपको हमेशा के लिए प्रयास करना चाहिए) तो आपका संदर्भ आमतौर पर इसे भंग करने के लिए पर्याप्त संकीर्ण है।
back2dos

2
मेरा मतलब था कि "प्रोसेसएक्सएक्सएक्सएक्स" नामक विधियां लगभग हमेशा भयानक, बेकार नाम हैं। सभी तरीकों की 'प्रक्रिया' चीजें, इसलिए इसे 'प्रोसेसएक्सएक्सएक्सएक्सएक्स' नाम देना उतना ही उपयोगी है जितना कि इसे 'doSomethingWithXXX' या 'मैनिपुलेटिवएक्सएक्सएक्सएक्स' और इसी तरह के नाम देना। 'ProcessXXX' नाम के तरीकों के लिए लगभग हमेशा एक बेहतर नाम है। व्यावहारिक दृष्टिकोण से, यह 'callAllSection1Functions' के रूप में उपयोगी (बेकार) है।
एरिक किंग

4

आपने कहा कि आप C # का उपयोग कर रहे हैं, इसलिए मुझे आश्चर्य है कि यदि आप एक संरचित वर्ग पदानुक्रम का निर्माण कर सकते हैं तो इस तथ्य का लाभ उठा सकते हैं कि आप एक वस्तु-उन्मुख भाषा का उपयोग कर रहे हैं? उदाहरण के लिए, यदि यह रिपोर्ट को खंडों में विभाजित करने के लिए समझ में आता है, तो एक Sectionवर्ग है और इसे ग्राहक विशिष्ट आवश्यकताओं के लिए विस्तारित करें।

इसके बारे में सोचने के लिए समझ में आ सकता है जैसे कि आप एक गैर-इंटरैक्टिव जीयूआई बना रहे थे। उन वस्तुओं के बारे में सोचें जो आप बना सकते हैं जैसे कि वे अलग-अलग जीयूआई घटक थे। अपने आप से पूछें कि एक मूल रिपोर्ट कैसी दिखेगी? कैसे एक जटिल के बारे में? विस्तार बिंदु कहां होना चाहिए?


3

निर्भर करता है। यदि आपके द्वारा बनाए जा रहे सभी कार्य सही मायने में एकल इकाई हैं, तो यह ठीक है, अगर वे अपने कॉलिंग फ़ंक्शन के 1-15, 16-30, 31-45 लाइन हैं, जो खराब है। लंबे कार्य बुरे नहीं हैं, यदि वे एक काम करते हैं, यदि आपके पास अपनी रिपोर्ट के लिए 20 फिल्टर हैं जो एक वैध फ़ंक्शन है जो सभी बीस की जांच करता है तो यह लंबा होगा। यह ठीक है, इसे फ़िल्टर या फ़िल्टर के समूहों द्वारा तोड़ना सिर्फ वास्तविक लाभ के लिए अतिरिक्त जटिलता जोड़ रहा है।

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


3
मेरे अनुभव में, लंबे समय कार्यों हैं बुराई।
बर्नार्ड

यदि आपका उदाहरण OO भाषा में था, तो मैं एक बेस फ़िल्टर क्लास बनाऊंगा और प्रत्येक 20 फ़िल्टर अलग-अलग व्युत्पन्न कक्षाओं में होंगे। सही फ़िल्टर प्राप्त करने के लिए स्विच स्टेटमेंट को एक निर्माण कॉल द्वारा प्रतिस्थापित किया जाएगा। प्रत्येक कार्य एक काम करता है और सभी छोटे होते हैं।
DXM

3

चूँकि आप C # का उपयोग कर रहे हैं, कोशिश करें और वस्तुओं में अधिक सोचें। ऐसा लगता है कि आप अभी भी "वैश्विक" वर्ग चर रहे हैं जो बाद के कार्यों पर निर्भर करते हुए प्रक्रियात्मक रूप से कोडिंग कर रहे हैं।

अलग-अलग कार्यों में अपने तर्क को तोड़ना निश्चित रूप से एक ही फ़ंक्शन में सभी तर्क रखने से बेहतर है। मैं शर्त लगा सकता हूं कि कई वस्तुओं में इसे तोड़कर कार्य करने वाले डेटा को भी अलग करके आप आगे बढ़ सकते हैं।

ReportBuilder वर्ग होने पर विचार करें जहां आप रिपोर्ट डेटा में पास कर सकते हैं। यदि आप अलग-अलग वर्गों में ReportBuilder को तोड़ सकते हैं तो यह भी करें।


2
कार्यविधियाँ पूरी तरह से अच्छा कार्य करती हैं।
डेडएमजी

1

हाँ।

यदि आपके पास एक कोड सेगमेंट है जिसे कई स्थानों पर स्वयं के फ़ंक्शन में उपयोग करने की आवश्यकता है। अन्यथा यदि आपको कार्यक्षमता में परिवर्तन करना है तो आपको कई स्थानों पर परिवर्तन करने की आवश्यकता होगी। यह न केवल काम को बढ़ाता है, बल्कि कीड़े के जोखिम को बढ़ाता है क्योंकि कोड एक स्थान पर बदल जाता है, लेकिन एक या दूसरे स्थान पर नहीं, बल्कि एक जगह पर पेश किया जाता है, लेकिन दूसरे में नहीं।

यदि वर्णनात्मक विधि नामों का उपयोग किया जाता है तो यह विधि को अधिक पठनीय बनाने में भी मदद करता है।


1

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

processSection1HeaderData();
processSection2HeaderData();

क्या अनुभाग हेडर को संसाधित करने के लिए प्रयुक्त कोड में कोई समानता नहीं है? क्या आप अंतरों को मापकर दोनों के लिए एक सामान्य फ़ंक्शन निकाल सकते हैं?


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

1

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

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


0

मुझे लगता है कि यह ज्यादातर व्यक्तिगत पसंद है। यदि आपके कार्यों का पुन: उपयोग होने जा रहा है (और क्या आप सुनिश्चित हैं कि आप उन्हें अधिक सामान्य और पुन: प्रयोज्य नहीं बना सकते?) मैं निश्चित रूप से कहूंगा कि उन्हें विभाजित करें। मैंने यह भी सुना है कि यह एक अच्छा सिद्धांत है कि किसी भी फ़ंक्शन या विधि में कोड के 2-3 से अधिक स्क्रीन नहीं होने चाहिए। इसलिए यदि आपका बड़ा कार्य अभी और आगे बढ़ता है, तो यह आपके कोड को विभाजित करने के लिए अधिक पठनीय बना सकता है।

आप उल्लेख नहीं करते हैं कि आप इन रिपोर्ट को विकसित करने के लिए किस तकनीक का उपयोग कर रहे हैं। ऐसा लगता है कि आप C # का उपयोग कर रहे होंगे। क्या वो सही है? यदि ऐसा है, तो आप # भाग निर्देश को भी विकल्प के रूप में मान सकते हैं यदि आप अपने कार्य को छोटे लोगों में विभाजित नहीं करना चाहते हैं।


हां, मैं C # में काम कर रहा हूं। यह संभव है कि मैं कुछ कार्यों का पुन: उपयोग करने में सक्षम हो जाऊंगा, लेकिन इनमें से कई रिपोर्टों के लिए अलग-अलग वर्गों के पास अलग-अलग डेटा और लेआउट (ग्राहक की आवश्यकता) हैं।
एरिक सी।

1
+1 सुझाव क्षेत्रों को छोड़कर। मैं क्षेत्रों का उपयोग नहीं करूंगा।
बर्नार्ड

@ बर्नार्ड - कोई विशेष कारण? मैं मान रहा हूँ कि यदि वह पहले से ही फूट डालने से इनकार करता है, तो पूछने वाला # भाग का उपयोग करने पर विचार करेगा।
जोशुआ कारमोडी

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

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