2009-06-07 13 views
6

अस्वीकरण: मैं वर्तमान में प्रोग्राम सीखने वाला एक व्यक्ति हूं। कभी भी एक परियोजना का हिस्सा नहीं रहा, न ही ~ 500 लाइनों से अधिक कुछ भी लिखा।क्या रक्षात्मक प्रोग्रामिंग DRY सिद्धांत का उल्लंघन करती है?

मेरा प्रश्न है: क्या रक्षात्मक प्रोग्रामिंग उल्लंघन का उल्लंघन करती है सिद्धांत को दोहराएं? रक्षात्मक प्रोग्रामिंग की मेरी परिभाषा मानना ​​सही है (कॉलिंग फ़ंक्शन विपरीत के बजाय इनपुट मान्य करता है), क्या यह आपके कोड के लिए हानिकारक नहीं होगा?

int foo(int bar) 
{ 
    if (bar != /*condition*/) 
    { 
     //code, assert, return, etc. 
    } 
} 

int main() 
{ 
    int input = 10; 
    foo(input); //doesn't the extra logic 
    foo(input); //and potentially extra calls 
    foo(input); //work against you? 
} 

इस की तुलना में:

int main() 
{ 
    if (input == /*condition*/) 
    { 
     foo(input); 
     foo(input); 
     foo(input); 
    } 
} 

फिर, एक layperson के रूप में, मैं कितना सरल तर्क बयान आप के खिलाफ जहां तक ​​गिनती नहीं जानते

उदाहरण के लिए, यह बुरा है प्रदर्शन के रूप में, लेकिन निश्चित रूप से रक्षात्मक प्रोग्रामिंग कार्यक्रम या आत्मा के लिए अच्छा नहीं है।

+0

यह सी ++ से कैसे संबंधित है? – xtofl

+0

क्षमा करें, अगर आप चाहें तो उस टैग को हटा दें..मैंने उदाहरणों में इसका इस्तेमाल किया था। – jkeys

+0

मैंने इसे लिखा था जब मैं 15 साल की उम्र में खुद को पढ़ रहा था। मुझे शायद अब कम चर्चा शब्द पता हैं, लेकिन मैंने और अधिक महत्वपूर्ण कार्यक्रम लिखे हैं। मुझे लगता है कि दो कदम आगे ... – jkeys

उत्तर

6

यह सब अनुबंध इंटरफ़ेस प्रदान करता है। इसके लिए दो अलग-अलग परिदृश्य हैं: इनपुट और आउटपुट।

इनपुट - और इसके द्वारा मैं मूल रूप से कार्यों के पैरामीटर का मतलब है - कार्यान्वयन द्वारा सामान्य नियम के रूप में जांच की जानी चाहिए।

आउटपुट - रिटर्न परिणाम होने पर - कम से कम मेरी राय में कॉलर द्वारा मूल रूप से भरोसा किया जाना चाहिए।

यह सब इस प्रश्न से बदतर है: क्या होता है यदि कोई पार्टी अनुबंध तोड़ती है? उदाहरण के लिए, मान लीजिए कि आपने एक अंतरफलक था:

class A { 
    public: 
    const char *get_stuff(); 
} 

और कहा कि अनुबंध निर्दिष्ट करता है कि एक अशक्त स्ट्रिंग लौटा दी कभी नहीं होगा (इसे रिक्त स्ट्रिंग पर सबसे खराब हो जाएगा) तो यह ऐसा करने के लिए सुरक्षित है:

A a = ... 
char buf[1000]; 
strcpy(buf, a.get_stuff()); 

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

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

बेशक परिस्थितियां इसे बदल सकती हैं।

+2

+1 यह सब इंटरफेस प्रदान करता अनुबंध के लिए आता है। रक्षात्मक कार्यक्रम! = मास्किंग समस्याएं, रक्षात्मक कार्यक्रम == अनुबंधों का उल्लंघन होने पर अपवाद फेंकने से समस्याएं उजागर कर रही हैं। – TimW

4

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

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

हालांकि मैं कभी भी डबल कंडीशन चेक पर काम नहीं करता। उन्हें पूरी तरह से दूसरी तरफ फेंकना आमतौर पर कई गुना अधिक खराब होता है :)

1

आपके सरलीकृत उदाहरण में, हाँ, दूसरा प्रारूप संभवतः बेहतर है।

हालांकि, कि वास्तव में, बड़ा और अधिक जटिल है, और अधिक यथार्थवादी कार्यक्रमों के लिए लागू नहीं होता।

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

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

void RepeatFoo(int bar, int repeatCount) 
{ 
    /* Validate bar */ 
    if (bar != /*condition*/) 
    { 
     //code, assert, return, etc. 
    } 

    for(int i=0; i<repeatCount; ++i) 
    { 
     UnprotectedFoo(bar); 
    } 
} 

void UnprotectedFoo(int bar) 
{ 
    /* Note: no validation */ 

    /* do something with bar */ 
} 

void Foo(int bar) 
{ 
    /* Validate bar */ 
    /* either do the work, or call UnprotectedFoo */ 
} 
:

आप वास्तव में एक पैटर्न जहां "foo" एक ही इनपुट के साथ कई बार कहा जाता हो जाएगा है, तो मैं एक आवरण समारोह है कि सत्यापन एक बार करता है, और एक असुरक्षित संस्करण है कि सत्यापन के पक्ष कदम का सुझाव

+1

BarIsValid() को बेनकाब करने के लिए बेहतर है और कॉलर को अपना लूप लिखने दें। फिर आपके पास न्यूनतम API है: BarIsValid() और Foo(), और जब कोई उपयोगकर्ता अधिक जटिल लूप चाहता है तो एपीआई को विस्तारित करने की आवश्यकता नहीं होगी। पुनश्च: मुझे लगता है कि RepeatBar बार मान्य नहीं करना चाहिए जब repeatCount 0. –

9

सूखी सिद्धांत का उल्लंघन है कि तरह लग रहा है:

int foo(int bar) 
{ 
    if (bar != /*condition*/) 
    { 
     //code, assert, return, etc. 
    } 
} 

int main() 
{ 
    int input = 10; 
    if (input == /*condition*/) 
    { 
     foo(input); 
     foo(input); 
     foo(input); 
    } 
} 

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

+0

मुझे लगता है कि यह है कि झुका क्या कहना है यह जाँच नहीं कर रहा था 2 बार, लेकिन केवल मुख्य() फ़ंक्शन में करना चाहता था। –

+0

यह एक अच्छा उदाहरण है। हालांकि कोई तर्क दे सकता है कि आपके 'foo' फ़ंक्शन में' if' एक जोर था, जो "रक्षा" का हिस्सा है; तो हम किसी भी तरह से, खुद को दोहराना होगा, लेकिन कम, और दोनों वास्तव में आवश्यक होगा। –

1

जैसा कि एलेक्स ने कहा, यह स्थिति पर निर्भर करता है, उदाहरण के लिए, मैं लगभग हमेशा इनपुट को मान्य करता हूं प्रक्रिया में लॉग के हर चरण।

अन्य स्थानों पर, आपको इसकी आवश्यकता नहीं है।

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

इनपुट हमेशा जांच की जानी है, तो सिर्फ समारोह में शामिल।

3

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

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

उस कथन के साथ एक समस्या है, बेशक, एक कार्यक्रम, यहां तक ​​कि मिशन महत्वपूर्ण भी हो सकता है, जब यह एक असंगत स्थिति में जारी रहता है। बेशक यह वास्तव में नहीं कर सकता है।

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

+0

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