तीसरे पक्ष के पुस्तकालयों का उपयोग करना - हमेशा एक आवरण का उपयोग करें?


78

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

एक उदाहरण के रूप में, हमारी अधिकांश PHP परियोजनाएं लॉग लॉगिंग के रूप में सीधे log4php का उपयोग करती हैं, अर्थात वे \ Logger :: getLogger () के माध्यम से त्वरित करते हैं, वे -> जानकारी () या -> चेतावनी () विधियों, आदि का उपयोग भविष्य में करते हैं। हालाँकि, एक काल्पनिक लॉगिंग ढांचा दिखाई दे सकता है जो किसी तरह से बेहतर है। जैसा कि यह खड़ा है, सभी परियोजनाएं जो लॉग 4 एफपीपी विधि हस्ताक्षरों के करीब हैं, उन्हें नए हस्ताक्षरों को फिट करने के लिए दर्जनों स्थानों में बदलना होगा। यह स्पष्ट रूप से कोडबेस पर व्यापक प्रभाव डालता है और कोई भी परिवर्तन संभावित समस्या है।

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

यह ध्यान में रखते हुए कि अन्य पुस्तकालयों के साथ अधिक जटिल उदाहरण हैं, क्या मैं ओवर-इंजीनियरिंग कर रहा हूं या यह ज्यादातर मामलों में एक बुद्धिमान एहतियात है?

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


3
log4XYZ एक ऐसा मजबूत ट्रेडमार्क है। जब लिंक लिंक्ड सूची के लिए एपीआई होगा, तो उसका एपीआई जल्द नहीं बदलेगा। दोनों एक लंबे समय से हल की समस्या है।
नौकरी

1
इस SO प्रश्न का सटीक डुप्लिकेट: stackoverflow.com/questions/1916030/…
माइकल बोर्गवर्ड

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

1
आगे के संदर्भ के लिए: इस पैटर्न को प्याज-वास्तुकला कहा जाता है, जहां बाहरी बुनियादी ढांचे (आप इसे बाहरी कामेच्छा कहते हैं) एक इंटरफ़ेस के पीछे छिपे हुए हैं
k3b

जवाबों:


42

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

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


अच्छे अंक, लेकिन हमें सिखाया जाता है कि निकट-युग्मित कोड खराब है, कई अच्छी तरह से समझ में आने वाले कारणों (परीक्षण करने के लिए कठिन, रिफ्लेक्टर के लिए कठिन, आदि) के लिए। प्रश्न का एक वैकल्पिक शब्द है, "यदि युग्मन खराब है, तो एपीआई से जोड़े के लिए ठीक क्यों है?"।
लॉटऑफ्रीटाइम सेप 11'11

7
@lotsoffreetime आप किसी एपीआई को कुछ युग्मन से नहीं बचा सकते हैं। इसलिए, अपने स्वयं के एपीआई को युगल करना बेहतर है। इस तरह, आप लाइब्रेरी को बदल सकते हैं और आमतौर पर रैपर द्वारा दिए गए एपीआई को बदलने की आवश्यकता नहीं होती है।
जॉर्ज मैरियन

@ george-marian यदि मैं किसी दिए गए एपीआई का उपयोग करने से बच नहीं सकता , तो मैं निश्चित रूप से स्पर्श बिंदुओं को कम कर सकता हूं। सवाल यह है कि, क्या मुझे हर समय ऐसा करने की कोशिश करनी चाहिए या क्या यह बहुत ज्यादा है?
लॉटऑफ्रीटाइम

2
@lotsoffreetime यह जवाब देने के लिए एक मुश्किल सवाल है। मैंने उस छोर पर अपने जवाब का विस्तार किया है। (मूल रूप से, यह बहुत सारे इफ्स के लिए है।)
जॉर्ज मैरियन

2
@lotsoffreetime: यदि आपके पास बहुत सारा खाली समय है, तो आप या तो कर सकते हैं। लेकिन मैं इस शर्त के अलावा एक एपीआई आवरण लिखने के खिलाफ सिफारिश करूंगा: 1) मूल एपीआई बहुत निम्न स्तर है, इसलिए आप अपनी विशिष्ट परियोजना को बेहतर करने के लिए उच्च स्तरीय एपीआई लिखते हैं, या 2) आपके पास एक योजना है पुस्तकालयों को स्विच करने के निकट भविष्य में, आप वर्तमान पुस्तकालय का उपयोग केवल एक बेहतर पत्थर की खोज करते हुए एक कदम पत्थर के रूप में कर रहे हैं।
रेयान

28

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

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

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


