क्या लंबे तरीके हमेशा खराब होते हैं? [बन्द है]


64

इसलिए पहले के आस-पास देखने पर मुझे कुछ तरीकों के बारे में ध्यान आया जिसमें लंबे तरीकों के खराब होने के बारे में बताया गया था।

मुझे यकीन नहीं है कि मैं हमेशा मानता हूं कि लंबे तरीके खराब हैं (और दूसरों से राय चाहते हैं)।

उदाहरण के लिए मेरे पास कुछ Django के विचार हैं जो उन्हें दृश्य में भेजने से पहले वस्तुओं के प्रसंस्करण का एक सा करते हैं, एक लंबी विधि कोड की 350 पंक्तियाँ हैं। मेरे पास मेरा कोड लिखा गया है ताकि यह क्वेरीज़ को छांटने / फ़िल्टर करने के लिए मापदंडों के साथ काम करता है - फिर बिट द्वारा कुछ वस्तुओं पर कुछ प्रसंस्करण होता है जो मेरी क्वेरी वापस आ गई है।

तो प्रसंस्करण मुख्य रूप से सशर्त एकत्रीकरण है, जिसमें जटिल पर्याप्त नियम हैं जो आसानी से डेटाबेस में नहीं हो सकते हैं, इसलिए मेरे पास मुख्य लूप के बाहर घोषित कुछ चर हैं फिर लूप के दौरान बदल जाते हैं।

variable_1 = 0
variable_2 = 0
for object in queryset :
     if object.condition_condition_a and variable_2 > 0 :
     variable 1+= 1
     .....
     ...    
     . 
      more conditions to alter the variables

return queryset, and context 

इसलिए सिद्धांत के अनुसार मुझे सभी कोड को छोटे तरीकों में बदलना चाहिए, ताकि मेरे पास अधिकतम एक पृष्ठ लंबा होने के रूप में दृश्य विधि हो।

हालाँकि अतीत में विभिन्न कोड आधारों पर काम करते हुए, मुझे कभी-कभी लगता है कि यह कोड को कम पठनीय बनाता है, जब आपको अपने सिर के सबसे बाहरी तरीके को ध्यान में रखते हुए इसके सभी भागों में लगातार एक विधि से छलांग लगाने की आवश्यकता होती है।

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

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

तो क्या ऐसा मामला है कि लंबे तरीके हमेशा खराब नहीं होते हैं? लेखन विधियों के लिए हमेशा एक मामला होता है, जब वे केवल एक ही स्थान पर उपयोग किए जाएंगे?

अद्यतन: लगता है जैसे मैंने यह सवाल एक साल पहले पूछा था।

इसलिए मैंने यहाँ (मिश्रित) प्रतिक्रिया के बाद कोड को रीक्रिएट किया, इसे विधियों में विभाजित किया। यह डेटाबेस से संबंधित वस्तुओं के जटिल सेटों को पुनर्प्राप्त करने वाला एक Django ऐप है, इसलिए परीक्षण तर्क बाहर है (परीक्षण मामलों के लिए प्रासंगिक ऑब्जेक्ट बनाने के लिए संभवत: अधिकांश वर्ष लगेंगे। मेरे पास "कल की गई यह आवश्यकताएं" प्रकार हैं। किसी से शिकायत होने से पहले काम का माहौल)। कोड के उस हिस्से में कीड़े को ठीक करना अब थोड़ा आसान है, लेकिन बड़े पैमाने पर ऐसा नहीं है।

इससे पहले :

#comment 1 
bit of (uncomplicated) code 1a  
bit of code 2a

#comment 2 
bit of code 2a
bit of code 2b
bit of code 2c

#comment 3
bit of code 3

अभी:

method_call_1
method_call_2
method_call_3

def method_1 
    bit of (uncomplicated) code 1a  
    bit of code 2a

def method_2 
    bit of code 2a
    bit of code 2b
    bit of code 2c

def method_3
    bit of code 3

156
सभी निरपेक्ष बुरे हैं। हमेशा।
जोकिम सॉर

30
मैं "अर्क विधियों को देखता हूं यदि आप उन्हें पुन: उपयोग कर सकते हैं" तर्क काफी बार (इस या इसी तरह के रूपों में), लेकिन मैं इसे नहीं खरीदता हूं: यदि विधि एक से अधिक काम कर रही है, तो आपको पठनीयता के लिए इसमें से तरीके निकालने चाहिए / रख-रखाव भी अगर उन नए तरीकों अपने कोड में केवल एक ही जगह से कहा जाता है।
जोआचिम सॉर

