क्या जावा में टेम्पलेट "मेटाप्रोग्रामिंग" एक अच्छा विचार है?


29

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

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

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

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

क्या इस दृष्टिकोण के लाभ नुकसान से आगे निकल जाते हैं? क्या मुझे इसके बजाय:

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

PS परियोजना के ख़राब डिज़ाइन के कारण, फ़ंक्शन को रूपरेखा देना मुश्किल है ... हालाँकि, पूर्व अनुचर ने मुझे आश्वस्त किया है कि प्रदर्शन हिट अस्वीकार्य है। मैं यह मानता हूं कि वह 5% से अधिक है, हालांकि यह मेरी ओर से पूर्ण अनुमान है।


शायद मुझे थोड़ा विस्तार करना चाहिए। 12 प्रतियां एक समान कार्य करती हैं, लेकिन मिनट के अंतर हैं। मतभेद पूरे समारोह में विभिन्न स्थानों पर हैं, इसलिए दुर्भाग्य से कई, कई, सशर्त बयान हैं। प्रभावी रूप से ऑपरेशन के 6 "मोड" हैं, और ऑपरेशन के 2 "प्रतिमान" (स्वयं द्वारा बनाए गए शब्द)। फ़ंक्शन का उपयोग करने के लिए, कोई "मोड" और ऑपरेशन के "प्रतिमान" को निर्दिष्ट करता है। यह कभी गतिशील नहीं है; कोड का प्रत्येक टुकड़ा बिल्कुल एक मोड और प्रतिमान का उपयोग करता है। सभी 12 मोड-प्रतिमान जोड़े अनुप्रयोग में कहीं न कहीं उपयोग किए जाते हैं। कार्यों को उपयुक्त रूप से func1 को func12 कहा जाता है, यहां तक ​​कि संख्याओं के साथ दूसरे प्रतिमान और विषम संख्याओं को पहले प्रतिमान का प्रतिनिधित्व करते हैं।

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


यदि प्रदर्शन हिट फ़ंक्शन के 12 संस्करणों को वारंट करने के लिए गंभीर है, तो आप इसके साथ फंस सकते हैं। यदि आप किसी एकल फ़ंक्शन (या जेनरिक का उपयोग) के लिए रिफ्लेक्टर करते हैं, तो क्या प्रदर्शन हिट काफी खराब होगा जो आप ग्राहकों और व्यापार को खो देंगे?
फ्रस्ट्रेटेडविथफॉर्म्सडिजेनर

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

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

2
फ़ंक्शन का नाम func1 ... func12 पागल लगता है। कम से कम उन्हें मोड 1Par2 आदि ... या शायद myFuncM3P2 नाम दें।
user949300

2
"यदि वे प्रोग्राम-जनरेट की गई फ़ाइल के बजाय संशोधित करते हैं" ... फ़ाइल को केवल तब बनाते हैं जब " Makefile" या (जो भी सिस्टम आप उपयोग करते हैं) से बना रहे हैं और इसे सही तरीके से समाप्त संकलन हटा दें । इस तरह से उनके पास गलत स्रोत फ़ाइल को संशोधित करने का मौका नहीं है।
बाकुरि

जवाबों:


23

यह एक बहुत बुरी स्थिति है, आपको इस ASAP को फिर से बनाने की आवश्यकता है - यह सबसे खराब तकनीकी ऋण है - आपको यह भी नहीं पता है कि कोड वास्तव में कितना महत्वपूर्ण है - केवल अनुमान लगाएं कि यह महत्वपूर्ण है।

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

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

संपादित करें

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

सीधे शब्दों में कहें: यह नहीं है।

अपनी खुद की मिनी-भाषा बनाने, इसके लिए एक कोड-जनरेटर लिखने और इसे बनाए रखने का अतिरिक्त बोझ, भविष्य के रखरखाव के लिए इसे पढ़ाने का उल्लेख नहीं करना लंबे समय में नारकीय है। जब आप दीर्घकालिक समाधान पर काम कर रहे हों, तो उपरोक्त समस्या को हल करने का एक सुरक्षित तरीका ही अनुमति देता है । जो लेगा वह मेरे ऊपर है।


19
क्षमा करें, लेकिन मुझे असहमत होना पड़ेगा। उसके लिए यह निर्णय लेने के लिए आपको ओपी कोड के बारे में पर्याप्त जानकारी नहीं है। कोड-जनरेटिंग मुझे ऐसा लगता है जैसे इसमें मूल समाधान की तुलना में अधिक तकनीकी ऋण है।
रॉबर्ट हार्वे

6
रॉबर्ट की टिप्पणी को समाप्त नहीं किया जा सकता है। किसी भी समय आपके पास "एक फ़ाइल को संशोधित न करने के लिए समझाते हुए एक अस्वीकरण" होता है जो कि "तकनीकी ऋण" है जो एक अवैध बुकी उपनाम "शार्क" द्वारा संचालित चेक-कैशिंग स्टोर के बराबर है।
corsiKa

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

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

