जादू की संख्या को खत्म करना: "ना" कहने का समय कब है?


36

हम सभी जानते हैं कि मैजिक नंबर (हार्ड-कोडेड वैल्यूज़) आपके प्रोग्राम में कहर बरपा सकते हैं, खासकर जब यह उस कोड के एक खंड को संशोधित करने का समय होता है जिसमें कोई टिप्पणी नहीं होती है, लेकिन आप कहां रेखा खींचते हैं?

उदाहरण के लिए, यदि आपके पास एक फ़ंक्शन है जो दो दिनों के बीच सेकंड की संख्या की गणना करता है, तो क्या आप प्रतिस्थापित करते हैं

seconds = num_days * 24 * 60 * 60

साथ में

seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE

किस बिंदु पर आप तय करते हैं कि यह पूरी तरह से स्पष्ट है कि हार्ड-कोडेड मूल्य का क्या मतलब है और इसे अकेला छोड़ दें?


2
उस गणना को किसी फ़ंक्शन या मैक्रो से प्रतिस्थापित क्यों नहीं किया जाता है ताकि आपका कोड समाप्त हो जाए जैसेseconds = CALC_SECONDS(num_days);
FrustratedWithFormsDesigner

15
TimeSpan.FromDays(numDays).Seconds;
कोई नहीं

18
@ बूस्टरवाल: उस रवैये के साथ ( HOURS_PER_DAY will never need to be altered), आप मंगल ग्रह पर तैनात सॉफ्टवेयर के लिए कभी भी कोडिंग नहीं करेंगे। : P
FrustratedWithFormsDesigner

23
मैंने स्थिरांक की संख्या को केवल SECONDS_PER_DAY = 86400 तक घटा दिया होगा। क्यों कुछ है कि बदल नहीं होगा गणना?
JohnFx

17
लीप सेकंड के बारे में क्या?
जॉन

जवाबों:


40

संख्यात्मक शाब्दिकों के बजाय प्रतीकात्मक स्थिरांक का उपयोग करने के दो कारण हैं:

  1. मैजिक नंबर बदलने पर रखरखाव को आसान बनाने के लिए। यह आपके उदाहरण पर लागू नहीं होता है। यह बहुत कम संभावना है कि एक घंटे में सेकंड की संख्या, या एक दिन में घंटों की संख्या बदल जाएगी।

  2. पठनीयता में सुधार के लिए। अभिव्यक्ति "24 * 60 * 60" लगभग सभी के लिए स्पष्ट है। "SECONDS_PER_DAY" बहुत अधिक है, लेकिन यदि आप बग का शिकार कर रहे हैं, तो आपको यह जांचना पड़ सकता है कि SECONDS_PER_DAY को सही तरीके से परिभाषित किया गया था। संक्षिप्तता में मूल्य है।

मैजिक नंबरों के लिए जो बिल्कुल एक बार दिखाई देते हैं, और बाकी प्रोग्राम से स्वतंत्र होते हैं, यह तय करना कि उस नंबर के लिए सिंबल बनाना स्वाद का विषय है या नहीं। यदि कोई संदेह है, तो आगे बढ़ें और एक प्रतीक बनाएं।

यह मत करो:

public static final int THREE = 3;

3
+1 @ केविन क्लाइन: मैं संक्षिप्तता के बारे में आपकी बात से सहमत हूँ बग-शिकार। अतिरिक्त लाभ जो मैं नामांकित निरंतर का उपयोग करते हुए देखता हूं, विशेष रूप से डिबगिंग करते समय, यदि यह पता चला है कि एक स्थिरांक को गलत तरीके से परिभाषित किया गया था, तो आपको गलत तरीके से लागू किए गए सभी घटनाओं के लिए एक पूरी परियोजना के माध्यम से खोजने के बजाय केवल एक कोड को बदलना होगा। मूल्य।
oosterwal

40
या इससे भी बदतर:publid final int FOUR = 3;
गाब्लिन

3
ओह प्रिय, आपने उसी आदमी के साथ काम किया होगा, जिसके साथ मैंने एक बार काम किया था।
जल्दी_अगला

2
@ गैब्लिन: गोरा होने के लिए, पबियों में पलकों का होना काफी उपयोगी है।
एलन पीयर्स

10
मैंने यह देखा है: public static int THREE = 3;... नोट - नहीं final!
स्टीफन सी

29

मैं जादू नंबर कभी नहीं होने का नियम रखना चाहते हैं।

जबकि

seconds = num_days * 24 * 60 * 60