4
@gnat: वाह, बिल्ड-स्टेप में किसी तरह का मैनुअल इनलाइनिंग (प्रीप्रोसेसर के माध्यम से) यहां बेहतर समाधान नहीं होगा?
जोकिम सॉर

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

2
लंबे तरीके हमेशा खराब नहीं होते हैं; लेकिन वे कुछ ऐसी चीजें हैं जिन्हें आपको हमेशा देखना चाहिए और खुद से पूछना चाहिए "क्या यह बुरा है?"
कार्सन 63000

जवाबों:


80

नहीं, लंबे तरीके हमेशा खराब नहीं होते हैं।

पुस्तक कोड कम्प्लीट में , यह मापा जाता है कि लंबी विधियाँ कभी-कभी तेज और आसानी से लिखी जाती हैं, और रखरखाव की समस्याओं को जन्म नहीं देती हैं।

वास्तव में, DRY रहना और चिंताओं को अलग करने का सम्मान करना वास्तव में महत्वपूर्ण है। कुछ समय के लिए, गणना लिखने के लिए लंबा है, लेकिन वास्तव में भविष्य में समस्या का कारण नहीं होगा।

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

संपादित करें: जैसे ही टिप्पणी की जाती है, मैं उत्तर के लिए एक दिलचस्प बिंदु जोड़ता हूं। मैं वास्तव में फ़ंक्शन (NPATH, साइक्लोमैटिक जटिलता या बेहतर CRAP) के लिए जटिलता मेट्रिक्स की भी जांच करूंगा।

वास्तव में, मैं लंबे कार्यों पर ऐसे मैट्रिक्स की जांच नहीं करने की सलाह देता हूं, लेकिन स्वचालित साधनों (जैसे उदाहरण के लिए जावा के लिए चेकस्टाइल) के साथ उन पर अलर्ट शामिल करने के लिए।


41
+1: "नहीं, लंबे तरीके खराब नहीं होते हैं" लेकिन वे लगभग हमेशा खराब होते हैं
बाइनरी वॉरियर

67
लंबी विधि निकायों एक शास्त्रीय कोड गंध हैं : यह अपने आप में एक समस्या नहीं है, लेकिन यह एक संकेत है कि शायद वहाँ एक समस्या है।
जोआचिम सॉर

6
+1, लेकिन मैं फिर भी लंबी विधि की चक्रीय जटिलता की जाँच करने की सलाह दूंगा । उच्च मान उन विधियों को इंगित करते हैं जो इकाई परीक्षण के लिए प्रभावी रूप से असंभव हैं (और लंबी विधियां बहुत कम ही नियंत्रण प्रवाह तर्क से रहित हैं)।
डैनियल बी

11
मैं टिप्पणियों को कम करने के लिए विधि नामों का उपयोग करता हूं। जो कभी-कभी "getSelectedNodeWithChildren" जैसे सामान की ओर जाता है, लेकिन मेरे सहयोगी मुझे बताते रहते हैं, कि मेरा कोड अच्छी तरह से पढ़ा जा सकता है। मैं संक्षिप्ताक्षर से बचने की भी कोशिश करता हूं, वे लिखना अच्छा लगता है, लेकिन पढ़ने में अच्छा नहीं लगता।
के ..

4
@ da_b0uncer वह भी एक नीति है जिसका मैं पालन करता हूं। कोड को लिखने की तुलना में पढ़ना कठिन है, इसलिए कोड को अधिक पठनीय बनाने के लिए लिखते समय अतिरिक्त प्रयास वापस भुगतान करता है।
deadalnix

55

यहां ज्यादातर ध्यान हमेशा शब्द के आसपास लगता है । हां, निरपेक्षता खराब है, और सॉफ्टवेयर इंजीनियरिंग लगभग कला है जितना विज्ञान है, और यह सब ... लेकिन मैं यह कहने जा रहा हूं कि आपके द्वारा दिए गए उदाहरण के लिए, विधि बेहतर होगी यदि इसे विभाजित किया गया था यूपी। ये वे तर्क हैं जो मैं आमतौर पर आपके तरीके को विभाजित करने के लिए उपयोग करता हूं:

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

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

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

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

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