"... रैपर वास्तव में केवल तभी समझ में आता है जब आप पहले से ही उन सभी एपीआई को जानते हैं जिन्हें आपको लपेटने की आवश्यकता है।" यह सही होगा यदि मैं रैपर में एपीआई का मिलान कर रहा था; शायद मुझे "एनकैप्सुलेशन" शब्द का उपयोग रैपर की तुलना में अधिक दृढ़ता से करना चाहिए। मैं इन एपीआई कॉल्स को "इस फॉम के साथ कॉल फू :: लॉग ()" के बजाय "इस टेक्स्ट को किसी तरह लॉग इन" करने के लिए एब्सट्रैक्ट कर रहा हूं।
लॉटऑफ्रीटाइम सेप

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

27

थर्ड पार्टी लाइब्रेरी को रैप करके आप उसके ऊपर एब्सट्रैक्शन की एक अतिरिक्त परत जोड़ते हैं। इसके कुछ फायदे हैं:

  • आपका कोड आधार परिवर्तनों के प्रति अधिक लचीला हो जाता है

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

  • आप लाइब्रेरी के एपीआई से स्वतंत्र रूप से रैपर के एपीआई को परिभाषित कर सकते हैं

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

  • इकाई परीक्षण तरीका सरल है

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

  • आप एक शिथिल युग्मित प्रणाली बनाते हैं

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


व्यावहारिक उदाहरण

चलो ईमानदार बनें। लोग घंटों तक कुछ इस तरह के फायदे और नुकसान के बारे में बहस कर सकते हैं - यही वजह है कि मैं बहुत कुछ सिर्फ आपको एक उदाहरण दिखाता हूं।

मान लीजिए कि आपके पास किसी प्रकार का Android एप्लिकेशन है और आपको चित्र डाउनलोड करने की आवश्यकता है। वहाँ पुस्तकालयों का एक समूह है जो लोडिंग और कैशिंग छवियों को उदाहरण के लिए पिकासो या यूनिवर्सल इमेज लोडर के लिए एक हवा बनाते हैं ।

अब हम एक इंटरफ़ेस को परिभाषित कर सकते हैं जिसका उपयोग हम करने जा रहे हैं जो भी पुस्तकालय का उपयोग करते हुए समाप्त होता है:

public interface ImageService {
    Bitmap load(String url);
}

यह वह इंटरफ़ेस है जिसे हम अब पूरे ऐप में उपयोग कर सकते हैं जब भी हमें किसी इमेज को लोड करने की आवश्यकता होती है। हम इस इंटरफ़ेस का कार्यान्वयन बना सकते हैं और उस कार्यान्वयन की एक आवृत्ति को इंजेक्ट करने के लिए निर्भरता इंजेक्शन का उपयोग कर सकते हैं जहाँ हम उपयोग करते हैं ImageService

मान लीजिए कि हम शुरू में पिकासो का उपयोग करने का निर्णय लेते हैं। अब हम एक कार्यान्वयन लिख सकते हैं ImageServiceजिसके लिए पिकासो आंतरिक रूप से उपयोग करता है:

public class PicassoImageService implements ImageService {

    private final Context mContext;

    public PicassoImageService(Context context) {
        mContext = context;
    }

    @Override
    public Bitmap load(String url) {
        return Picasso.with(mContext).load(url).get();
    }
}

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

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

public class UniversalImageLoaderImageService implements ImageService {

    private final ImageLoader mImageLoader;

    public UniversalImageLoaderImageService(Context context) {

        DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .build();

        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
                .defaultDisplayImageOptions(defaultOptions)
                .build();

        mImageLoader = ImageLoader.getInstance();
        mImageLoader.init(config);
    }

    @Override
    public Bitmap load(String url) {
        return mImageLoader.loadImageSync(url);
    }
}

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

कम से कम मेरे लिए यह सब पहले से ही बहुत अच्छा लग रहा है, लेकिन रुको! अभी और भी बहुत कुछ है। कल्पना कीजिए कि आप जिस कक्षा में काम कर रहे हैं, उसके लिए इकाई परीक्षण लिख रहे हैं और यह वर्ग इसका उपयोग करता है ImageService। बेशक, आप अपने यूनिट परीक्षणों को किसी अन्य सर्वर पर स्थित कुछ संसाधन पर नेटवर्क कॉल करने की अनुमति नहीं दे सकते हैं, लेकिन चूंकि अब ImageServiceआप उपयोग कर रहे हैं, आप आसानी से एक नकली को लागू करके यूनिट परीक्षणों के लिए उपयोग किए जाने वाले load()स्थैतिक को वापस कर सकते हैं :BitmapImageService

public class MockImageService implements ImageService {

    private final Bitmap mMockBitmap;

    public MockImageService(Bitmap mockBitmap) {
        mMockBitmap = mockBitmap;
    }