क्रंच मोड में तीन या चार सप्ताह के लिए प्रतिदिन 10 घंटे के लिए कोड किए जाने के बाद, ज्यादातर समय पूरी तरह से पठनीय होता है

seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE

पढ़ने के लिए बहुत आसान है।

FrustratedWithFormsDesigner का सुझाव बेहतर है:

seconds = num_days * DAYS_TO_SECOND_FACTOR

या इससे भी बेहतर

seconds = CONVERT_DAYS_TO_SECONDS(num_days)

जब आप बहुत थक जाते हैं तो चीजें स्पष्ट होना बंद हो जाती हैं। कोड रक्षात्मक रूप से


13
एक क्रंच मोड में आना, जैसे आप वर्णन करते हैं, एक प्रतिस्पर्शी एंटीपैटर्न है जिसे टाला जाना चाहिए। प्रोग्रामर लगभग 35-40 घंटे / सप्ताह पर चरम निरंतर उत्पादकता तक पहुंचते हैं।
btilly

4
@btilly मैं आपसे तहे दिल से सहमत हूँ। लेकिन ऐसा होता है, अक्सर बाहरी कारकों के कारण।
विटोर पाय

3
मैं सामान्य रूप से दूसरे, मिनट, दिन और घंटे के लिए स्थिरांक को परिभाषित करता हूं। अगर और कुछ नहीं '30 * मिनट 'वास्तव में पढ़ने के लिए आसान है और मुझे इसके बारे में सोचने के बिना एक समय पता है।
ज़ाचारी के

9
@ बीटीली: पीक 35-40 घंटे या रक्त एल्कोहोल स्तर 0.129% और 0.138% के बीच है। मैंने इसे XKCD पर पढ़ा , तो यह सच हो गया!
ओस्टरवाल

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

8

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

लेकिन आपके उदाहरण में, मुझे लगता है कि 24 * 60 * 60द्वारा प्रतिस्थापित DAYS_TO_SECONDS_FACTORकरना बेहतर है।


मैं मानता हूं कि जब संदर्भ और उपयोग पूरी तरह से स्पष्ट है तो हार्ड-कोडेड मूल्य भी ठीक हैं। यह, हालांकि, एक निर्णय कॉल है ...

उदाहरण:

जैसा कि @rmx ने बताया है, यदि कोई सूची खाली है, या जाँच करने के लिए 0 या 1 का उपयोग करते हुए, या शायद एक लूप की सीमा में एक ऐसे मामले का उदाहरण है जहां स्थिर का उद्देश्य बहुत स्पष्ट है।


2
यह आमतौर पर उपयोग करने के लिए ठीक है 0या 1मुझे लगता है। if(someList.Count != 0) ...से बेहतर है if(someList.Count != MinListCount) ...। हमेशा नहीं, लेकिन आम तौर पर।
कोई भी

2
@ डिमा: वी.एस. फॉर्म डिज़ाइनर का काम संभालता है। यदि यह स्थिरांक बनाना चाहता है, तो मेरे साथ ठीक है। लेकिन मैं उत्पन्न कोड में नहीं जा रहा हूं और सभी हार्ड-कोडित मूल्यों को स्थिरांक के साथ बदल रहा हूं ।
FrustratedWithFormsDesigner

4
आइए कोड को भ्रमित न करें, जिसका अर्थ है कि मानव उपभोग के लिए लिखे गए कोड के साथ एक उपकरण द्वारा उत्पन्न और संभाला जाना।
बिज़िक्लोप

1
@FicratedWithFormsDesigner @biziclop के रूप में बताया, उत्पन्न कोड एक पूरी तरह से अलग जानवर है। नामांकित स्थिरांक का उपयोग उस कोड में किया जाना चाहिए जो लोगों द्वारा पढ़ा और संशोधित किया गया हो। उत्पन्न कोड, कम से कम आदर्श मामले में, बिल्कुल भी संशोधित नहीं होना चाहिए।
दिमा

2
@FrustratedWithFormsDesigner: क्या होता है जब आपके पास अपने कार्यक्रम में दर्जनों फाइलों में एक प्रसिद्ध मूल्य हार्ड-कोडेड होता है जिसे अचानक बदलने की आवश्यकता होती है? उदाहरण के लिए, आप हार्ड-कोड को एक एम्बेडेड प्रोसेसर के लिए माइक्रो-सेकंड प्रति घड़ी-टिक की संख्या का प्रतिनिधित्व करते हैं, फिर आपके सॉफ़्टवेयर को एक डिज़ाइन में पोर्ट करने के लिए कहा जाता है, जहां माइक्रोक्रॉन्ड प्रति घड़ी-टिक की एक अलग संख्या होती है। यदि आपका मूल्य कुछ सामान्य था, जैसे 8, दर्जनों फाइलों पर एक खोज / प्रतिस्थापित करना अधिक समस्याएं पैदा कर सकता है।
oosterwal