मुझे यह भी लगता है कि इस मामले में, एक लंबा तरीका होने का बहाना है "... मुख्य लूप के बाहर घोषित किए गए कुछ चर तब लूप के दौरान बदल जाते हैं"। मैं पाइथन का विशेषज्ञ नहीं हूं, लेकिन मैं काफी हद तक निश्चित हूं कि इस समस्या को कुछ संदर्भों द्वारा पारित किया जा सकता है।


13
प्रश्न के हमेशा भाग को नष्ट करने और मांस पर ध्यान केंद्रित करने के लिए +1: लंबे तरीके खराब हैं या नहीं। मुझे लगता है कि ओपी औचित्य की तलाश कर रहा है जैसे कि उसका परिदृश्य एक किनारे का मामला है, हालांकि आमतौर पर जब मैं सुनता हूं कि लोग अपने बुरे व्यवहारों को असामान्य परिदृश्य के लिए आवश्यक बताते हैं, तो यह सिर्फ इसलिए है क्योंकि वे अच्छी प्रथाओं का उपयोग करने के लिए बहुत कठिन प्रयास नहीं करते थे। असामान्य परिदृश्य वास्तव में बहुत ही असामान्य हैं, लंबी विधियां दुख की बात है लेकिन काफी सामान्य हैं।
जिमी हॉफ

2
ऊपर दी गई सूची को देखते हुए ठीक है: पिछले अनुभव से पठनीयता मैं कहूंगा कि विधि लंबे समय तक रहने से बढ़ जाती है, जिसमें बहुत सारी टिप्पणियां होती हैं, और अच्छी तरह से स्वरूपित होती हैं, बजाय कोड से विधि के बारे में छलांग लगाने के तरीकों से। हालांकि यह संभवतः काफी व्यक्तिपरक है। मुझे उम्मीद नहीं है कि कोड के कुछ हिस्सों का पुन: उपयोग किया जाएगा। कोड का पुन: उपयोग वर्तमान में विरासत से प्राप्त किया जाता है।
wobbily_col

1
@wobbily_col BTW, यदि आप एक अच्छी तरह से लिखे गए पाठ की तलाश कर रहे हैं, जो छोटी विधियों के औचित्य से गुजरता है, तो क्लीन कोड के पहले कुछ अध्यायों को पढ़ें , जो स्पष्टीकरण का एक अच्छा काम करता है।
डैनियल बी

5
@wobbily_col आप कहते हैं कि कई तरीकों से कोड को समझने के लिए बहुत अधिक कूदने के लिए भ्रमित होना, मुझे लगता है कि यहां लापता बिंदु नामकरण के महत्व पर है। यदि कोई विधि अच्छी तरह से नामित है, तो आपको यह देखने के लिए यह देखने की आवश्यकता नहीं है कि यह क्या कर रहा है, कॉलिंग विधि पूरी तरह से किसी भी अंतर्निहित ज्ञान के बिना समझ में आनी चाहिए कि यह किस तरीके से कॉल कर रही है, उदाहरण के लिए आपने कभी उपयोग किया है someVar.toString()और महसूस किया है। आपको यह जानने के लिए कि यह क्या कर रहा है, स्ट्रिंग के कोड को देखने की आवश्यकता है? आप सिर्फ अच्छी विधि नामकरण के कारण इसे ठीक से पढ़ते हैं।
जिम्मी हॉफ

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

28

लंबे तरीके हमेशा खराब होते हैं, लेकिन कभी-कभी विकल्पों की तुलना में बेहतर होते हैं।


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

9

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

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


7

लंबे तरीके हमेशा खराब नहीं होते हैं। वे आमतौर पर एक संकेत हैं कि कोई समस्या हो सकती है।

जिस सिस्टम पर मैं काम कर रहा हूं, उस पर हमारे पास आधा दर्जन या इतनी विधियाँ हैं जो 10,000 से अधिक लंबी हैं। एक वर्तमान में 54,830 लाइनें लंबी हैं। और यह ठीक है।

