मेरे मालिक ने मुझे छोटे कार्य लिखना बंद करने और एक ही पाश में सब कुछ करने के लिए कहा


209

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

उसके तर्क थे

  • छोटे कार्यों को लिखना एक दर्द है क्योंकि यह आपको प्रत्येक छोटे कार्य में स्थानांतरित करने के लिए मजबूर करता है कि कोड क्या कर रहा है।
  • मुख्य लूप में सब कुछ रखो भले ही मुख्य लूप 300 लाइनों से अधिक हो, यह पढ़ने में तेज है।
  • यदि आपको कोड डुप्लिकेट करना है तो केवल छोटे कार्य लिखें।
  • टिप्पणी के नाम के साथ एक फ़ंक्शन न लिखें, ऊपर की टिप्पणी के साथ अपने कोड की जटिल रेखा (3-4 लाइनें) डालें; इसी तरह आप सीधे असफल कोड को संशोधित कर सकते हैं

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

मैं जिस भाषा का उपयोग करता हूं वह मुख्य रूप से जावास्क्रिप्ट है। मुझे वास्तव में पढ़ने में कठिनाई हो रही है क्योंकि मैंने अपने सभी छोटे स्पष्ट रूप से नामित कार्यों को हटा दिया है और सब कुछ एक बड़े लूप में डाल दिया है। हालाँकि, मेरे बॉस को यह पसंद है।

एक उदाहरण था:

// The way I would write it
if (isApplicationInProduction(headers)) {
  phoneNumber = headers.resourceId;
} else {
  phoneNumber = DEV_PHONE_NUMBER;
}

function isApplicationInProduction(headers) {
   return _.has(headers, 'resourceId');
}

// The way he would write it
// Take the right resourceId if application is in production
phoneNumber = headers.resourceId ? headers.resourceId : DEV_PHONE_NUMBER;

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

खैर, मैं कुछ सलाह देना चाहूंगा कि स्वच्छ कोड लिखने के लिए कौन सा तरीका / अभ्यास बेहतर है?



4
फोननंबर = हेडर .resourceId ;: DEV_PHONE_NUMBER;
जोशुआ

10
मान्य करें, कि आप उस स्थान पर काम करना चाहते हैं, जहाँ प्रबंधन ने आपको अपना काम करने के लिए कहा है, बजाय इसके कि आपको क्या करना है।
कॉन्सटेंटिन पेट्रूख्नोव

8
@rjmunro जब तक आप वास्तव में अपनी नौकरी पसंद करते हैं, ध्यान रखें कि नौकरियों की तुलना में कम डेवलपर्स हैं। तो मार्टिन फाउलर को उद्धृत करने के लिए: "यदि आप अपने संगठन को नहीं बदल सकते हैं, तो अपने संगठन को बदल दें!" और बॉस मुझे बता रहे हैं कि कोड कुछ ऐसा है जिसकी सलाह मुझे आपको बदलनी चाहिए।
नील्स वैन रीजर्सडाल

10
कभी नहीं एक isApplicationInProduction()समारोह है! आपके पास परीक्षण होना चाहिए, और परीक्षण बेकार हैं यदि आपका कोड उत्पादन से अलग कुछ भी व्यवहार करता है। यह जानबूझकर उत्पादन में अनपेक्षित / खुला कोड होने जैसा है : इसका कोई मतलब नहीं है।
रॉनन पैक्साओ

जवाबों:


215

पहले कोड के उदाहरण लेना। आप एहसान करते हैं:

if (isApplicationInProduction(headers)) {
  phoneNumber = headers.resourceId;
} else {
  phoneNumber = DEV_PHONE_NUMBER;
}

function isApplicationInProduction(headers) {
   return _.has(headers, 'resourceId');
}

और आपके बॉस इसे लिखेंगे:

// Take the right resourceId if application is in production
phoneNumber = headers.resourceId ? headers.resourceId : DEV_PHONE_NUMBER;

मेरे विचार में, दोनों में समस्याएं हैं। जैसा कि मैंने आपका कोड पढ़ा था, मेरा तात्कालिक विचार था "आप इसे ifएक टर्नरी अभिव्यक्ति के साथ बदल सकते हैं "। तब मैंने आपके बॉस के कोड को पढ़ा और सोचा "उसने आपके फ़ंक्शन को एक टिप्पणी के साथ क्यों बदल दिया?"।