8

रुकें जब आप संख्या के लिए एक अर्थ या उद्देश्य को पिन नहीं कर सकते।

seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE

केवल संख्याओं का उपयोग करने की तुलना में पढ़ना बहुत आसान है। (हालांकि इसे एक SECONDS_PER_DAYस्थिर होने से अधिक पठनीय बनाया जा सकता है , लेकिन यह एक पूरी तरह से अलग मुद्दा है।)

मान लें कि कोड को देखने वाला एक डेवलपर यह देख सकता है कि वह क्या करता है। लेकिन यह मत समझिए कि वे भी जानते हैं कि क्यों। यदि आपका निरंतर क्यों समझने में मदद करता है, तो इसके लिए जाएं। यदि नहीं, तो नहीं।

यदि आप बहुत सारे स्थिरांक के साथ समाप्त हो जाते हैं, जैसा कि एक उत्तर द्वारा सुझाया गया था, तो इसके बजाय एक बाहरी कॉन्फ़िगरेशन फ़ाइल का उपयोग करने पर विचार करें, क्योंकि फ़ाइल में दर्जनों स्थिरांक होने से पठनीयता में सुधार नहीं होता है।


7

मैं शायद "नहीं" कहना चाहूंगा जैसे:

#define HTML_END_TAG "</html>"

और निश्चित रूप से "नहीं" कहेंगे:

#define QUADRATIC_DISCRIMINANT_COEF 4
#define QUADRATIC_DENOMINATOR_COEF  2

7

सबसे अच्छे उदाहरणों में से एक है जो मैंने स्पष्ट चीजों के लिए स्थिरांक के उपयोग को बढ़ावा देने के लिए पाया HOURS_PER_DAYहै:

हम गणना कर रहे थे कि किसी व्यक्ति की नौकरी की कतार में कितनी देर बैठे थे। आवश्यकताओं को शिथिल रूप से परिभाषित किया गया था और प्रोग्रामर को 24कई स्थानों पर कोडित किया गया था। आखिरकार हमने महसूस किया कि उपयोगकर्ताओं को 24 घंटे तक एक समस्या पर बैठने के लिए दंडित करना उचित नहीं था जब वास्तव में केवल 8 घंटे काम करते हैं। जब कार्य इसे ठीक करने के लिए आया था और देखें कि अन्य रिपोर्ट में वही समस्या हो सकती है जो कि जीआरपी के लिए कोड के माध्यम से खोज करना बहुत मुश्किल था / खोज करना बहुत आसान हो गया है।HOURS_PER_DAY


ओह नो, इसलिए प्रति दिन घंटे अलग-अलग होते हैं, चाहे आप प्रति दिन काम के घंटे देखें (मैं 7.5 BTW काम करता हूं) या एक दिन में घंटे। इस तरह से स्थिरांक का अर्थ बदलने के लिए, आप इसका नाम किसी और चीज़ में बदलना चाहेंगे। आसान बनाया गया खोज के बारे में आपकी बात हालांकि मान्य है।
gbjbaanb 21

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

4

मुझे लगता है कि जब तक संख्या पूरी तरह से स्थिर है और बदलने की कोई संभावना नहीं है, यह पूरी तरह से स्वीकार्य है। तो आपके मामले में, seconds = num_days * 24 * 60 * 60ठीक है (यह मानते हुए कि आप कुछ मूर्खतापूर्ण नहीं करते हैं जैसे लूप के अंदर इस तरह की गणना करते हैं) और यकीनन पठनीयता के लिए बेहतर है seconds = num_days * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE

जब आप इस तरह की चीजें करते हैं तो यह बुरा है:

lineOffset += 24; // 24 lines to a page

यहां तक ​​कि अगर आप पृष्ठ पर अब और लाइनों को फिट नहीं कर सकते हैं या यहां तक ​​कि अगर आपके पास इसे बदलने का कोई इरादा नहीं है, तो इसके बजाय एक निरंतर चर का उपयोग करें, क्योंकि एक दिन यह आपको वापस लाने के लिए आने वाला है। अंत में, बिंदु पठनीयता है, सीपीयू पर गणना के 2 चक्रों को नहीं बचा रहा है। यह अब 1978 नहीं है जब कीमती बाइट्स को उनके सभी मूल्य के लिए निचोड़ा गया था।


