Protobuf डिजाइन पैटर्न


19

मैं जावा आधारित सेवा के लिए Google प्रोटोकॉल बफ़र्स का मूल्यांकन कर रहा हूं (लेकिन भाषा अज्ञेय पैटर्न की अपेक्षा कर रहा हूं)। मेरे दो सवाल हैं:

पहला व्यापक सामान्य प्रश्न है:

हम लोगों को किस पैटर्न का उपयोग करते हुए देख रहे हैं? कहा कि वर्ग संगठन से संबंधित पैटर्न (जैसे, संदेश प्रति फ़ाइल, पैकेजिंग, और वितरण) और संदेश परिभाषा (उदाहरण के लिए, दोहराया क्षेत्रों बनाम दोहराया समझाया क्षेत्र *) आदि।

Google Protobuf सहायता पृष्ठों और सार्वजनिक ब्लॉगों पर इस तरह की बहुत कम जानकारी है जबकि XML जैसे स्थापित प्रोटोकॉल के लिए एक टन जानकारी है।

मेरे पास निम्नलिखित दो अलग-अलग पैटर्न पर विशिष्ट प्रश्न हैं:

  1. .Proto फ़ाइलों में संदेशों का प्रतिनिधित्व करें, उन्हें एक अलग जार के रूप में पैकेज करें, और इसे सेवा के उपभोक्ताओं को लक्षित करने के लिए शिप करें - जो मूल रूप से डिफ़ॉल्ट दृष्टिकोण है जो मुझे लगता है।

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

    public V toProtobufMessage() {
        V.Builder builder = V.newBuilder();
        for (Item item : getItemList()) {
            builder.addItem(item);
        }
        return builder.setAmountPayable(getAmountPayable()).
                       setShippingAddress(getShippingAddress()).
                       build();
    }
    
    public static T fromProtobufMessage(V message_) { 
        return new T(message_.getShippingAddress(), 
                     message_.getItemList(),
                     message_.getAmountPayable());
    }
    

एक फायदा जो मैं देख रहा हूं (2) वह यह है कि मैं अपने द्वारा शुरू की गई जटिलताओं को छिपा सकता हूं V.newBuilder().addField().build()और अपने रैपर में कुछ सार्थक तरीके जैसे isOpenForTrade()या isAddressInFreeDeliveryZone()आदि जोड़ सकता हूं। दूसरा लाभ जो मैं (2) के साथ देख रहा हूं वह यह है कि मेरे ग्राहक अपरिहार्य वस्तुओं (कुछ मैं रैपर क्लास में लागू कर सकते हैं) के साथ व्यवहार करते हैं।

एक नुकसान मैं (2) के साथ देखता हूं कि मुझे कोड की नकल करनी है और अपने आवरण वर्गों को .proto फ़ाइलों के साथ सिंक करना है।

क्या किसी के पास दो दृष्टिकोणों में से किसी पर बेहतर तकनीक या आगे की आलोचना है?


* एक दोहराया क्षेत्र encapsulating से मैं इस तरह के रूप में संदेश मतलब है:

message ItemList {
    repeated item = 1;
}

message CustomerInvoice {
    required ShippingAddress address = 1;
    required ItemList = 2;
    required double amountPayable = 3;
}

संदेशों के बजाय जैसे यह एक:

message CustomerInvoice {
    required ShippingAddress address = 1;
    repeated Item item = 2;
    required double amountPayable = 3;
}

मुझे बाद पसंद है लेकिन मैं इसके खिलाफ तर्क सुनकर खुश हूं।


मुझे नए टैग बनाने के लिए 12 और अंक चाहिए और मुझे लगता है कि इस पोस्ट के लिए protobuf एक टैग होना चाहिए।
अपूर्व खुरसिया

जवाबों:


13

जहां मैं काम करता हूं, वहां प्रोटोबॉफ के उपयोग को छिपाने के लिए निर्णय लिया गया था। हम .protoअनुप्रयोगों के बीच फ़ाइलों को वितरित नहीं करते हैं , बल्कि, कोई भी अनुप्रयोग जो एक प्रोटोबाफ़ इंटरफ़ेस को उजागर करता है, एक ग्राहक पुस्तकालय का निर्यात करता है जो उससे बात कर सकता है।

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

क्लाइंट एप्लिकेशन तब क्लाइंट लाइब्रेरी को आयात करते हैं, और वे भेजने के लिए किसी भी इंटरफेस के कार्यान्वयन प्रदान करते हैं। दरअसल, दोनों पक्ष बाद की बात करते हैं।

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

  • पार्टीइनविटेशन संदेश, .protoफ़ाइल में लिखा गया है
  • PartyInvitationMessage वर्ग, द्वारा उत्पन्न protoc
  • PartyInvitation इंटरफ़ेस, साझा लाइब्रेरी में परिभाषित किया गया है
  • ActualPartyInvitation, PartyInvitationक्लाइंट ऐप द्वारा परिभाषित एक ठोस कार्यान्वयन (वास्तव में यह नहीं कहा जाता है!)
  • StubPartyInvitation, PartyInvitationसाझा पुस्तकालय द्वारा परिभाषित का एक सरल कार्यान्वयन
  • PartyInvitationConverter, जो PartyInvitationPartyInvitationMessage, और ए PartyInvitationMessageको कन्वर्ट कर सकता हैStubPartyInvitation
  • RSVP संदेश, .protoफ़ाइल में लिखा गया है
  • RSVPMessage वर्ग, द्वारा उत्पन्न protoc
  • RSVP इंटरफ़ेस, साझा लाइब्रेरी में परिभाषित किया गया है
  • ActualRSVP, RSVPसर्वर ऐप द्वारा परिभाषित एक ठोस कार्यान्वयन (वास्तव में यह भी नहीं कहा जाता है!)
  • StubRSVP, RSVPसाझा पुस्तकालय द्वारा परिभाषित का एक सरल कार्यान्वयन
  • RSVPConverter, जो ए , और ए RSVPको कन्वर्ट कर सकता हैRSVPMessageRSVPMessageStubRSVP

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

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

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


एक बिंदु पर, मैंने मानक क्रमांकन के लिए अधिक या कम ड्रॉप-इन प्रतिस्थापन के रूप में JBoss सीरियल का उपयोग करने पर ध्यान दिया । यह काफी तेज था। हालांकि प्रोटोफ्यू जितना तेज नहीं है।
टॉम एंडरसन

जैकसन 2 का उपयोग करते हुए JSON क्रमांकन बहुत तेज है। GBP के बारे में मुझे जो बात से नफरत है, वह मुख्य इंटरफ़ेस कक्षाओं का अनावश्यक दोहराव है।
अपूर्व खुरसिया

0

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


2
यह एक स्पर्शज्या टिप्पणी की तरह अधिक पढ़ता है, देखें कि कैसे उत्तर देना है
gnat

1
अच्छी तरह से इसके: वहाँ कोई डोमेन नहीं हैं वर्ग के अंत में एक शब्द के सभी मुद्दे हैं (ओह मैं C ++ में अपनी सभी चीजों को विकसित कर रहा हूं लेकिन यह कोई मुद्दा नहीं होना चाहिए)
मार्को बेनकिक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.