    @Override
    public Bitmap load(String url) {
        return mMockBitmap;
    }
}

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


1
यह बस एक अस्थिर API पर भी लागू होता है। हमारा कोड 1000 जगहों पर सिर्फ इसलिए नहीं बदला क्योंकि अंतर्निहित लाइब्रेरी बदल गई। बहुत अच्छा जवाब।
रबरडैक

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

आपका उत्तर सुपर सहायक था और एक उदाहरण के साथ अवधारणा को प्रस्तुत करना अवधारणा को और भी स्पष्ट कर दिया।
अनिल गोरथी

24

मुझे लगता है कि अगर कल कुछ बेहतर होता है तो तीसरे पक्ष के पुस्तकालयों को लपेटना कल YAGNI का बहुत व्यर्थ उल्लंघन है। यदि आप बार-बार अपने आवेदन में एक तरीके से तृतीय-पक्ष कोड को कॉल कर रहे हैं, तो आप पुनरावृत्ति को समाप्त करने के लिए उन कॉल को एक रैपिंग क्लास में रिफ्लेक्टर करेंगे। अन्यथा आप पूरी तरह से पुस्तकालय एपीआई का उपयोग कर रहे हैं और कोई भी आवरण केवल पुस्तकालय की तरह दिखेगा।

अब मान लीजिए कि एक नया पुस्तकालय बेहतर प्रदर्शन या जो भी हो, के साथ दिखाई देता है। पहले मामले में, आप बस नए एपीआई के लिए रैपर को फिर से लिखते हैं। कोई दिक्कत नहीं है।

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


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

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

3
@lotsoffreetime: "अच्छा डिज़ाइन" का उद्देश्य जीवन पर आवेदन की कुल लागत को कम करना है। भविष्य के परिवर्तनों के लिए अप्रत्यक्ष की परतों को जोड़ना बहुत महंगा बीमा है। मैंने कभी किसी को उस दृष्टिकोण से किसी भी बचत का एहसास नहीं देखा। यह सिर्फ उन प्रोग्रामर के लिए तुच्छ कार्य बनाता है, जिनका समय ग्राहक-विशिष्ट आवश्यकताओं पर बेहतर ढंग से व्यतीत होगा। अधिकांश समय, यदि आप कोड लिख रहे हैं जो आपके ग्राहक के लिए विशिष्ट नहीं है, तो आप समय और धन बर्बाद कर रहे हैं।
केविन क्लाइन

1
@ जॉर्ज: अगर ये बदलाव दर्दनाक हैं, तो मुझे लगता है कि यह एक प्रक्रिया गंध है। जावा में, मैं पुरानी कक्षाओं के समान नामों के साथ नई कक्षाएं बनाऊंगा, लेकिन एक अलग पैकेज में, पुराने पैकेज के नाम की सभी घटनाओं को बदल देंगे, और स्वचालित परीक्षणों को फिर से चलाएँगे।
केविन क्लाइन

1
@kevin यह अधिक काम है, और इस प्रकार अधिक जोखिम होता है, बस आवरण को अद्यतन करने और परीक्षण चलाने से।
जॉर्ज मैरियन

9

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

क्या यह प्रयास के लायक है एक अलग कहानी है। यह बहस संभवतः लंबे समय तक जारी रहेगी।

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

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


यूनिट परीक्षण के मामले में जहां एपीआई के एक मॉक को इंजेक्ट करने में सक्षम होना परीक्षण के तहत यूनिट को कम करने के लिए कार्य करता है, "परिवर्तन क्षमता" एक कारक नहीं है। यह कहते हुए कि, यह अभी भी मेरा पसंदीदा उत्तर है क्योंकि यह मेरे विचार से सबसे करीब है। अंकल बॉब क्या कहेंगे? :)
लॉटऑफ्रीटाइम

इसके अलावा, छोटी परियोजनाओं (कोई टीम, मूल कल्पना, आदि) के अपने नियम नहीं हैं जिनमें आप इस तरह के अच्छे अभ्यास का उल्लंघन कर सकते हैं और एक हद तक इसके साथ भाग सकते हैं। लेकिन यह एक अलग सवाल है ...
लॉटऑफ्रीटाइम

1

पहले से ही कहा गया @ के अतिरिक्त , मैं केवल लॉगिंग के विशेष उद्देश्य के लिए इस उत्तर को जोड़ना चाहूंगा।


मेरे पास हमेशा लॉगिंग के लिए एक इंटरफ़ेस है, लेकिन मुझे कभी भी एक log4fooरूपरेखा नहीं चुननी पड़ी।