मेरा सुझाव है कि दोनों के बीच इष्टतम कोड है:

phoneNumber = isApplicationInProduction(headers) ? headers.resourceId : DEV_PHONE_NUMBER;

function isApplicationInProduction(headers) {
   return _.has(headers, 'resourceId');
}

यह आपको दोनों दुनिया का सबसे अच्छा देता है: एक सरलीकृत परीक्षण अभिव्यक्ति और टिप्पणी को परीक्षण योग्य कोड से बदल दिया जाता है।

हालांकि कोड डिजाइन पर अपने बॉस के विचारों के बारे में:

छोटे कार्यों को लिखना एक दर्द है क्योंकि यह आपको प्रत्येक छोटे कार्यों में यह देखने के लिए मजबूर करता है कि कोड क्या कर रहा है।

यदि फ़ंक्शन अच्छी तरह से नामित है, तो यह मामला नहीं है। isApplicationInProductionस्व-स्पष्ट है और यह देखने के लिए कि यह क्या होता है, कोड की जांच करना आवश्यक नहीं होना चाहिए। वास्तव में विपरीत सच है: कोड की जांच से पता चलता है कि फ़ंक्शन नाम की अपेक्षा इरादे से कम है (यही कारण है कि आपके बॉस को टिप्पणियों का सहारा लेना पड़ता है)।

मुख्य लूप में सब कुछ रखो भले ही मुख्य लूप 300 लाइनों से अधिक हो, यह पढ़ने में तेज है

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

अगर आपको कोड डुप्लिकेट करना है तो केवल छोटे कार्य लिखें

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

टिप्पणी के नाम के साथ एक फ़ंक्शन न लिखें, ऊपर टिप्पणी के साथ अपनी जटिल लाइन ऑफ़ कोड (3-4 लाइनें) डालें। इस तरह आप फेल कोड को सीधे संशोधित कर सकते हैं

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

स्व-दस्तावेजीकरण कोड लिखना कठिन है, और पूरक डॉक्स (टिप्पणियों के रूप में भी) कभी-कभी आवश्यक होते हैं। लेकिन "अंकल बॉब" का मानना ​​है कि टिप्पणियाँ एक कोडिंग विफलता हैं जो सभी में अक्सर सच होती हैं।

अपने बॉस को क्लीन कोड की किताब पढ़ने के लिए कहें और उसे संतुष्ट करने के लिए अपने कोड को कम पठनीय बनाने की कोशिश करें। अंततः, यदि आप उसे बदलने के लिए राजी नहीं कर सकते हैं, तो आपको या तो लाइन में लगना पड़ेगा या एक नया बॉस ढूंढना होगा जो बेहतर कोड कर सके।


26
छोटे fucntions easilly इकाई परीक्षण कर रहे हैं
Mawg

13
Quoth @ ExpertBeginner1 : "मैं अपने कोड में सभी जगहों पर बहुत सारे छोटे-छोटे तरीकों को देखकर थक गया हूं, इसलिए यहां से आगे, सभी तरीकों पर न्यूनतम 15 LOC है।"
ग्रेग बेकन

34
"टिप्पणियों में एक मौलिक दोष है: वे संकलित / व्याख्या नहीं किए जाते हैं और इसलिए यूनिट परीक्षण नहीं किया जा सकता है" यहां शैतान के वकील को खेलना, यह सच है यदि आप "टिप्पणियों" को "फ़ंक्शन नामों" से बदलते हैं।
मटकापू

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

4
@DavidArno सभी कार्यों में पूर्व और बाद की स्थितियां हैं, सवाल यह है कि आप उन्हें दस्तावेज करते हैं या नहीं। यदि मेरा कार्य एक पैरामीटर लेता है, जो मापा पैरों में दूरी है, तो आपको इसे पैरों में आपूर्ति करना होगा, न कि किलोमीटर पर। यह एक पूर्व शर्त है।
जोर्जेन फॉग

223

अन्य समस्याएं हैं

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

phoneNumber = DEV_PHONE_NUMBER_WHICH_CAUSED_PROBLEMS_FOR_CUSTOMERS;

या

phoneNumber = DEV_PHONE_NUMBER_FROM_OTHER_COUNTRY;

क्या आप और भी शाखाएँ जोड़ना चाहते हैं?

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

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

निर्भरता अन्तःक्षेपण