2
क्या आप नामांकित निरंतर SECONDS_PER_DAY का उपयोग करने के बजाय अपरिवर्तनीय मूल्य 86400 को हार्ड-कोड करना स्वीकार्य होगा? आप यह कैसे सत्यापित करेंगे कि मूल्य की सभी घटनाएं सही थीं और उदाहरण के लिए 6 विज्ञापन 4 को स्वैप या स्वैप नहीं किया गया था?
oosterwal

फिर क्यों नहीं: सेकंड = संख्या_दिन * 86400? वह भी नहीं बदलेगा।
जेएफओ

2
मैंने SECONDS_PER_DAY बात दोनों तरीकों से की है - नाम का उपयोग करके और संख्या का उपयोग करके। जब आप 2 साल बाद कोड पर वापस आते हैं, तो नामांकित संख्या हमेशा अधिक समझ में आती है।
जल्दी_नौ

2
सेकंड = num_days * 86400 मेरे लिए स्पष्ट नहीं है। यही अंततः मायने रखता है। अगर मैं "सेकंड = संख्या_ दिन * 24 * 60 * 60" देखता हूं, तो इस तथ्य से अलग कि चर नाम इस अर्थ में काफी अच्छी तरह से उधार देते हैं, मैं तुरंत खुद से पूछूंगा कि मैंने उन्हें अलग क्यों किया और अर्थ स्पष्ट हो जाता है क्योंकि मैंने छोड़ दिया उन्हें संख्या के रूप में (इसलिए वे स्थिर हैं), वे चर नहीं जिनकी आगे की जांच से मुझे उनके मूल्यों को समझने की आवश्यकता होगी और यदि वे स्थिर हैं।
नील

1
लोगों को अक्सर महसूस नहीं होता है: यदि आप उस लाइनऑफ़सेट मूल्य को 24 से 25 तक बदलते हैं, तो आपको अपने सभी कोड से गुजरना होगा, यह देखने के लिए कि कहाँ 24 का उपयोग किया गया था और यदि इसे बदलने की आवश्यकता है, और फिर सभी दिनों से लेकर घंटों की गणना तक 24 से गुणा करना वास्तव में आपके रास्ते में आता है।
gnasher729

3
seconds = num_days * 24 * 60 * 60

बिलकुल ठीक है। ये वास्तव में जादू की संख्या नहीं हैं क्योंकि वे कभी नहीं बदलेंगे।

कोई भी संख्या जो यथोचित रूप से बदल सकती है या जिसका कोई स्पष्ट अर्थ नहीं है, को चर में रखा जाना चाहिए। जिसका मतलब है कि उन सभी को बहुत अधिक।


2
seconds = num_days * 86400अभी भी स्वीकार्य होगा ? यदि कई अलग-अलग फ़ाइलों में कई बार उपयोग किए गए मान की तरह, आप यह कैसे सत्यापित करेंगे कि किसी ने गलती seconds = num_days * 84600से एक या दो स्थानों पर टाइप नहीं किया है ?
oosterwal

1
86400 लेखन लेखन से बहुत अलग है 24 * 60 * 60
Carra

4
जरूर बदलेगी। हर दिन इसमें 86,400 सेकंड नहीं होते हैं। उदाहरण के लिए, दिन की बचत समय पर विचार करें। साल में एक बार, कुछ स्थानों केवल एक दिन में 23 घंटे है, और एक और दिन वे 25 होगा poof अपने नंबरों टूट रहे हैं।
डेव डेलॉन्ग

1
@Dave, उत्कृष्ट बिंदु। लीप सेकंड मौजूद हैं - en.wikipedia.org/wiki/Leap_second

निष्पक्ष बिंदु। यदि आप कभी भी उन अपवादों को पकड़ना चाहते हैं, तो एक फ़ंक्शन जोड़ना एक सुरक्षा उपाय होगा।
कार्रा

3

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

इस स्थिति में मैं कभी भी सेकंड / मिनट / घंटे का उपयोग नहीं करूंगा। मैं केवल TimeSpan / DateTime का उपयोग करूंगा।


1

निर्णय लेने के लिए एक पैरामीटर के रूप में संदर्भ का उपयोग करें

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

और एक और सवाल यह है कि अलग-अलग तरीके से इसकी गणना करने की संभावनाएं क्या हैं? कभी-कभी एक ही काम करने के बहुत सारे तरीके होते हैं, इसलिए भविष्य के प्रोग्रामर को निर्देशित करने और उन्हें दिखाने के लिए कि आपने किस पद्धति का उपयोग किया है, स्थिरांक को परिभाषित करने से यह पता लगाने में मदद मिल सकती है।

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