इंटरफ़ेस प्रदान करने और आवरण को लिखने में केवल आधे घंटे लगते हैं, इसलिए मुझे लगता है कि यदि आप आवश्यक नहीं हैं तो आपको बहुत समय बर्बाद नहीं करना चाहिए।

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


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

@ फाल्कन: क्या आप सब कुछ लपेटते हैं? ORM, लॉग इंटरफ़ेस, मुख्य भाषा कक्षाएं? आखिरकार, कोई भी यह नहीं बता सकता है कि बेहतर हाशप की आवश्यकता कब हो सकती है।
केविन क्लाइन

1

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

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


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

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


1

मैं रैपिंग कैंप में दृढ़ता से हूं और सबसे बड़ी प्राथमिकता (हालांकि यह एक बोनस है) के साथ तीसरे पक्ष के पुस्तकालय को स्थानापन्न करने में सक्षम नहीं है। मेरा मुख्य तर्क यह है कि रैपिंग के पक्षधर हैं

तृतीय पक्ष पुस्तकालय हमारी विशिष्ट आवश्यकताओं के लिए डिज़ाइन नहीं किए गए हैं।

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

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

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

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

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


0

तृतीय-पक्ष पुस्तकालयों पर मेरा विचार:

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

क्या हमें तृतीय-पक्ष UI लाइब्रेरीज़ का उपयोग करने से बचना चाहिए?

तृतीय-पक्ष पुस्तकालयों पर विचार करने के कारण:

ऐसा लगता है कि दो मुख्य कारण डेवलपर्स को तीसरे पक्ष के पुस्तकालय का उपयोग करने पर विचार करते हैं:

  1. कौशल या ज्ञान का अभाव। मान लीजिए, आप फोटो शेयरिंग ऐप पर काम कर रहे हैं। आप अपने स्वयं के क्रिप्टो को रोल करके शुरू नहीं करते हैं।
  2. कुछ बनाने के लिए समय या रुचि का अभाव। जब तक आपके पास असीमित मात्रा में समय (जो अभी तक कोई मानव नहीं है) आपको प्राथमिकता देना होगा।

अधिकांश UI लाइब्रेरीज़ ( सभी नहीं! ) दूसरी श्रेणी में आती हैं। यह सामान कोई रॉकेट साइंस नहीं है, लेकिन इसे सही बनाने में समय लगता है।

यदि यह एक मुख्य व्यवसाय कार्य है - इसे स्वयं करें, चाहे वह कोई भी हो।

बहुत अधिक दो प्रकार के नियंत्रण / विचार हैं:

  1. सामान्य, आप कई अलग अलग संदर्भों यहां तक कि उनके रचनाकारों, जैसे द्वारा के बारे में सोचा नहीं में उन्हें इस्तेमाल करने की इजाजत दी UICollectionViewसे UIKit
  2. विशिष्ट, एकल उपयोग-केस के लिए डिज़ाइन किया गया, जैसे UIPickerView। अधिकांश तृतीय-पक्ष पुस्तकालय दूसरी श्रेणी में आते हैं। क्या अधिक है, वे अक्सर एक मौजूदा कोडबेस से निकाले जाते हैं जिसके लिए उन्हें अनुकूलित किया गया था।

अज्ञात प्रारंभिक धारणाएँ

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

अक्सर विचार सीखना परिणामी कोड प्राप्त करने की तुलना में अधिक फायदेमंद होता है।

आप इसे छिपा नहीं सकते

UIKit को जिस तरह से डिज़ाइन किया गया है, उसकी वजह से आप संभवतः एक एडाप्टर के पीछे तीसरे पक्ष के यूआई लाइब्रेरी को छिपाने में सक्षम नहीं होंगे। एक पुस्तकालय आपके यूआई कोड को आपके प्रोजेक्ट के वास्तविक तथ्य के साथ जोड़ देगा।

भविष्य के समय की लागत

प्रत्येक iOS रिलीज़ के साथ UIKit बदलता है। चीजें टूटेंगी। आपकी तृतीय-पक्ष निर्भरता रखरखाव-मुक्त नहीं होगी जितनी आप अपेक्षा कर सकते हैं।

निष्कर्ष:

मेरे व्यक्तिगत अनुभव से, थर्ड-पार्टी यूआई कोड के अधिकांश उपयोग कुछ समय के लिए छोटे लचीलेपन का आदान-प्रदान करते हैं।

हम अपनी वर्तमान रिलीज़ को तेज़ी से शिप करने के लिए तैयार कोड का उपयोग करते हैं। जल्दी या बाद में, हालांकि, हम पुस्तकालय की सीमाओं को मारते हैं और एक कठिन निर्णय से पहले खड़े होते हैं: आगे क्या करना है?


0

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

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

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