आपका कोड कैसा दिखना चाहिए:

phoneNumber = headers.resourceId;

यहाँ कोई शाखा नहीं है, क्योंकि यहाँ तर्क में कोई शाखा नहीं है। प्रोग्राम को हेडर से फोन नंबर खींचना चाहिए। अवधि।

यदि आप DEV_PHONE_NUMBER_FROM_OTHER_COUNTRYएक परिणाम के रूप में करना चाहते हैं , तो आपको इसे लगाना चाहिए headers.resourceId। इसे करने का एक तरीका केवल headersपरीक्षण मामलों के लिए एक अलग वस्तु को इंजेक्ट करना है (क्षमा करें यदि यह उचित कोड नहीं है, तो मेरे जावास्क्रिप्ट कौशल थोड़ा कठोर हैं):

function foo(headers){
    phoneNumber = headers.resourceId;
}

// Creating the test case
foo({resourceId: DEV_PHONE_NUMBER_FROM_OTHER_COUNTRY});

यह मानते हुए कि headersआप एक सर्वर से प्राप्त प्रतिक्रिया का एक हिस्सा हैं: आदर्श रूप से आपके पास एक संपूर्ण परीक्षण सर्वर है जो headersपरीक्षण उद्देश्यों के लिए विभिन्न प्रकारों को वितरित करता है। इस तरह से आप वास्तविक उत्पादन कोड का परीक्षण करते हैं और कुछ आधे डुप्लिकेट कोड नहीं होते हैं जो उत्पादन कोड की तरह काम कर सकते हैं या नहीं भी कर सकते हैं।


11
मैंने अपने स्वयं के उत्तर में इस विषय को संबोधित करने पर विचार किया, लेकिन लगा कि यह पहले से ही काफी लंबा था। तो +1 करने के लिए आपको ऐसा करना होगा :)
डेविड अरनो

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

56
@DavidArno हो सकता है कि आपको अपने उत्तर को छोटे उत्तरों में तोड़ देना चाहिए था। ;)
क्रिलगर

2
@ user949300 एक बिटवाइज़ का उपयोग करना या बुद्धिमानी नहीं होगी?)
curiousdannii

1
@curiousdannii हाँ, देखा कि संपादित करने में बहुत देर हो चुकी है ...
15:

59

इसका कोई "सही" या "गलत" उत्तर नहीं है। हालांकि, मैं 36 साल के पेशेवर अनुभव के आधार पर अपनी राय पेश करूंगा और सॉफ्टवेयर सिस्टम को विकसित करूंगा ...

  1. "स्व-दस्तावेजीकरण कोड" जैसी कोई चीज नहीं है। क्यों? क्योंकि वह दावा पूरी तरह से व्यक्तिपरक है।
  2. टिप्पणियाँ कभी असफल नहीं होती हैं। एक विफलता कोड क्या है जो बिना टिप्पणियों के बिल्कुल भी समझा नहीं जा सकता है ।
  3. एक कोड ब्लॉक में कोड की 300 निर्बाध लाइनें एक रखरखाव दुःस्वप्न है और त्रुटियों के लिए अत्यधिक संभावना है। ऐसा ब्लॉक खराब डिजाइन और योजना का दृढ़ता से संकेत देता है।

आपके द्वारा दिए गए उदाहरण से सीधे बात करना ... isApplicationInProduction()अपनी दिनचर्या में शामिल करना स्मार्ट (एर) चीज है। आज वह परीक्षण केवल "हेडर" का एक चेक है और इसे एक टर्नरी ( ?:) ऑपरेटर में संभाला जा सकता है । कल, परीक्षण कहीं अधिक जटिल हो सकता है। इसके अतिरिक्त, "headers.resourceId" का अनुप्रयोग के "उत्पादन की स्थिति में" से कोई स्पष्ट संबंध नहीं है; मैं तर्क दूंगा कि अंतर्निहित डेटा से इस तरह की स्थिति के लिए एक परीक्षण को डिकॉय करने की आवश्यकता है; एक सबरूटीन ऐसा करेगा और एक टर्नरी नहीं करेगा। इसके अतिरिक्त, एक उपयोगी टिप्पणी संसाधन क्यों "उत्पादन में" के लिए एक परीक्षण है।