2
@corsiKa मैंने कभी नहीं कहा कि यह एक स्थायी समाधान है। यह मूल स्थिति के रूप में एक ऋण के रूप में ज्यादा होगा। केवल एक चीज जो करती है वह है अस्थिरता में कमी जब तक कि एक व्यवस्थित समाधान नहीं मिलता है। यदि आप जावा में इस तरह की समस्याओं को मार रहे हैं, तो आप पूरी तरह से एक नए प्लेटफॉर्म / फ्रेमवर्क / भाषा में जाने की संभावना को शामिल करेंगे - आप या तो बहुत जटिल या बेहद गलत कर रहे हैं।
22

16

क्या रखरखाव वास्तविक है, या क्या यह आपको परेशान करता है? यदि यह केवल आपको परेशान करता है, तो इसे अकेला छोड़ दें।

क्या प्रदर्शन समस्या वास्तविक है, या पिछले डेवलपर ने केवल यह सोचा था कि यह था? प्रदर्शन की समस्याएं, अधिक बार नहीं, वे नहीं हैं जहां उन्हें सोचा जाता है, यहां तक ​​कि जब एक प्रोफाइलर का उपयोग किया जाता है। (मैं इस तकनीक का उपयोग मज़बूती से उन्हें खोजने के लिए करता हूं।)

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


10

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

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


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

6

इस प्रणाली के लिए कुछ प्रकार के टेम्पलेट प्रीप्रोसेसर \ कोड पीढ़ी शामिल क्यों नहीं हैं? एक अतिरिक्त अतिरिक्त बिल्ड चरण जो बाकी कोड को संकलित करने से पहले अतिरिक्त जावा स्रोत फ़ाइलों को निष्पादित और उत्सर्जित करता है। यह कैसे wsdl और xsd फ़ाइलों से बंद वेब क्लाइंट सहित अक्सर काम करता है।

आपके पास निश्चित रूप से उस प्रीप्रोसेसर \ _ कोड जनरेटर का रखरखाव होगा, लेकिन चिंता करने के लिए आपके पास डुप्लिकेट कोर कोड रखरखाव नहीं होगा।

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

जावा जेनेरिक भाषा में प्रकार के क्षरण के कारण कोई प्रदर्शन लाभ नहीं देते हैं, इसके स्थान पर सरल कास्टिंग का उपयोग किया जाता है।

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


2

कोई भी संत जावा विधि 12 वेरिएंट के लिए लंबे समय तक नहीं हो सकती है ... और जेआईटीसी लंबी विधियों से नफरत करता है - यह बस उन्हें ठीक से अनुकूलित करने से इनकार करता है। मैंने एक विधि को दो छोटे लोगों में विभाजित करके दो का गति कारक देखा है। शायद यही रास्ता है।

OTOH की कई प्रतियाँ होने पर भी कुछ समझ में आ सकता है। जैसा कि उनमें से प्रत्येक को विभिन्न स्थानों में उपयोग किया जाता है, वे अलग-अलग मामलों के लिए अनुकूलित हो जाते हैं (जेआईटीसी उन्हें प्रोफाइल करता है और फिर दुर्लभ मामलों को एक असाधारण पथ पर रखता है।

मैं कहूंगा कि कोड बनाना कोई बड़ी बात नहीं है, यह मानते हुए कि एक अच्छा कारण है। ओवरहेड कम है, और ठीक से नामित फ़ाइलें तुरंत अपने स्रोत तक ले जाती हैं। कुछ समय पहले जैसा कि मैंने सोर्स कोड जनरेट किया था, मैंने // DO NOT EDITहर लाइन पर रखा ... मुझे लगता है कि यह पर्याप्त बचत है।


1

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

उनके पास यह सुनिश्चित करने के लिए बहुत सारे विशेष तरीके हैं कि वे सभी प्रकार के ऑपरेशनों के लिए प्रदर्शन को अधिकतम कर सकते हैं: अन्य शर्तें लागू होने पर शामिल हों, चुनें, एग्रीगेट आदि ...।

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


1

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


0

आप Scala भाषा का उपयोग करके विशेष विधियों की समस्या को हल कर सकते हैं।

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

लेकिन इसके अलावा, स्काला के पास सिंटैक्टिक मैक्रोज़ हैं, जो एक प्रकार-सुरक्षित तरीके से संकलन समय पर कोड के साथ बहुत सी चीजें करना संभव बनाता है।

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

इसके अलावा, स्काला कई अन्य तरीकों से कमाल है। और आपको Scala के लिए सभी कोड को फिर से लिखना नहीं है, क्योंकि Scala <-> Java इंटरऑपरेबिलिटी उत्कृष्ट है। परियोजना के निर्माण के लिए बस SBT (scala build tool) का उपयोग करना सुनिश्चित करें ।


-1

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


यह एक उत्तर की तुलना में एक टिप्पणी की तरह अधिक पढ़ता है
gnat

-2

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


1
ऐसा लगता है कि कुछ ही घंटे पहले पोस्ट किए गए एक उत्तर में समझाया और समझाया गया था
gnat

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