मेरी रूबी ऑन रेल्स पैटर्न्स और एंटी-पैटर्न्स श्रृंखला के अंतिम भाग में आपका स्वागत है। इन सभी विषयों पर लिखना और शोध करना काफी यात्रा रही है। इस ब्लॉग पोस्ट में, हम उन सबसे आम समस्याओं पर जाएंगे जिनका सामना मुझे वर्षों से रूबी ऑन रेल्स एप्लिकेशन बनाने और शिपिंग करते समय करना पड़ा है।
यहां जिन विचारों पर मैं चर्चा करूंगा, वे कोड में लगभग हर जगह लागू होते हैं। इसलिए उन्हें सामान्य विचारों के रूप में मानें, न कि मॉडल-व्यू-कंट्रोलर पैटर्न से संबंधित कुछ। यदि आप रेल्स MVC से संबंधित पैटर्न और एंटी-पैटर्न में रुचि रखते हैं, तो आप मॉडल, व्यू और कंट्रोलर ब्लॉग पोस्ट देख सकते हैं।
तो आइए सामान्य समस्याओं और निष्कर्षों में कूदते हैं।
स्वार्थी ऑब्जेक्ट्स और डिमेटर का नियम
डिमेटर का नियम एक यूरिस्टिक है जिसे इसका नाम तब मिला जब लोगों के एक समूह ने डिमेटर प्रोजेक्ट पर काम किया। विचार यह है कि आपके ऑब्जेक्ट्स तब तक ठीक हैं जब तक वे एक समय में एक मेथड कॉल करते हैं और कई मेथड कॉल्स को चेन नहीं करते। व्यवहार में इसका अर्थ निम्नलिखित है:
# खराब song.label.address # अच्छा song.label_address
तो अब, song ऑब्जेक्ट को यह जानने की आवश्यकता नहीं है कि एड्रेस कहां से आता है — एड्रेस label ऑब्जेक्ट की जिम्मेदारी है। आपको केवल एक मेथड कॉल चेन करने के लिए प्रोत्साहित किया जाता है और अपने ऑब्जेक्ट्स को 'स्वार्थी' बनाएं ताकि वे अपनी पूरी जानकारी सीधे साझा न करें बल्कि हेल्पर मेथड्स के माध्यम से।
सौभाग्य से, रेल्स में, आपको प्रति से एक हेल्पर मेथड लिखने की आवश्यकता नहीं है — आप delegate हेल्पर का उपयोग कर सकते हैं:
def Label < ApplicationModel belongs_to :song delegate :address, to: :song end
आप डेलीगेट के डॉक्स में डेलीगेट द्वारा स्वीकार किए जाने वाले विकल्पों के साथ खेल सकते हैं। लेकिन विचार और निष्पादन बहुत सरल हैं। डिमेटर के नियम को लागू करके, आप संरचनात्मक कपलिंग को कम करते हैं। शक्तिशाली delegate के साथ, आप इसे कम लाइन्स में और बढ़िया विकल्पों के साथ करते हैं।
एक और विचार जो डिमेटर के नियम के बहुत समान है, वह है सिंगल-रिस्पॉन्सिबिलिटी सिद्धांत (या संक्षेप में SRP)। यह बताता है कि एक मॉड्यूल, क्लास, या फंक्शन सिस्टम के एक भाग के लिए जिम्मेदार होना चाहिए। या, दूसरे तरीके से प्रस्तुत:
उन चीजों को एक साथ इकट्ठा करें जो उन्हीं कारणों से बदलती हैं। उन चीजों को अलग करें जो अलग-अलग कारणों से बदलती हैं।
लोग अक्सर SRP की अलग समझ रखते हैं, लेकिन विचार अपने बिल्डिंग ब्लॉक्स को एक चीज़ के लिए जिम्मेदार रखना है। जैसे-जैसे आपका रेल्स ऐप विस्तारित होता है, SRP हासिल करना चुनौतीपूर्ण हो सकता है, लेकिन रीफैक्टरिंग करते समय इसके बारे में जागरूक रहें।
फीचर्स जोड़ते समय और LOC बढ़ाते समय, मैंने पाया है कि लोग अक्सर त्वरित समाधान के लिए पहुंचते हैं। तो आइए त्वरित सुधार हासिल करने के बारे में जानते हैं।
मैं एक आदमी को जानता हूं (क्या आपको उस रूबी जेम की आवश्यकता है?)
पुराने दिनों में जब रेल्स एक गर्म विषय था, ओपन-सोर्स सहयोग में उछाल आया था, हर कोने पर नए रूबी जेम्स उभर रहे थे (आजकल उभरती जावास्क्रिप्ट लाइब्रेरीज़ की तरह, लेकिन बहुत छोटे पैमाने पर):
👆 मॉड्यूल काउंट्स से जानकारी।
वैसे भी, एक सामान्य दृष्टिकोण आपकी समस्या को हल करने के लिए एक मौजूदा जेम ढूंढना था।
इसमें कुछ भी गलत नहीं है, लेकिन जेम इंस्टॉल करने का निर्णय लेने से पहले मैं कुछ सलाह के टुकड़े साझा करना चाहूंगा।
सबसे पहले, अपने आप से ये सवाल पूछें:
- आप जेम की सुविधाओं के किस हिस्से का उपयोग करने जा रहे हैं?
- क्या वहां कोई समान जेम है जो 'सरल' या अधिक अद्यतन है?
- क्या आप जिस सुविधा की आवश्यकता है उसे आसानी से और आत्मविश्वास के साथ लागू कर सकते हैं?
मूल्यांकन करें कि यदि आप जेम की सुविधाओं की पूरी श्रृंखला का उपयोग करने की योजना नहीं बनाते हैं तो इम्प्लीमेंटेशन करना उचित है या नहीं। या, यदि जेम का इम्प्लीमेंटेशन बहुत जटिल है और आपको लगता है कि आप इसे अधिक सरलता से कर सकते हैं, तो कस्टम समाधान का विकल्प चुनें।
एक और कारक जिस पर मैं विचार करता हूं वह है जेम के रिपॉजिटरी की गतिविधि — क्या कोई सक्रिय मेंटेनर्स हैं? आखिरी बार रिलीज़ कब हुई थी?
आपको जेम के डिपेंडेंसीज़ पर भी नज़र रखनी चाहिए। आप किसी विशिष्ट डिपेंडेंसी वर्जन में लॉक नहीं होना चाहते, इसलिए हमेशा Gemfile.spec फाइल चेक करें। जेम वर्जन निर्दिष्ट करने के रूबीजेम्स तरीके से परामर्श करें।
जबकि हम जेम्स के विषय पर हैं, एक संबंधित विचार है जिसका मैंने सामना किया है: 'नॉट इनवेंटेड हीयर' (या NIH) घटना जो रेल्स/रूबी दुनिया पर लागू होती है। आइए अगले सेक्शन में देखें कि यह क्या है।
नॉट इनवेंटेड हीयर (शायद आपको उस रूबी जेम की आवश्यकता है आखिरकार?)
मेरे करियर में कुछ घटनाओं में, मुझे लोगों (मुझ सहित) को 'नॉट इनवेंटेड हीयर' सिंड्रोम का शिकार होते देखने का मौका मिला। यह विचार 'पहिए का पुनः आविष्कार' के समान है। कभी-कभी, टीमें और संगठन उन लाइब्रेरीज़ (जेम्स) पर भरोसा नहीं करते जिन्हें वे नियंत्रित नहीं कर सकते। विश्वास की कमी उन्हें पहले से मौजूद जेम का पुनः आविष्कार करने के लिए प्रेरित कर सकती है।
कभी-कभी, NIH का अनुभव करना अच्छी बात हो सकती है। इन-हाउस समाधान बनाना बहुत अच्छा हो सकता है, खासकर यदि आप वहां मौजूद अन्य समाधानों पर सुधार करते हैं। यदि आप समाधान को ओपन-सोर्स करने का निर्णय लेते हैं, तो यह और भी बेहतर हो सकता है (रूबी ऑन रेल्स या रिएक्ट पर एक नज़र डालें)। लेकिन यदि आप केवल इसके लिए पहिए का पुनः आविष्कार करना चाहते हैं, तो ऐसा न करें। पहिया अपने आप में पहले से ही बहुत अच्छा है।
यह विषय काफी पेचीदा है, और यदि आप कभी ऐसी स्थिति में फंसते हैं, तो अपने आप से ये सवाल पूछें:
- क्या हम आश्वस्त हैं कि हम मौजूदा समाधानों से बेहतर समाधान बना सकते हैं?
- यदि मौजूदा ओपन-सोर्स समाधान हमारी आवश्यकता से भिन्न है, तो क्या हम ओपन-सोर्स योगदान देकर और इसे सुधार सकते हैं?
- इसके अलावा, क्या हम ओपन-सोर्स समाधान के मेंटेनर्स बन सकते हैं और संभवतः बहुत सारे डेवलपर्स के जीवन को सुधार सकते हैं?
लेकिन कभी-कभी, आपको बस अपना रास्ता खुद बनाना होता है और खुद एक लाइब्रेरी बनानी होती है। शायद आपका संगठन ओपन-सोर्स लाइब्रेरी को लाइसेंस देना पसंद नहीं करता, इसलिए आपको अपना खुद का बनाने के लिए मजबूर किया जाता है। लेकिन आप जो भी करें, मैं कहूंगा पहिए का पुनः आविष्कार करने से बचें।
लाइफगार्ड ऑन ड्यूटी (ओवर-रेस्क्यूइंग एक्सेप्शन्स)
लोग मूल रूप से लक्षित से अधिक एक्सेप्शन्स को रेस्क्यू करते हैं।
यह विषय पिछले वाले की तुलना में कोड से थोड़ा अधिक संबंधित है। यह कुछ के लिए सामान्य ज्ञान हो सकता है, लेकिन यह समय-समय पर कोड में देखा जा सकता है। उदाहरण के लिए:
begin song.upload_lyrics rescue puts 'Lyrics upload failed' end
यदि हम उस एक्सेप्शन को निर्दिष्ट नहीं करते जिसे हम रेस्क्यू करना चाहते हैं, तो हम कुछ ऐसे एक्सेप्शन्स को पकड़ लेंगे जिनकी हमने योजना नहीं बनाई थी।
इस मामले में, समस्या यह हो सकती है कि song ऑब्जेक्ट nil है। जब उस एक्सेप्शन को एरर ट्रैकर को रिपोर्ट किया जाता है, तो आप सोच सकते हैं कि अपलोड प्रक्रिया में कुछ गड़बड़ है, जबकि वास्तव में, आप कुछ पूरी तरह से अलग अनुभव कर रहे होंगे।
इसलिए, सुरक्षित रहने के लिए, एक्सेप्शन्स को रेस्क्यू करते समय, सुनिश्चित करें कि आपको उन सभी एक्सेप्शन्स की सूची मिल जाए जो हो सकते हैं। यदि आप किसी कारण से हर एक्सेप्शन प्राप्त नहीं कर सकते, तो ओवर-रेस्क्यू करने के बजाय अंडर-रेस्क्यू करना बेहतर है। उन एक्सेप्शन्स को रेस्क्यू करें जिन्हें आप जानते हैं और दूसरों को बाद के चरण में संभालें।
आप बहुत ज्यादा पूछते हैं (बहुत सारे SQL क्वेरीज़)
इस सेक्शन में, हम एक और वेब डेवलपमेंट, रिलेशनल-डेटाबेस समस्या से गुजरेंगे।
आप एक रिक्वेस्ट में बहुत सारे SQL क्वेरीज़ के साथ वेबसर्वर पर बमबारी करते हैं। यह समस्या कैसे उत्पन्न होती है? खैर, यह हो सकता है यदि आप एक रिक्वेस्ट में कई टेबल्स से कई रिकॉर्ड्स लाने का प्रयास करते हैं। लेकिन जो सबसे अक्सर होता है वह है कुख्यात N+1 क्वेरी समस्या।
निम्न मॉडल्स की कल्पना करें:
class Song < ApplicationRecord belongs_to :artist end class Artist < ApplicationRecord has_many :songs end
यदि हम एक जेनर में कुछ गाने और उनके कलाकार दिखाना चाहते हैं:
songs = Song.where(genre: genre).limit(10) songs.each do |song| puts "#{song.title} by #{song.artist.name}" end
यह कोड दस गाने प्राप्त करने के लिए एक SQL क्वेरी ट्रिगर करेगा। उसके बाद, प्रत्येक गाने के लिए कलाकार लाने के लिए एक अतिरिक्त SQL क्वेरी की जाएगी। वह ग्यारह (11) क्वेरीज़ कुल।
उस परिदृश्य की कल्पना करें यदि हम अधिक गाने लोड करते हैं — हम डेटाबेस को सभी कलाकारों को प्राप्त करने का प्रयास करने में भारी लोड डालेंगे।
वैकल्पिक रूप से, रेल्स से includes का उपयोग करें:
songs = Song.includes(:artists).where(genre: genre).limit(10) songs.each do |song| puts "#{song.title} by #{song.artist.name}" end
includes के बाद, हमें अब केवल दो SQL क्वेरीज़ मिलती हैं, चाहे हम कितने भी गाने दिखाने का फैसला करें। कितना साफ।
बहुत सारे SQL क्वेरीज़ का निदान करने का एक तरीका डेवलपमेंट में है। यदि आप एक ही टेबल से डेटा लाने वाले समान SQL क्वेरीज़ का एक समूह देखते हैं, तो वहां कुछ मछली जैसा चल रहा है। इसीलिए मैं आपको अपने डेवलपमेंट एनवायरनमेंट के लिए SQL लॉगिंग चालू करने के लिए दृढ़ता से प्रोत्साहित करता हूं। इसके अलावा, रेल्स वर्बोज़ क्वेरी लॉग्स का समर्थन करता है जो दिखाते हैं कि कोड में क्वेरी कहां से बुलाई गई है।
यदि लॉग्स देखना आपकी चीज़ नहीं है, या आप कुछ अधिक गंभीर चाहते हैं, तो AppSignal के प्रदर्शन माप और N+1 क्वेरी डिटेक्शन को आज़माएं। वहां, आपको एक उत्कृष्ट संकेतक मिलेगा कि क्या आपका मुद्दा N+1 क्वेरी से आता है। यहां यह कैसा दिखता है:
सारांश
इस ब्लॉग पोस्ट श्रृंखला को पढ़ने के लिए धन्यवाद। मुझे खुशी है कि आप इस दिलचस्प यात्रा में मेरे साथ शामिल हुए, जहां हम रेल्स में पैटर्न और एंटी-पैटर्न पेश करने से लेकर रेल्स MVC पैटर्न के अंदर वे क्या हैं, इसका पता लगाने तक गए, इससे पहले यह अंतिम ब्लॉग पोस्ट सामान्य समस्याओं पर।
मुझे उम्मीद है कि आपने बहुत कुछ सीखा, या कम से कम जो आप पहले से जानते थे उसे संशोधित और स्थापित किया। यह सब याद रखने के बारे में जोर न दें। यदि आप किसी भी क्षेत्र में परेशानी हो रही है तो आप हमेशा श्रृंखला से परामर्श कर सकते हैं।
आप निश्चित रूप से पैटर्न और एंटी-पैटर्न दोनों का सामना करेंगे क्योंकि यह दुनिया (और विशेष रूप से सॉफ्टवेयर इंजीनियरिंग) आदर्श नहीं है। इससे आपको चिंता भी नहीं होनी चाहिए।
पैटर्न और एंटी-पैटर्न में महारत हासिल करना आपको एक महान सॉफ्टवेयर इंजीनियर बना देगा। लेकिन जो आपको और भी बेहतर बनाता है वह यह जानना है कि उन पैटर्न और सांचों को कब तोड़ना है, क्योंकि कोई पूर्ण समाधान नहीं है।
फिर से जुड़ने और पढ़ने के लिए धन्यवाद। अगले में मिलते हैं — और चीयर्स!
P.S. यदि आप रूबी मैजिक पोस्ट को प्रेस से बाहर आते ही पढ़ना चाहते हैं, तो हमारे रूबी मैजिक न्यूज़लेटर की सदस्यता लें और कभी भी एक भी पोस्ट मिस न करें!