प्रसंग
मुझे हाल ही में बेहतर स्वरूपित कोड के निर्माण में रुचि है। और बेहतर से मेरा मतलब है "निम्नलिखित नियम पर्याप्त लोगों द्वारा इसे एक अच्छा अभ्यास मानने का समर्थन करते हैं" (क्योंकि कोड करने के लिए एक अनूठा "सर्वश्रेष्ठ" तरीका कभी नहीं होगा, निश्चित रूप से)।
इन दिनों, मैं ज्यादातर रूबी में कोड करता हूं, इसलिए मैंने अपने कोड की "गुणवत्ता" (समुदाय संचालित परियोजना रूबी-शैली-गाइड द्वारा परिभाषित की जा रही "गुणवत्ता" पर मुझे कुछ जानकारी प्रदान करने के लिए एक लिंटर (रूबोकॉप) का उपयोग करना शुरू कर दिया ।
ध्यान दें कि मैं "गुणवत्ता" का उपयोग "फ़ॉर्मेटिंग की गुणवत्ता" के रूप में करूंगा, कोड की दक्षता के बारे में इतना नहीं, भले ही कुछ मामलों में, कोड दक्षता वास्तव में प्रभावित होती है कि कोड कैसे लिखा जाता है।
वैसे भी, सब कुछ करते हुए, मुझे एहसास हुआ (या कम से कम, याद है) कुछ बातें:
- कुछ भाषाएं (विशेष रूप से पायथन, रूबी और ऐसी) कोड के महान वन-लाइनर्स बनाने की अनुमति देती हैं
- आपके कोड के लिए कुछ दिशानिर्देशों का पालन करने से यह काफी कम हो सकता है और फिर भी बहुत स्पष्ट हो सकता है
- फिर भी, इन दिशानिर्देशों का सख्ती से पालन करने से कोड कम स्पष्ट / पढ़ने में आसान हो सकता है
- कोड लगभग पूरी तरह से और अभी भी खराब गुणवत्ता के कुछ दिशानिर्देशों का सम्मान कर सकता है
- कोड पठनीयता ज्यादातर व्यक्तिपरक है (जैसा कि "मुझे जो स्पष्ट है वह एक साथी डेवलपर के लिए पूरी तरह से अस्पष्ट हो सकता है")
वे केवल अवलोकन हैं, निश्चित रूप से पूर्ण नियम नहीं हैं। आप यह भी नोट करेंगे कि कोड पठनीयता और निम्नलिखित दिशानिर्देश इस बिंदु पर असंबंधित लग सकते हैं, लेकिन यहां दिशानिर्देश एक तरह से कोड की एक संख्या को फिर से लिखने के लिए संकीर्ण हैं।
अब, कुछ उदाहरण, उन सभी को और अधिक स्पष्ट करने के लिए।
उदाहरण
चलो एक सरल उपयोग मामला लेते हैं: हमारे पास एक " User
" मॉडल के साथ एक आवेदन है । एक उपयोगकर्ता वैकल्पिक है firstname
और surname
और एक अनिवार्य email
पता।
मैं एक विधि लिखना चाहता हूं " name
" जो firstname + surname
उपयोगकर्ता के नाम ( ) में वापस आ जाएगी यदि कम से कम उसका firstname
या surname
मौजूद है, या email
यदि नहीं तो एक कमबैक मान के रूप में।
मैं यह विधि भी चाहता हूं use_email
कि पैरामीटर (बूलियन) के रूप में एक " " लेने के लिए, उपयोगकर्ता ईमेल को फॉलबैक मूल्य के रूप में उपयोग करने की अनुमति देता है। यह " use_email
" पैरामीटर डिफ़ॉल्ट होना चाहिए (यदि पारित नहीं है) " true
" के रूप में ।
रूबी में यह लिखने का सबसे सरल तरीका होगा:
def name(use_email = true)
# If firstname and surname are both blank (empty string or undefined)
# and we can use the email...
if (firstname.blank? && surname.blank?) && use_email
# ... then, return the email
return email
else
# ... else, concatenate the firstname and surname...
name = "#{firstname} #{surname}"
# ... and return the result striped from leading and trailing spaces
return name.strip
end
end
यह कोड इसे करने का तरीका समझने में सबसे सरल और आसान है। यहां तक कि किसी के लिए जो रूबी को "नहीं" बोलते हैं।
आइए अब इसे छोटा बनाने की कोशिश करते हैं:
def name(use_email = true)
# 'if' condition is used as a guard clause instead of a conditional block
return email if (firstname.blank? && surname.blank?) && use_email
# Use of 'return' makes 'else' useless anyway
name = "#{firstname} #{surname}"
return name.strip
end
यह छोटा है, फिर भी समझना आसान है, अगर आसान नहीं है (गार्ड क्लॉज सशर्त ब्लॉक की तुलना में पढ़ने के लिए अधिक स्वाभाविक है)। गार्ड क्लॉज भी मेरे द्वारा उपयोग किए जा रहे दिशा-निर्देशों के अनुरूप है, इसलिए यहां जीतना है। हम इंडेंट स्तर को भी कम करते हैं।
अब इसे कमतर करने के लिए कुछ रूबी जादू का उपयोग करें:
def name(use_email = true)
return email if (firstname.blank? && surname.blank?) && use_email
# Ruby can return the last called value, making 'return' useless
# and we can apply strip directly to our string, no need to store it
"#{firstname} #{surname}".strip
end
यहां तक कि दिशानिर्देशों को पूरी तरह से छोटा और अनुसरण करना ... लेकिन वापसी कथन की कमी के कारण बहुत कम स्पष्ट है, जो इस अभ्यास से अपरिचित लोगों के लिए थोड़ा भ्रमित करता है।
यह यहां है कि हम सवाल पूछना शुरू कर सकते हैं: क्या यह वास्तव में इसके लायक है? क्या हमें "नहीं, इसे पठनीय बनाना चाहिए और return
" " जोड़ना चाहिए (यह जानते हुए कि यह दिशानिर्देशों का सम्मान नहीं करेगा)। या हमें कहना चाहिए "यह ठीक है, यह रूबी तरीका है, लानत भाषा सीखो!"
यदि हम विकल्प बी लेते हैं, तो इसे और भी छोटा क्यों न बनाएं:
def name(use_email = true)
(email if (firstname.blank? && surname.blank?) && use_email) || "#{firstname} #{surname}".strip
end
यहाँ यह है, एक लाइनर! बेशक यह कम है ... यहाँ हम इस तथ्य का लाभ उठाते हैं कि रूबी एक मान लौटाएगा या दूसरा जिसके आधार पर किसी को परिभाषित किया जाएगा (क्योंकि ईमेल को पहले की तरह उसी स्थिति में परिभाषित किया जाएगा)।
हम इसे भी लिख सकते हैं:
def name(use_email = true)
(email if [firstname, surname].all?(&:blank?) && use_email) || "#{firstname} #{surname}".strip
end
यह छोटा है, पढ़ने में कठिन नहीं है (मेरा मतलब है, हम सभी ने देखा है कि एक बदसूरत वन-लाइनर कैसा दिख सकता है), अच्छा रूबी, यह मेरे द्वारा उपयोग किए जाने वाले दिशानिर्देश का अनुपालन करता है ... लेकिन फिर भी, लिखने के पहले तरीके की तुलना में यह, यह पढ़ने और समझने में बहुत आसान है। हम यह भी तर्क दे सकते हैं कि यह रेखा बहुत लंबी है (80 से अधिक अक्षर)।
सवाल
कोड के कुछ उदाहरण दिखा सकते हैं कि एक "पूर्ण-आकार" कोड और इसके कई कम संस्करणों (प्रसिद्ध वन-लाइनर के नीचे) के बीच चयन करना कठिन हो सकता है, क्योंकि हम देख सकते हैं, वन-लाइनर डरावना नहीं हो सकता है लेकिन फिर भी, कुछ भी पठनीयता के मामले में "पूर्ण-आकार" कोड को नहीं हराएगा ...
तो यहाँ असली सवाल है: कहाँ रुकना है? कब छोटा, काफी छोटा है? जब कोड "बहुत छोटा" और कम पठनीय हो (यह ध्यान में रखते हुए कि यह काफी व्यक्तिपरक है) कैसे पता चलेगा? और इससे भी अधिक: हमेशा तदनुसार कोड कैसे करें और कोड के "पूर्ण आकार" के साथ एक-लाइनर्स को मिश्रण करने से बचें जब मुझे बस ऐसा लगता है?
टी एल; डॉ
यहाँ मुख्य प्रश्न यह है: जब कोड के "लंबे, लेकिन स्पष्ट, पठनीय और समझने योग्य हिस्सा" और "शक्तिशाली, छोटी और मुश्किल से पढ़ने / समझने के लिए एक-लाइनर" के बीच चयन करने की बात आती है, तो उन दोनों को जानना सबसे ऊपर और एक स्केल के नीचे और न केवल दो विकल्प: कैसे परिभाषित करें कि "स्पष्ट रूप से पर्याप्त" और "जितना स्पष्ट होना चाहिए" के बीच सीमा कहां है? "
मुख्य प्रश्न शास्त्रीय "वन-लाइनर्स बनाम पठनीयता नहीं है: कौन सा बेहतर है?" लेकिन "उन दोनों के बीच संतुलन कैसे खोजें?"
संपादित करें 1
कोड के उदाहरणों में टिप्पणियों को "अनदेखा" करने के लिए है, वे यहां स्पष्ट करने के लिए हैं कि क्या हो रहा है, लेकिन कोड की पठनीयता का मूल्यांकन करते समय ध्यान में नहीं रखा जाता है।
return
कीवर्ड जोड़ा । मेरी नजर में उन सात पात्रों में काफी स्पष्टता है।
[firstname,surname,!use_email].all?(&:blank?) ? email : "#{firstname} #{surname}".strip
... क्योंकि false.blank?
रिटर्न सही है और टर्नरी ऑपरेटर आपको कुछ अक्षर बचाता है ... characters \ _ (ツ) _ / ¯
return
कीवर्ड को जोड़ने के लिए क्या स्पष्टता है ?! यह कोई भी जानकारी प्रदान नहीं करता है । यह शुद्ध अव्यवस्था है।