"छोटे स्पष्ट रूप से नामित कार्यों के साथ ओवरबोर्ड न जाने के लिए सावधान रहें।" एक दिनचर्या को एक विचार को "सिर्फ कोड" से अधिक एनकैप करना चाहिए। मैं एमोन के सुझाव का समर्थन करता हूं phoneNumber = getPhoneNumber(headers)और जोड़ता getPhoneNumber()हूं कि "उत्पादन की स्थिति" परीक्षण के साथ करना चाहिएisApplicationInProduction()


25
अच्छी टिप्पणियों के रूप में ऐसी बात है जो असफल नहीं है। हालाँकि, टिप्पणियाँ जो लगभग शब्दशः कोड हैं जिन्हें वे स्पष्ट रूप से समझाते हैं या एक विधि / वर्ग / आदि से पहले खाली टिप्पणी ब्लॉक हैं। निश्चित रूप से एक विफलता है।
jpmc26

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

7
टिप्पणियाँ कभी भी आंतरिक रूप से विफल नहीं होती हैं । टिप्पणियाँ विफल हो सकती हैं, और ऐसा तब होता है जब वे गलत होते हैं। ब्लैक बॉक्स मोड में गलत व्यवहार सहित कई स्तरों पर गलत कोड का पता लगाया जा सकता है। गलत टिप्पणियों को केवल सफेद बॉक्स मोड में मानव समझ से पहचाना जा सकता है, मान्यता के माध्यम से कि दो मॉडल वर्णित हैं और उनमें से एक गलत है।
टिम्बो

7
@ टिम्बो का मतलब है, "... कम से कम उनमें से एक गलत है।" ;)
jpmc26

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

47

"आवश्यकता से परे संस्थाओं को गुणा नहीं किया जाना चाहिए।"

- ओकाम का रेजर

कोड को यथासंभव सरल होना चाहिए। कीड़े जटिलता के बीच छिपाना पसंद करते हैं, क्योंकि उन्हें वहां स्पॉट करना मुश्किल होता है। तो क्या कोड सरल बनाता है?

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

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

लेकिन हर फ़ंक्शन कॉल में एक संज्ञानात्मक ओवरहेड होता है : मुझे कोड को अपने वर्तमान कोड के भीतर समझने की ज़रूरत नहीं है , मुझे यह भी समझना होगा कि यह कोड को बाहर से कैसे इंटरैक्ट करता है । मुझे लगता है कि यह कहना उचित है कि आपने जो फ़ंक्शन निकाला है, वह फ़ंक्शन के अर्क की तुलना में अधिक जटिलता का परिचय देता है । आपके बॉस को " छोटे कार्यों [द्वारा] एक दर्द का मतलब है क्योंकि यह आपको प्रत्येक छोटे कार्य में स्थानांतरित करने के लिए मजबूर करता है कि कोड क्या कर रहा है। "

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

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

एक बहुत ही महत्वपूर्ण मीट्रिक साइक्लोमैटिक जटिलता (मैककेब जटिलता) है। यह कोड के एक टुकड़े के माध्यम से स्वतंत्र पथों की संख्या को मापता है। यह संख्या प्रत्येक सशर्त के साथ तेजी से बढ़ती है । प्रत्येक सशर्त या लूप पथ की संख्या को दोगुना करता है। 10 से अधिक अंकों के स्कोर का सुझाव देने के लिए सबूत बहुत जटिल है। इसका मतलब है कि एक बहुत लंबा कार्य जिसमें 5 का स्कोर होता है, शायद 25 के स्कोर के साथ बहुत ही छोटे और घने फ़ंक्शन से बेहतर होता है। हम नियंत्रण प्रवाह को अलग-अलग कार्यों में निकालकर जटिलता को कम कर सकते हैं।

आपकी स्थिति जटिलता के एक टुकड़े का एक उदाहरण है जिसे पूरी तरह से निकाला जा सकता है:

function bigFatFunction(...) {
  ...
  phoneNumber = getPhoneNumber(headers);
  ...
}

...

function getPhoneNumber(headers) {
  return headers.resourceId ? headers.resourceId : DEV_PHONE_NUMBER;
}

यह अभी भी उपयोगी होने के किनारे पर है। मुझे यकीन नहीं है कि क्या यह जटिलता कम हो जाती है क्योंकि यह सशर्त बहुत सशर्त नहीं है । उत्पादन में, यह हमेशा एक ही रास्ता लेगा।


