कोड के लिए रक्षात्मक प्रोग्रामिंग प्रथाओं का पालन करना कितना आवश्यक है जिसे कभी भी सार्वजनिक रूप से उपलब्ध नहीं कराया जाएगा?


45

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

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

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


4
= ~ एस / आवश्यक / अनुशंसित / जीआई
ग्रैंडमास्टरबी

2
डेटा प्रकार निर्माण द्वारा सही होना चाहिए, अन्यथा आप क्या निर्माण कर रहे हैं? उन्हें इस तरह से समझाया जाना चाहिए कि, परिवर्तनशील या नहीं, वे केवल वैध राज्यों में ही हो सकते हैं। केवल तभी यदि यह वैधानिक रूप से लागू करना असंभव है (या अनुचित रूप से कठिन) आपको एक रनटाइम त्रुटि को उठाना चाहिए।
जॉन पर्सी

1
नेवर से नेवर। जब तक आपके कोड का उपयोग कभी नहीं किया जाता है, तो आप कभी भी कुछ के लिए नहीं जान सकते हैं कि आपका कोड कहां समाप्त होगा। ;)
इज़्काता

1
@codebreaker ग्रैंडमास्टरबी की टिप्पणी यह ​​एक प्रतिस्थापित अभिव्यक्ति है। इसका अर्थ है: "आवश्यक" को "अनुशंसित" से बदल दें।
रिकार्डो सूजा

1
कोडलेस कोड # 116 ट्रस्ट नो वन विशेष रूप से उपयुक्त है।

जवाबों:


72

मैं डिजाइन की समस्या का समाधान नहीं करने जा रहा हूं - बस यह सवाल कि क्या गैर-सार्वजनिक एपीआई में "सही ढंग से" चीजें करना है।

यह सिर्फ मेरे लिए है, इसलिए यह ऐसा है जैसे मैं अपने कोड को खुद से बचा रहा हूं

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

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


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

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

2
मैं निश्चित रूप से सहमत हूं। कॉलेज में वापस मुझे इसके बारे में कभी नहीं सोचना था, हालांकि।
कोडब्रेकर

25

मैं आमतौर पर कुछ सरल नियमों का पालन करता हूं:

  • हमेशा अनुबंध द्वारा कार्यक्रम करने का प्रयास करें ।
  • यदि कोई विधि सार्वजनिक रूप से उपलब्ध है या बाहरी दुनिया से इनपुट प्राप्त करती है , तो कुछ रक्षात्मक उपाय (जैसे IllegalArgumentException) लागू करें ।
  • बाकी सब के लिए जो केवल आंतरिक रूप से सुलभ है, अभिकथन (जैसे assert input != null) का उपयोग करें ।

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

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


1
अनुबंध द्वारा डिजाइन का उल्लेख करने के लिए +1। यदि आप व्यवहार को पूरी तरह से प्रतिबंधित नहीं कर सकते हैं (और ऐसा करना कठिन है) तो कम से कम आप स्पष्ट कर दें कि बुरे व्यवहार की कोई गारंटी नहीं है। मुझे भी एक IllegalStateException या एक UnsupportedOperationException फेंकना पसंद है।
user949300 22

@ user949300 ज़रूर। मुझे विश्वास है कि इस तरह के अपवादों को एक सार्थक उद्देश्य के साथ पेश किया गया था। सम्मानजनक अनुबंध इस तरह की भूमिका के लिए उपयुक्त हैं।
afsantos

16

रक्षात्मक प्रोग्रामिंग एक बहुत अच्छी बात है।
जब तक यह कोड लिखने के तरीके में शुरू नहीं होता है। तब यह इतनी अच्छी बात नहीं है।


थोड़ा और व्यावहारिक रूप से बोलते हुए ...

ऐसा लगता है कि आप चीजों को बहुत दूर ले जाने के किनारे पर सही हैं। चुनौती (और आपके प्रश्न का उत्तर) यह समझने में निहित है कि कार्यक्रम के व्यावसायिक नियम या आवश्यकताएं क्या हैं।

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

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


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

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


2
+1 के लिए "जब तक यह कोड लिखने के तरीके से शुरू नहीं होता है।" विशेष रूप से लघु-व्यक्तिगत परियोजनाओं के लिए, रक्षात्मक रूप से कोडिंग करना इसके लायक होने की तुलना में अधिक समय ले सकता है।
कोरी

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

13

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

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

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


1
मैंने ज़ोन को कार्ड की संपत्ति माना, लेकिन चूंकि मेरे कार्ड अपरिवर्तनीय वस्तुओं के रूप में बेहतर काम करते हैं, इसलिए मैंने फैसला किया कि यह तरीका सबसे अच्छा था। सलाह के लिए धन्यवाद।
कोडब्रेकर

3
@ कोडब्रेकर एक चीज जो उस स्थिति में मदद कर सकती है, वह कार्ड को किसी अन्य ऑब्जेक्ट में इनकैप्सुलेट कर रही है। हुकुम का एक ऐस यह क्या है। स्थान इसकी पहचान को परिभाषित नहीं करता है, और एक कार्ड शायद अपरिवर्तनीय होना चाहिए। हो सकता है कि एक ज़ोन में कार्ड हों: हो सकता है CardDescriptorकि इसमें एक कार्ड हो, उसका स्थान, चेहरा ऊपर / नीचे की स्थिति, या यहां तक ​​कि उन खेलों के लिए रोटेशन जो उसकी देखभाल करते हैं। वे सभी परिवर्तनशील गुण हैं जो कार्ड की पहचान को नहीं बदलते हैं।

1

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

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

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


2
आपका जवाब ओआरएस सामान्य रूप से रक्षात्मक प्रोग्रामिंग के बारे में पूछ रहा है व्यापक सवालों के बजाय हाथ में समस्या पर थोड़ा बहुत ध्यान केंद्रित करता है।

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

@ GlenH7: मुझे लगता है कि विशिष्ट उदाहरणों के साथ काम करना अक्सर अमूर्त सिद्धांत से अधिक मदद करता है। ओपी ने एक दिलचस्प कहानी प्रदान की, इसलिए मैं उसके साथ गया।
राल्फचेपिन

1

एपीआई डिजाइन में रक्षात्मक कोडिंग आम तौर पर इनपुट को मान्य करने और उचित त्रुटि हैंडलिंग तंत्र का चयन करने के बारे में है। अन्य बातों का उल्लेख भी ध्यान देने योग्य हैं।

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

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

हालाँकि, यह कार्यान्वयन Collection<Card>कार्डों के अधिक - प्रकार के सेट के एक कम प्रकार के समान होता है , जिसमें कम प्रतिबंधक एपीआई होता है। उदाहरण के लिए जब आप हैंड वैल्यू कैलकुलेटर, या एआई का निर्माण करना चाहते हैं, तो आप निश्चित रूप से यह चुनने के लिए स्वतंत्र होना चाहते हैं कि आप प्रत्येक कार्ड में से कितने और कितने का चयन करते हैं।

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

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