ये हास्यास्पद रूप से लंबे कार्य बहुत सरल हैं और ऑटोगेन्सर हैं। उस बड़ी ५४, motion३० लाइन लंबे राक्षस में १ जनवरी १ ९ ६२ से १० जनवरी, २०१२ (हमारा अंतिम विमोचन) का दैनिक ध्रुवीय गति डेटा है। हम एक प्रक्रिया भी जारी करते हैं जिसके द्वारा हमारे उपयोगकर्ता उस ऑटोजेनरेटेड फ़ाइल को अपडेट कर सकते हैं। उस स्रोत फ़ाइल में http://data.iers.org/products/214/14443/orig/eopc04_08_IAU2000.62-now , auto- अनुवादित से C ++ तक का ध्रुवीय गति डेटा है ।

मक्खी पर उस वेब साइट को पढ़ना एक सुरक्षित इंस्टॉलेशन में संभव नहीं है। बाहर की दुनिया से कोई संबंध नहीं है। वेब साइट को स्थानीय कॉपी के रूप में डाउनलोड करना और C ++ में पार्स करना कोई विकल्प नहीं है; पार्सिंग धीमा है , और यह तेज होना है। डाउनलोड करना, C ++ में ऑटो-ट्रांसलेट करना और संकलन करना: अब आपके पास कुछ ऐसा है जो तेज है। (बस इसे अनुकूलित संकलित न करें। यह आश्चर्यजनक है कि कब तक एक अनुकूलन संकलक अत्यंत सरल सीधी रेखा कोड की 50,000 पंक्तियों को संकलित करने में लेता है। मेरे कंप्यूटर पर आधे घंटे से अधिक समय लगता है यह संकलन करने के लिए कि एक फ़ाइल अनुकूलित है। और अनुकूलन बिल्कुल कुछ भी नहीं पूरा करता है। अनुकूलन करने के लिए कुछ भी नहीं है। यह सरल सीधी रेखा कोड है, एक के बाद एक असाइनमेंट स्टेटमेंट।)


6
"एक के बाद एक असाइनमेंट स्टेटमेंट" ... मैं उस "डेटा फ़ाइल" को कॉल करूंगा। यह कोड क्यों है?
जोकिम सॉर

3
@JoachimSauer - क्योंकि मोंटे कार्लो सेटअप में एक बड़े डेटा फ़ाइल को पार्स करना एक बुरा विचार है। एक बहुत, बहुत बुरा विचार।
डेविड हैमेन

4
@David Hammen: फिर इसे आरंभीकरण समय पर करें, जैसे आप अपने लिंकर / लोडर को करने के लिए मजबूर कर रहे हैं। या सी कोड के बजाय हेडर फ़ाइल में सी संरचना के रूप में डेटा फ़ाइल लिखें। कम से कम तब लोडर डेटा ब्लॉक के रूप में लोड होगा।
जेवियर

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

7
+1 दिलचस्प कहानी। उत्पन्न कोड वास्तव में स्रोत कोड नहीं है, इसलिए कोई यह तर्क दे सकता है कि यह नियम को नहीं तोड़ता है। एक कोड जनरेटर ही अच्छा लघु तरीकों था मान लेता है
jk।

7

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

एक से अधिक लूप्स के लिए माना जाता है कि एक हिट परफॉरमेंस हिट हो रहा है, बिना माप के यह जानने का कोई तरीका नहीं है। एकाधिक छोटे लूप काफी तेजी से हो सकते हैं यदि इसका मतलब है कि इसकी जरूरत की हर चीज कैश में रह सकती है। यहां तक ​​कि अगर कोई प्रदर्शन हिट है, तो यह आमतौर पर पठनीयता के पक्ष में नगण्य है।

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


1
"इसमें जाँच करने से पहले रिफ्लेक्टर की योजना बनाने में कुछ भी गलत नहीं है।" उसके लिए +1। आजकल ज्यादातर IDE में रिफ्लेक्टरिंग टूल होते हैं जो इसे बेहद आसान बनाते हैं। लेकिन एक उल्टा तरीका है जहां आप चीजों को गैर-मौजूद कार्यों में सौंपते हैं, और बाद में जाकर विधियों को भरते हैं, लेकिन मैं कभी भी उस तरह से कोड नहीं कर पाया हूं, जितना मैंने कोशिश की है।
ताजार्ट

+1 के लिए "आपके सिर में सबसे बाहरी विधि" [रखना] एक संकेत है कि आप इसे सबसे इष्टतम तरीके से नहीं तोड़ रहे हैं, "
माइकल शॉ