जटिलता कभी गायब नहीं हो सकती। इसे केवल इधर-उधर किया जा सकता है। क्या कई छोटी चीजें कुछ बड़ी चीजों की तुलना में सरल होती हैं? यह परिस्थिति पर बहुत निर्भर करता है। आमतौर पर, वहाँ कुछ संयोजन है जो सही लगता है। यह पता लगाना कि विभिन्न जटिलता कारकों के बीच समझौता अंतर्ज्ञान और अनुभव लेता है, और भाग्य का एक सा।

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

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

(नोट: यह जवाब जिमी हॉफ़ द्वारा व्हाइटबोर्ड पर उचित कोड ब्लॉग पोस्ट के विचारों पर आधारित है , जो कोड को सरल बनाता है पर एक उच्च-स्तरीय दृश्य प्रदान करता है।)


मैं सामान्य हूँ मुझे आपकी प्रतिक्रिया पसंद आई। हालांकि, मैं mcabes साइक्लोमैटिक जटिलता माप के साथ समस्या लेता हूं। मैंने जो देखा है, उससे यह जटिलता का सही माप प्रस्तुत नहीं करता है।
रॉबर्ट बैरन

27

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

उनकी बात मत सुनो!

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

स्वचालित रीफैक्टरिंग उपकरण विधियों को निकालने के लिए आसान, सरल और सुरक्षित बनाते हैं। और कृपया, उन लोगों को गंभीर न लें, जो> 300 लाइनों के साथ लेखन कार्यों की सलाह देते हैं - ऐसे लोग निश्चित रूप से आपको यह बताने के लिए योग्य नहीं हैं कि आपको कैसे कोड करना चाहिए।


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

10
@ArseniMourzenko: हममें से हर किसी को अपने बॉस के सामने झुकना नहीं पड़ता। मुझे उम्मीद है कि ओपी यह जानने के लिए काफी पुराना है कि उसे कब सही काम करना है, या जब उसे वह करना है जो उसका बॉस कहता है। और हां, मैं जानबूझकर उदाहरण के विवरण में नहीं जा रहा था, पहले से ही उन विवरणों पर चर्चा करने के लिए पर्याप्त अन्य उत्तर हैं।
डॉक ब्राउन

8
@DocBrown सहमत हैं। एक पूरी कक्षा के लिए 300 लाइनें संदिग्ध हैं। एक 300 लाइन फ़ंक्शन अश्लील है।
१२

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

9
इसके अलावा, मैंने अंकल बॉब की ऋषि सलाह को गलत तरीके से देखा और दुरुपयोग किया है, इसलिए मुझे मेरी शंका है कि यह किसी और के लिए उपयोगी है लेकिन अनुभवी प्रोग्रामर हैं।
रॉबर्ट हार्वे

23

आपके मामले में: आप एक फ़ोन नंबर चाहते हैं। या तो यह स्पष्ट है कि आपको फोन नंबर कैसे मिलेगा, तो आप स्पष्ट कोड लिखें। या यह स्पष्ट नहीं है कि आपको फोन नंबर कैसे मिलेगा, तो आप इसके लिए एक विधि लिखते हैं।

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

".ApplicationInProduct" विधि काफी व्यर्थ है। अपने getPhonenumber विधि से इसे कॉल करने से कार्यान्वयन को अधिक स्पष्ट नहीं किया जाता है, और बस यह पता लगाना कठिन हो जाता है कि क्या चल रहा है।

छोटे कार्य न लिखें। ऐसे कार्यों को लिखें जिनका एक अच्छा-परिभाषित उद्देश्य हो और उस अच्छी तरह से परिभाषित उद्देश्य को पूरा करना हो।

पुनश्च। मुझे कार्यान्वयन बिल्कुल पसंद नहीं है। यह मानता है कि फोन नंबर की अनुपस्थिति का मतलब है कि यह एक देव संस्करण है। इसलिए यदि फ़ोन नंबर उत्पादन में अनुपस्थित है, तो आप न केवल इसे संभालते हैं, बल्कि एक यादृच्छिक फ़ोन नंबर स्थानापन्न करते हैं। कल्पना कीजिए कि आपके पास 10,000 ग्राहक हैं, और 17 के पास फोन नंबर नहीं है, और आप उत्पादन में परेशानी में हैं। चाहे आप उत्पादन में हों या विकास की सीधे जाँच की जानी चाहिए, किसी और चीज़ से नहीं।


