क्या पुनरावृत्त विधियाँ चक्रीय जटिलता को कम करती हैं और समर्थन क्षमता में सुधार करती हैं?


11

क्या पुनरावृत्त तरीके जैसे कि आधुनिक भाषाओं में आमतौर पर C #, जावास्क्रिप्ट, और (उम्मीद है) जावा 8 में पाए जाते हैं, कोड की समझ और समर्थन पर चक्रीय जटिलता को कम करते हैं?

उदाहरण के लिए C # में हमारे पास निम्नलिखित कोड हो सकते हैं:

List<String> filteredList = new List<String>();

foreach (String s in originalList){
   if (matches(s)){
      filteredList.add(s);
   }
}

यह 2 की एक सरल चक्रीय जटिलता है।

हम इसे इस प्रकार आसानी से लिख सकते हैं:

List<String> filteredList = originalList.where(s => matches(s));

जिसमें 0 की एक सरल चक्रीय जटिलता है।

क्या यह वास्तव में अधिक सहायक कोड में परिणाम करता है? क्या इस विषय पर कोई वास्तविक शोध है?


2
आपका शीर्षक चक्रवाती जटिलता में कमी के बारे में पूछता है, लेकिन आपका पाठ सीसी कटौती को मानता है और स्थिरता के बारे में पूछता है। यह एक मूल्यवान प्रश्न होने की क्षमता है, क्या आप शीर्षक को अधिक सटीक होने के लिए संपादित कर सकते हैं?
किलन फ़ॉथ

@ KilianFoth बेहतर है?
सी। रॉस

मैं पुनरावृत्त तरीकों के साथ पुनरावृत्त करना चाहता हूँ। मुझे लगता है कि एक बेहतर शब्द उच्च-क्रम के कार्य होंगे। (और एक तरफ के रूप में, तरीकों में कोई वापसी प्रकार / शून्य नहीं है, जबकि फ़ंक्शन कुछ वापस करते हैं)।
जोहान्स रूडोल्फ

@JohannesRudolph "विधियों में कोई वापसी प्रकार / शून्य नहीं है, जबकि फ़ंक्शन कुछ वापस करते हैं" - यह किस भाषा में सच है? मैंने यह कभी नहीं सुना; वास्तव में, मैंने कभी सुना है कि केवल वास्तविक अंतर था विधियां एक वर्ग के साथ जुड़ी हुई हैं, फ़ंक्शन नहीं हैं।
जूल

जवाबों:


14

मेरा अनुमान है कि आपने सिर्फ जटिलता को विभाजित / स्थानांतरित किया है। यह कम हो गया क्योंकि आप .where()अपने CC के कार्यान्वयन की गणना नहीं करते हैं।

समग्र CC वास्तव में स्थानांतरित नहीं हुआ है, आपका स्वयं का कोड कम हो गया है, केवल इसलिए कि अब इसे फ्रेमवर्क कोड में ले जाया गया है।

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


11

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


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

6

उद्देश्यपूर्ण ढंग से प्रश्न का उत्तर देने के लिए, हमें स्थिरता के लिए किसी प्रकार की मीट्रिक की आवश्यकता होगी। साइक्लोमैटिक जटिलता अपने आप में स्थिरता की माप नहीं है, लेकिन यह कुछ मेट्रिक्स का एक घटक है जो कि स्थायित्व को मापने के लिए पर्पस है । उदाहरण के लिए, रखरखाव सूचकांक का सूत्र है:

MI = 171 - 5.2 * ln(V) - 0.23 * (G) - 16.2 * ln(LOC)

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

यह कहना मुश्किल है कि आप जिस तरह का बदलाव प्रस्तावित करते हैं, वह प्रोग्रामर को प्रोग्रामर के लिए अधिक अनुरक्षित लगता है; संभवतया इस बात पर निर्भर करता है कि वे (आपके मामले में) whereविधि से कितने परिचित हैं ।


चेतावनी: मैजिक नंबर! (>_<)
इज़्काता

मेनटेनेबिलिटी इंडेक्स के साथ बस यही एक छोटी सी समस्या है। इसके तीन घटक हैं हेल्स्टेड वॉल्यूम, साइक्लोमैटिक कॉम्प्लेक्सिटी और लाइन्स ऑफ़ कोड। Halstead Volume और Cyclomatic Complexity दोनों को बहुत ही मजबूती से कोड ऑफ लाइंस से संबंधित दिखाया गया है। इसका मतलब यह है कि केवल लाइन्स ऑफ कोड पर निर्भर रखने वाली मेनटेनेबिलिटी इंडेक्स के लिए एक वैकल्पिक अनुमानित समीकरण को व्युत्पन्न किया जा सकता है, जो मूल रूप से लगभग उतना ही सटीक होगा, जिसमें काफी कम कम्प्यूटेशनल कठिनाई होगी।
जॉन आर। स्ट्रॉहैम