4

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


34
हमेशा कम से कम दो प्रोग्रामर शामिल होते हैं: "आप" और "आप, अब से तीन सप्ताह"।
जोकिम सोउर

3

कुछ ऐसा है जिसे हम कार्यात्मक अपघटन कहते हैं, जहाँ कहीं भी संभव हो अपने छोटे तरीकों को तोड़ने के लिए। जैसा कि आपने उल्लेख किया है कि आपकी विधि में छँटाई / छानना शामिल है तो आपके पास इन कार्यों के लिए अलग तरीके या कार्य हैं।

सटीक रूप से, आपकी विधि को केवल 1 कार्य पर लागू किया जाना चाहिए।

और अगर इसे किसी अन्य तरीके से कॉल करने की आवश्यकता है, तो ऐसा करें अन्यथा आप पहले से ही लिख रहे हैं। इसके अलावा पठनीयता के लिए, आप टिप्पणी जोड़ सकते हैं। परंपरागत रूप से, प्रोग्रामर विधि विवरण के लिए बहु-पंक्ति टिप्पणियों (/ **, सी, सी ++, सी # और जावा में) का उपयोग करते हैं और एकल-लाइन टिप्पणियों (// सी, सी ++, सी # और जावा में) का उपयोग करते हैं। वहाँ भी अच्छे प्रलेखन उपकरण उपलब्ध हैं और साथ ही अधिक से अधिक कोड पठनीयता (उदाहरण के लिए। JavaDoc )। यदि आप एक .Net डेवलपर हैं तो आप XML आधारित टिप्पणियों में भी देख सकते हैं।

लूप्स प्रोग्राम के प्रदर्शन को प्रभावित करते हैं और अगर ठीक से उपयोग नहीं किया जाता है तो एप्लिकेशन ओवरहेड हो सकता है। विचार अपने एल्गोरिथ्म को इस तरह से डिजाइन करना है कि आप कम से कम संभव के रूप में नेस्टेड छोरों का उपयोग करें।


"एक फ़ंक्शन को एक ही कार्य करना चाहिए" के रूप में भी जाना जाता है।
भगवानदेव

3

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

दिनचर्या की लंबाई के बारे में कोड पूरा 2 में एक उत्कृष्ट संक्षिप्त चर्चा है।

सैद्धांतिक रूप से सबसे अच्छी 497 अधिकतम लंबाई अक्सर एक या दो पृष्ठों की सूची लिस्टिंग के रूप में वर्णित है, 66 से 132 लाइनें। आधुनिक कार्यक्रमों में कुछ छोटी दिनचर्याओं के साथ मिश्रित लघु दिनचर्या की मात्रा होती है।

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

यदि आप लगभग 200 लाइनों से अधिक लंबी दिनचर्या लिखना चाहते हैं, तो सावधान रहें। अध्ययनों में से किसी ने लागत में कमी, त्रुटि दर में कमी, या दोनों बड़े रूटीन के साथ 200 रेखाओं से बड़े आकार के बीच अंतर किया, और आप कोड की 200 पंक्तियों को पारित करने के लिए समझ की ऊपरी सीमा में चलने के लिए बाध्य हैं। 536 प्रति सेहत प्रतिबंध।


2

एक और वोट कि यह लगभग हमेशा गलत है। मुझे दो मूल मामले मिलते हैं जहाँ यह उचित उत्तर है, हालाँकि:

1) एक विधि जो मूल रूप से सिर्फ अन्य तरीकों का एक गुच्छा कहती है और कोई वास्तविक काम नहीं करती है। आपके पास एक ऐसी प्रक्रिया है जिसे पूरा करने में 50 कदम लगते हैं, आपको इसमें 50 कॉल के साथ एक विधि मिलती है। वहाँ आम तौर पर कुछ भी नहीं है कि ऊपर तोड़ने की कोशिश कर रहा द्वारा प्राप्त किया जा सकता है।

2) डिस्पैचर्स। OOP डिजाइन ने इस तरह के तरीकों से छुटकारा पा लिया है, लेकिन डेटा के आने वाले स्रोत उनके बहुत ही स्वभाव से डेटा हैं और इस प्रकार OOP सिद्धांतों का पालन नहीं कर सकते हैं। डेटा को हैंडल करने वाले कोड में डिस्पैचर रूटीन का किसी प्रकार का होना बिल्कुल असामान्य नहीं है।