1
"छोटे फ़ंक्शंस न लिखें। ऐसे फ़ंक्शंस लिखें जिनमें एक अच्छी तरह से परिभाषित उद्देश्य हो और उस अच्छी तरह से परिभाषित उद्देश्य को पूरा करें।" कि बंटवारे कोड के लिए सही कसौटी है। यदि कोई फ़ंक्शन बहुत अधिक (जैसे एक से अधिक) असमान कार्य करता है , तो उसे विभाजित करें। एकल जिम्मेदारी सिद्धांत मार्गदर्शक सिद्धांत है।
रॉबर्ट ब्रिस्टो-जॉनसन 5:20 बजे

16

यहां तक ​​कि इस तथ्य की अनदेखी करते हुए कि न तो कार्यान्वयन सभी अच्छे हैं, मैं ध्यान दूंगा कि यह अनिवार्य रूप से एकल उपयोग तुच्छ कार्यों के सार के स्तर पर कम से कम स्वाद का सवाल है।

लाइनों की संख्या ज्यादातर मामलों में एक उपयोगी मीट्रिक नहीं है।

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

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

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

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

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


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

15

सब कुछ एक बड़े लूप में न डालें, लेकिन ऐसा न करें अक्सर:

function isApplicationInProduction(headers) {
   return _.has(headers, 'resourceId');
}

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

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

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


2
मैं समझता हूं कि एक एकल बूलियन एक लाइनर को पढ़ना आसान है, लेकिन यह वास्तव में केवल "क्या" हो रहा है। मैं अभी भी फ़ंक्शन लिखता हूं जो सरल टर्नरी अभिव्यक्तियों को लपेटता है क्योंकि फ़ंक्शन का नाम "क्यों" मैं इस स्थिति की जांच कर रहा हूं, इसका कारण बताने में मदद करता है। यह विशेष रूप से तब मददगार होता है जब कोई नया (या 6 महीने में खुद को) व्यावसायिक तर्क को समझने की आवश्यकता होती है।
एजे एक्स।

14

ऐसा लगता है कि वास्तव में आप क्या चाहते हैं:

phoneNumber = headers.resourceId || DEV_PHONE_NUMBER

यह जो भी इसे पढ़ता है उसे आत्म-व्याख्यात्मक होना चाहिए: यदि यह उपलब्ध है तो सेट phoneNumberकरें resourceId, या DEV_PHONE_NUMBERयदि यह नहीं है तो डिफ़ॉल्ट है ।

यदि आप वास्तव में उस चर को केवल उत्पादन में सेट करना चाहते हैं, तो आपको यह निर्धारित करने के लिए कि आपके पास कहां से चल रहे हैं, कुछ अन्य, अधिक विहित ऐप-वाइड उपयोगिता विधि (जिसमें मापदंडों की आवश्यकता नहीं है) होनी चाहिए। उस जानकारी के लिए हेडर पढ़ना समझ में नहीं आता है।


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

14

मुझे कुंद होने दें: यह मुझे लगता है कि आपका वातावरण (भाषा / रूपरेखा / वर्ग डिजाइन आदि) वास्तव में "स्वच्छ" कोड के लिए अनुकूल नहीं है। आप कोड की कुछ पंक्तियों में सभी संभव प्रकार की चीजों को मिला रहे हैं जो वास्तव में एक साथ पास नहीं होनी चाहिए। एक एकल फ़ंक्शन का क्या कार्य है जो यह जानने के साथ resourceId==undefहै कि आप उत्पादन में नहीं हैं, कि आप गैर-उत्पादन प्रणालियों में एक डिफ़ॉल्ट फोन नंबर का उपयोग कर रहे हैं, कि रिसोर्सआईड कुछ "हेडर" और इतने पर सहेजा गया है? मुझे लगता है headersकि HTTP हेडर हैं, इसलिए आप भी निर्णय लेते हैं कि आप अंतिम उपयोगकर्ता के लिए किस वातावरण में हैं?

कार्यों में उस एकल टुकड़े को फैक्टर करना आपको उस अंतर्निहित समस्या से बहुत मदद नहीं करेगा।

देखने के लिए कुछ कीवर्ड:

  • decoupling
  • एकजुटता
  • निर्भरता अन्तःक्षेपण

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

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

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


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