@ JohnR.Strohm मुझे लगता है कि यदि आप अभी भी LOC का उपयोग स्थिरता मीट्रिक के रूप में करते हैं तो भी आपको एक समान परिणाम मिलेगा। ओपी का परिवर्तन एलओसी को 4 से 1 तक कम कर देता है, और अन्य परिवर्तन जो कि चक्रीय जटिलता को कम करते हैं, उसी तरह एलओसी को भी कम करने की संभावना है। किसी भी तरह से, यह वास्तव में नीचे आता है कि आप कैसे परिभाषित करते हैं और रखरखाव को मापते हैं।
कालेब

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

3

क्योंकि यह दिखाया गया है कि साइक्लोमैटिक जटिलता (CC) को कोड आकार के साथ बहुत दृढ़ता से सहसंबद्ध किया जाता है, "इतना ही कहा जा सकता है कि CC की अपनी कोई स्पष्ट शक्ति नहीं है।" आप वास्तव में पूछ रहे हैं कि क्या "पुनरावृत्त तरीके जैसे कि आधुनिक भाषाओं में आमतौर पर C #, जावास्क्रिप्ट, और Java 8 में पाए जाते हैं (उम्मीद है) कोड आकार को समझने और कोड की सहूलियत पर प्रभाव को कम करते हैं।"

उस समय, किसी को उम्मीद होगी कि उत्तर स्पष्ट होगा। यह दशकों से ज्ञात है कि आमतौर पर छोटे कोड समझने, बनाए रखने और समर्थन करने में आसान होते हैं।


2

यदि आप Cyclomatic Complexity की कच्ची मूर्ति के बारे में बात कर रहे हैं, तो निश्चित रूप से। आप बस इसे 2 से 0. तक nuked करते हैं, यदि आप संख्याओं, शुद्ध लाभ, सभी तरह से जा रहे हैं।

एक व्यावहारिक (पढ़ें: मानव) परिप्रेक्ष्य से, मैं तर्क देता हूं कि आपने वास्तव में जटिलता को बढ़ा दिया है 2. इसका एक बिंदु इस तथ्य से आता है कि अब कुछ अन्य प्रोग्रामर को इसे समझने के लिए धाराप्रवाह-वाक्य रचना LINQ का ज्ञान प्राप्त करना चाहिए या प्राप्त करना चाहिए कोड।

बढ़ी हुई कठिनाई का एक और बिंदु लैम्बडा एक्सप्रेशंस को समझने से आता है; हालांकि इस उदाहरण में एक लाम्बा काफी सीधा है , कुछ प्रतिमान बदलाव हैं जिन्हें पूरी तरह से सराहना करने के लिए बनाया जाना चाहिए।

यह मामला, a.where(x => matches(x, arg))भयानक नहीं है, और सभी ईमानदारी में पहली बार LINQ और लैंबडा एक्सप्रेशन के साथ कुछ सहकर्मी को देखने और काम करने का एक शानदार तरीका है (मैंने वास्तव में इसके लिए कुछ पूर्व सहकर्मियों को LINQ / Lambdas पर एक ट्यूटोरियल प्रस्तुत किया है। और कोड के अन्य सेट, महान प्रभाव के लिए।) हालांकि, इन के उपयोग के लिए कुछ ज्ञान की आवश्यकता होती है।

मैं सावधानी बरतने की सलाह देता हूं, क्योंकि मैंने ऐसे मामले देखे हैं जहां LINQ रिफ्लेक्टर वास्तव में पढ़ने के लिए काफी बदतर है जो कि foreachलूप बन जाता है।


1

विशेष रूप से, यह डेवलपर श्रोताओं पर निर्भर करता है, यदि वे लंबोदर भावों को समझते हैं, तो;

List<String> filteredList = originalList.where(s => matches(s));

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

List<String> filteredList = 
    originalList.where(stringToBeTested => matchesNameTest(stringToBeTested));

या

List<String> filteredList = 
        originalList.where(originalListString => matchesNameTest(originalListString));

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

स्थिरता केवल कोड को समझने की क्षमता के बारे में नहीं है, बल्कि मुख्य रूप से गति और सटीकता के बारे में है जिसके साथ कोई कोड को समझ सकता है।


2
हाय ऐस। यह एक उदाहरण है, जानबूझकर संरचना को उजागर करने के लिए शब्दार्थ सामग्री से रहित है।
सी। रॉस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.