मैं यह भी कहूंगा कि ऑटोगेनरेटेड सामान के साथ काम करते समय किसी को भी सवाल पर विचार नहीं करना चाहिए। कोई भी यह समझने की कोशिश नहीं करता है कि ऑटोजेनरेटेड कोड क्या करता है, यह एक कोटा नहीं बल्कि मायने रखता है कि क्या मानव के लिए समझना आसान है।


1
50 कदम की प्रक्रिया को संभवतया कई बाल्टियों में संक्षेपित किया जा सकता है। चरण 1 - 9 पैरामीटर चेक हैं इसलिए पैरामीटर चेकिंग नामक एक नई विधि बनाएं। (मुझे यकीन है कि कुछ उदाहरण हैं जहां यह संभव नहीं है। मुझे एक को देखने में दिलचस्पी होगी)।
साठफुटेरसूड

@sixtyfootersdude: ज़रूर, आप इसे तोड़ सकते हैं। मैंने यह नहीं कहा कि यह असंभव था, मैंने कहा कि इसे तोड़ने से कुछ हासिल नहीं होगा। हालांकि यह 50 कदम नहीं था, मैंने कुछ इस तरह से मारा है: एक खेल की दुनिया बनाना। # 1 ने खाली दुनिया का निर्माण किया, # 2 ने इलाक़ा बनाया और फिर उसके बाद चरणों की एक पूरी गुच्छा को एक तरह से या किसी अन्य तरीके से मालिश किया।
लोरेन Pechtel

& सिक्सफ़ुटर्सडूड: यह आश्चर्यजनक है कि आप कैसे कोड जानते हैं जो आपने कभी नहीं देखा है और इसे कैसे सुधारें।
gnasher729

2

मैं आपके द्वारा दिए गए उदाहरण को संबोधित करना चाहता था:

उदाहरण के लिए मेरे पास कुछ Django के विचार हैं जो उन्हें दृश्य में भेजने से पहले वस्तुओं के प्रसंस्करण का एक सा करते हैं, एक लंबी विधि कोड की 350 पंक्तियाँ हैं। मेरे पास मेरा कोड लिखा गया है ताकि यह पैरामाटर्स से निपटता है - क्वेरी को छांटना / छानना, फिर बिट द्वारा कुछ वस्तुओं पर कुछ प्रसंस्करण होता है जो मेरी क्वेरी वापस आ गई है।

मेरी कंपनी में हमारी सबसे बड़ी परियोजना Django पर बनाई गई है और हमारे पास लंबे समय तक कार्य भी हैं (कई 350 लाइनों से अधिक हैं)। मेरा तर्क है कि हमारे लिए इतना लंबा होने की आवश्यकता नहीं है, और वे हमें चोट पहुँचा रहे हैं।

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

मुझे संदेह है कि आपके विचारों में समान विशेषताएं हैं। मेरे मामले में, मुझे पता है कि यह समस्याओं का कारण बनता है और मैं बदलाव लाने के लिए काम कर रहा हूं। यदि आप इस बात से सहमत नहीं हैं कि यह समस्याएँ पैदा कर रहा है, तो आपको इसे ठीक करने की आवश्यकता नहीं है।


2

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

function nextSlide() {
  var content = getNextSlideContent();
  hideCurrentSlide();
  var newSlide = createSlide(content);
  setNextSlide(newSlide);
  showNextSlide();
}

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

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

जब मैं विधियां बनाता हूं तो मैं आमतौर पर उन्हें विभाजित करने और रणनीति को जीतने के रूप में छोटे तरीकों में विभाजित करता हूं। जैसी विधि

   if (hasMoreRecords()) { ... }

निश्चित रूप से अधिक पठनीय है

if (file.isOpen() && i < recordLimit && currentRecord != null) { ... } 

सही?

मैं मानता हूं कि पूर्ण कथन खराब हैं और इस बात से भी सहमत हैं कि आमतौर पर एक लंबा तरीका खराब होता है।


1

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

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


0

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

एक विधि के लिए 350 रेखाएँ बताती हैं कि बहुत सारे कार्य जो इसे अंजाम दे रहे हैं, उन्हें कहीं और दोहराया जाता है क्योंकि किसी विशेष कार्य को करने के लिए इतनी बड़ी मात्रा में कोड की आवश्यकता होती है।