प्रथम श्रेणी के कार्यों के साथ जावास्क्रिप्ट प्रोटोटाइप है। यह स्वाभाविक रूप से OO है, लेकिन क्लासिक अर्थों में नहीं, इसलिए आपकी धारणा सही नहीं हो सकती है। YouTube पर
क्रॉकफ़ोर्ड विड्स

13

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


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

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

6

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

मैं यह नहीं कहूंगा कि आपको पूरी तरह से एक टर्नरी का उपयोग करना चाहिए, कुछ लोग जिनके साथ मैंने काम किया है वे थोड़े लंबे समय तक पसंद करते हैं if () {...} else {...}, यह ज्यादातर एक व्यक्तिगत पसंद है। मैं "एक लाइन एक चीज को अप्रोच करता हूं" को प्राथमिकता देता हूं, लेकिन मैं मूल रूप से जो भी कोडबेस सामान्य रूप से उपयोग करता है उससे चिपकेगा।

टर्नरी का उपयोग करते समय यदि लॉजिकल चेक लाइन को बहुत लंबा या जटिल बनाता है तो मान रखने के लिए एक अच्छी तरह से नामित वैरिएबल / एस बनाने पर विचार करें।

// NOTE "resourceId" not present in dev build, use test data
let isProduction = 'resourceId' in headers;
let phoneNumber = isProduction ? headers.resourceId : DEV_PHONE_NUMBER;

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


5

आपके द्वारा दिया गया कोड उदाहरण, आपका बॉस IS CORRECT है। उस मामले में एक स्पष्ट रेखा बेहतर है।

सामान्य तौर पर, छोटे टुकड़ों में जटिल तर्क को तोड़ना, सुगमता, कोड रखरखाव और संभावना के लिए बेहतर होता है कि उपवर्गों का व्यवहार अलग होगा (भले ही थोड़ा सा ही)।

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


1
"फंक्शन ओवरहेड": जो कंपाइलर तक है। "अस्पष्टता": ओपी ने संकेत नहीं दिया है कि यह उस संपत्ति की जांच करने का एकमात्र या सबसे अच्छा तरीका है; आप निश्चित रूप से नहीं जान सकते। "जटिल स्पेगेटी तर्क": कहाँ? "मृत कार्यों के लिए क्षमता": उस तरह के मृत कोड विश्लेषण कम लटका हुआ फल है, और विकास टूलकिन जिसमें इसकी कमी है अपरिपक्व हैं।
१२:१६ पर कविता

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

2

मैं लंबे कार्यों के पक्ष में कम से कम दो तर्क सोच सकता हूं:

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

  • कई छोटे कार्यों का मतलब है कि एक बड़ा और अधिक जटिल कॉल ग्राफ है। यादृच्छिक फ़ंक्शन में एक यादृच्छिक रेखा चुनें, और इस प्रश्न का उत्तर दें "किस संदर्भ में यह रेखा निष्पादित है?" यह कॉल ग्राफ जितना बड़ा और अधिक जटिल हो जाता है, क्योंकि आपको उस ग्राफ़ में और अधिक कोने देखना होगा।

मन के लिए लंबे कार्यों-इकाई-परीक्षणीय स्प्रिंग्स के खिलाफ भी तर्क हैं। एक और दूसरे के बीच चयन करते समय अपने अनुभव के लिए t Useh̶e̶ ̶f̶o̶r̶c̶e experience का उपयोग करें।

नोट: मैं यह नहीं कह रहा हूं कि आपका बॉस सही है, केवल उसका दृष्टिकोण पूरी तरह से मूल्य से रहित नहीं हो सकता है।


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


डेविड अर्नो के जवाब पर टिप्पणी :

छोटे कार्यों को लिखना एक दर्द है क्योंकि यह आपको प्रत्येक छोटे कार्यों में यह देखने के लिए मजबूर करता है कि कोड क्या कर रहा है।

यदि फ़ंक्शन अच्छी तरह से नामित है, तो यह मामला नहीं है। isApplicationInProduction स्व-स्पष्ट है और यह देखने के लिए कि यह क्या होता है, कोड की जांच करने के लिए आवश्यक नहीं होना चाहिए। वास्तव में विपरीत सच है: कोड की जांच से पता चलता है कि फ़ंक्शन नाम की अपेक्षा इरादे से कम है (यही कारण है कि आपके बॉस को टिप्पणियों का सहारा लेना पड़ता है)।