कोड को कम करने में मदद करें क्या ?
अवनेर शाहर-कश्तन

@ AvnerShahar-Kashtan, वह शायद "दोहराव" का मतलब है :-)
पेटर टॉर्क

0

यह वास्तव में लंबे तरीके नहीं हैं जो बुरे अभ्यास हैं यह अधिक है कि उन्हें इस तरह छोड़ दें कि यह बुरा है।

मेरा मतलब है कि आपके नमूने को फिर से दिखाने का वास्तविक कार्य:

varaible_1 = 0
variable_2 = 0
for object in queryset :
     if object.condition_condition_a and variable_2 > 0 :
     variable 1+= 1
     .....
     ...    
     . 
      more conditions to alter the variables

return queryset, and context 

सेवा

Status status = new Status();
status.variable1 = 0;
status.variable2 = 0;
for object in queryset :
     if object.condition_condition_a and status.variable2 > 0 :
     status.variable1 += 1
     .....
     ...    
     . 
      more conditions to alter the variables (status)

return queryset, and context 

और फिर

class Status {
    variable1 = 0;
    variable2 = 0;

    void update(object) {
        if object.condition_condition_a and variable2 > 0 {
            variable1 += 1
        }
    }
};

Status status = new Status();
for object in queryset :
     status.update(object);
     .....
     ...    
     . 
      more conditions to alter the variables (status)

return queryset, and context 

अब आप न केवल बहुत कम विधि बल्कि बहुत अधिक प्रयोग करने योग्य और समझ में आने वाले रास्ते पर हैं।


0

मुझे लगता है कि तथ्य यह है कि विधि बहुत लंबी है, पर जाँच करने के लिए कुछ है, लेकिन निश्चित रूप से तत्काल विरोधी पैटर्न नहीं है। विशाल तरीकों में देखने के लिए बड़ी बात बहुत से घोंसले के शिकार हैं। यदि आपके पास है

foreach(var x in y)
{
    //do ALL the things
    //....
}

और लूप का शरीर अत्यधिक स्थानीयकृत नहीं है (यानी, आप इसे 4 से कम मापदंडों पर भेज सकते हैं), तो संभवतः इसे इसमें बदलना बेहतर होगा:

foreach(var x in y)
{
    DoAllTheThings(x);
}
...
void DoAllTheThings(object x)
{
    //do ALL the things
    //....
}

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

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


0

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

दूसरी बात, जब कार्यों / प्रक्रियाओं की बात आती है:

void setDataValueAndCheckForRange(Data *data) {/*code*/} 

एक अच्छा तरीका है अगर यह केवल "डेटा" की सीमा के लिए जाँच करता है। यह एक BAD विधि है जब एक ही श्रेणी कई कार्यों के लिए लागू होती है (खराब कोड का उदाहरण):

void setDataValueAndCheckForRange(Data *data){ /*code */}
void addDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}
void subDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}
void mulDataValuesAndCheckForRange(Data *result, Data *d1, Data *d2){ /*code*/}

यह करने के लिए refactored किया जाना है:

bool isWithinRange(Data *d){ /*code*/ }
void setDataValue(Data *d) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void addDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void subDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 
void mulDataValue(Data *d, Data *d1, Data *d2) {/*code*/ if(isWithinRange(d)){/*continue*/}else{/*warn/abort*/} 

जितना संभव हो सके कोड को पुन: लिखें। और यह तब संभव है जब आपके प्रोग्राम का प्रत्येक फंक्शन SIMPLE (जरूरी नहीं कि आसान हो) पर्याप्त हो।

QUOTE: MOUNTAIN पृथ्वी के छोटे दानों से बना है। सागर पानी की छोटी-छोटी बूंदों से बना है .. (- शिवानंद)


0

लंबी विधियाँ अपूर्ण भाषाओं में "खराब" की ओर जाती हैं, जो कथन, पक्ष-प्रभाव और पारस्परिकता के पक्ष में हैं, ठीक है क्योंकि उन विशेषताओं में जटिलता और इस प्रकार कीड़े बढ़ जाते हैं।

कार्यात्मक प्रोग्रामिंग भाषाओं में, जो भाव, शुद्धता और अपरिवर्तनीयता के पक्ष में हैं, चिंता का कारण कम है।

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


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