नाम स्पष्ट करता है कि रिटर्न वैल्यू का क्या मतलब है , लेकिन यह कोड को निष्पादित करने के प्रभावों के बारे में कुछ नहीं कहता है (= कोड क्या करता है )। नाम (केवल) इरादे के बारे में जानकारी देते हैं, कोड व्यवहार के बारे में जानकारी देता है (जिससे इरादे के कुछ हिस्सों को कभी-कभी अनुमान लगाया जा सकता है)।

कभी-कभी आप एक चाहते हैं, कभी-कभी दूसरे, इसलिए यह अवलोकन एकतरफा सार्वभौमिक रूप से मान्य निर्णय नियम नहीं बनाता है।

मुख्य लूप में सब कुछ रखो भले ही मुख्य लूप 300 लाइनों से अधिक हो, यह पढ़ने में तेज है

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

मैं सहमत हूं कि आपको इसे अपने सिर में निष्पादित करना होगा। यदि आपके पास एक बड़े फ़ंक्शन बनाम कई छोटे कार्यों में कार्यक्षमता की 500 लाइनें हैं, तो यह मेरे लिए स्पष्ट नहीं है कि यह आसान क्यों है।

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

जब आप सहायक कार्यों के कॉल ट्री को ट्रेस कर रहे हैं, तो आपको बिजनेस लॉजिक से लेकर कार्यान्वयन के विवरणों तक का निर्धारण करने की चुनौती का सामना करना पड़ेगा। मैं साक्ष्य के बिना दावा करता हूं कि कॉल ग्राफ जितना सरल है, यह भेद करना उतना ही आसान है।

(*) कम से कम मैं इसके बारे में ईमानदार हूं ;-)

एक बार फिर, मुझे लगता है कि दोनों दृष्टिकोणों में ताकत और कमजोरियां हैं।

अगर आपको कोड डुप्लिकेट करना है तो केवल छोटे कार्य लिखें

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

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

उस ने कहा, यह बॉस के दृष्टिकोण का एक हिस्सा है जो मैं शायद सबसे ज्यादा असहमत हूं।

टिप्पणी के नाम के साथ एक फ़ंक्शन न लिखें, ऊपर टिप्पणी के साथ अपनी जटिल लाइन ऑफ़ कोड (3-4 लाइनें) डालें। इस तरह आप फेल कोड को सीधे संशोधित कर सकते हैं

मैं वास्तव में इस के पीछे के तर्क को नहीं समझ सकता, यह मानते हुए कि यह वास्तव में गंभीर है। [...] टिप्पणियों में एक मौलिक दोष है: वे संकलित / व्याख्या नहीं की जाती हैं और इसलिए इकाई परीक्षण नहीं किया जा सकता है। कोड संशोधित हो जाता है और टिप्पणी अकेले छोड़ दी जाती है और आप अंत तक यह नहीं जानते हैं कि कौन सही है।

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


-1

मेरी राय में, आपके लिए आवश्यक कार्यक्षमता का सही कोड है:

phoneNumber = headers.resourceId || DEV_PHONE_NUMBER;

या यदि आप इसे एक फंक्शन में विभाजित करना चाहते हैं, तो शायद कुछ ऐसा हो:

phoneNumber = getPhoneNumber(headers);

function getPhoneNumber(headers) {
  return headers.resourceId || DEV_PHONE_NUMBER
}

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

function isApplicationInProduction() {
  process.env.NODE_ENV === 'production';
}

तो आप के साथ फोन नंबर प्राप्त कर सकते हैं:

phoneNumber = isApplicationInProduction() ? headers.resourceId : DEV_PHONE_NUMBER;

-2

बुलेट के दो बिंदुओं पर एक टिप्पणी

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

कई संपादक (उदाहरण के लिए IntelliJ) आपको Ctrl-क्लिक के उपयोग से किसी फ़ंक्शन / वर्ग में जाने देंगे। इसके अलावा, आपको अक्सर कोड को पढ़ने के लिए किसी फ़ंक्शन के कार्यान्वयन के विवरण को जानने की आवश्यकता नहीं होती है, इस प्रकार कोड पढ़ने में तेज़ी आती है।

मुझे लगता है कि आप अपने मालिक को बताते हैं; वह आपकी वकालत पसंद करेंगे और इसे नेतृत्व के रूप में देखेंगे। बस विनम्र बनो।

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