रेल पैटर्न और एंटी-पैटर्न श्रृंखला पर मेरी रूबी के अंतिम भाग में आपका स्वागत है। इन सभी विषयों पर लिखना और शोध करना काफी अच्छा रहा है। इस ब्लॉग पोस्ट में, हम उन सबसे आम समस्याओं के बारे में जानेंगे जिनका सामना मैंने वर्षों से रूबी ऑन रेल्स एप्लिकेशन के निर्माण और शिपिंग के दौरान किया है।
मैं यहां जिन विचारों से गुजरूंगा, वे कोड में लगभग कहीं भी लागू होते हैं। इसलिए उन्हें सामान्य विचार मानें, न कि मॉडल-व्यू-कंट्रोलर पैटर्न से संबंधित कुछ। यदि आप रेल एमवीसी से संबंधित पैटर्न और एंटी-पैटर्न में रुचि रखते हैं, तो आप मॉडल, व्यू और कंट्रोलर ब्लॉग पोस्ट देख सकते हैं।
तो चलिए सामान्य समस्याओं और टेकअवे में कूदते हैं।
स्वार्थी वस्तुएं और डिमेटर का नियम
डेमेटर का कानून एक अनुमानी है जिसे इसका नाम तब मिला जब लोगों के एक समूह ने डेमेटर प्रोजेक्ट पर काम किया। विचार यह है कि जब तक वे एक समय में एक विधि को कॉल करते हैं और कई विधि कॉलों को श्रृंखलाबद्ध नहीं करते हैं, तब तक आपकी वस्तुएं ठीक रहती हैं। व्यवहार में इसका अर्थ निम्नलिखित है:
# Bad
song.label.address
# Good
song.label_address
तो अब, song
ऑब्जेक्ट को अब यह जानने की ज़रूरत नहीं है कि पता कहाँ से आता है — पता label
. की ज़िम्मेदारी है वस्तु। आपको केवल एक विधि कॉल को श्रृंखलाबद्ध करने और अपनी वस्तुओं को 'स्वार्थी' बनाने के लिए प्रोत्साहित किया जाता है ताकि वे अपनी पूरी जानकारी सीधे साझा न करें बल्कि सहायक विधियों के माध्यम से साझा करें।
सौभाग्य से, रेल में, आपको एक सहायक विधि लिखने की ज़रूरत नहीं है — आप delegate
का उपयोग कर सकते हैं सहायक:
def Label < ApplicationModel
belongs_to :song
delegate :address, to: :song
end
आप आगे बढ़ सकते हैं और उन विकल्पों के साथ खेल सकते हैं जो प्रतिनिधि प्रतिनिधि के दस्तावेज़ों में स्वीकार करते हैं। लेकिन विचार और निष्पादन बहुत सरल हैं। Demeter के नियम को लागू करने से, आप स्ट्रक्चरल कपलिंग को कम करते हैं। साथ में शक्तिशाली delegate
, आप इसे कम पंक्तियों में करते हैं और इसमें बढ़िया विकल्प शामिल हैं।
एक और विचार जो डेमेटर के कानून के समान है, वह है एकल-जिम्मेदारी सिद्धांत (या संक्षेप में एसआरपी)। इसमें कहा गया है कि एक सिस्टम के एक हिस्से के लिए एक मॉड्यूल, क्लास या फंक्शन जिम्मेदार होना चाहिए। या, दूसरे तरीके से प्रस्तुत किया गया:
<ब्लॉकक्वॉट>उन चीजों को एक साथ इकट्ठा करें जो समान कारणों से बदलती हैं। उन चीजों को अलग करें जो अलग-अलग कारणों से बदलती हैं।
लोगों को अक्सर एसआरपी की एक अलग समझ हो सकती है, लेकिन विचार यह है कि अपने बिल्डिंग ब्लॉक्स को एक ही चीज़ के लिए ज़िम्मेदार रखें। एसआरपी हासिल करना चुनौतीपूर्ण हो सकता है क्योंकि आपके रेल ऐप का विस्तार होता है, लेकिन रिफैक्टरिंग करते समय इसके बारे में जागरूक रहें।
सुविधाओं को जोड़ने और एलओसी को बढ़ाने के दौरान, मैंने पाया है कि लोग अक्सर त्वरित समाधान के लिए पहुंचते हैं। तो चलिए जल्दी ठीक करते हैं।
मैं एक लड़के को जानता हूं (क्या आपको वह रूबी रत्न चाहिए?)
उस दिन वापस जब रेल एक गर्म विषय था, ओपन-सोर्स सहयोग में उछाल आया था, हर कोने पर नए रूबी रत्न पॉप अप हो रहे थे (जैसे आजकल सभी उभरते जावास्क्रिप्ट पुस्तकालयों के साथ, लेकिन बहुत छोटे पैमाने पर):
👆 मॉड्यूल गणना से जानकारी।
वैसे भी, आपकी समस्या को हल करने के लिए एक मौजूदा रत्न ढूंढना एक सामान्य तरीका था।
इसमें कुछ भी गलत नहीं है, लेकिन इससे पहले कि आप कोई रत्न स्थापित करने का निर्णय लें, मैं कुछ सलाह देना चाहूंगा।
सबसे पहले, खुद से ये सवाल पूछें:
- मणि की विशेषताओं का आप किस भाग का उपयोग करने जा रहे हैं?
- क्या कोई ऐसा ही रत्न है जो 'सरल' है या अधिक अप-टू-डेट है?
- क्या आप उस सुविधा को आसानी से लागू कर सकते हैं जिसकी आपको आवश्यकता है और विश्वास के साथ?
मूल्यांकन करें कि क्या यह कार्यान्वयन करने योग्य है यदि आप मणि सुविधाओं की पूरी श्रृंखला का उपयोग करने की योजना नहीं बनाते हैं। या, यदि रत्न का कार्यान्वयन बहुत जटिल है और आपको लगता है कि आप इसे और अधिक सरलता से कर सकते हैं, तो एक कस्टम समाधान चुनें।
एक अन्य कारक जिस पर मैं विचार करता हूं वह यह है कि मणि का भंडार कितना सक्रिय है - क्या कोई सक्रिय अनुरक्षक हैं? पिछली बार कब रिलीज़ हुई थी?
आपको मणि की निर्भरता के लिए भी देखना चाहिए। आप किसी निर्भरता के विशिष्ट संस्करण में बंद नहीं होना चाहते हैं, इसलिए हमेशा Gemfile.spec
जांचें फ़ाइल। मणि संस्करण निर्दिष्ट करने के लिए RubyGems तरीके से परामर्श करें।
जबकि हम रत्नों के विषय पर हैं, एक संबंधित विचार है जिसका मैंने सामना किया है:'यहां आविष्कार नहीं किया गया' (या एनआईएच) घटना जो रेल/रूबी दुनिया पर लागू होती है। आइए देखें कि अगले भाग में इसके बारे में क्या है।
यहां आविष्कार नहीं किया गया (शायद आपको उस रूबी रत्न की आवश्यकता है?)
मेरे करियर में कुछ घटनाओं में, मुझे लोगों (मुझे शामिल किया गया) को 'नॉट इन्वेंटेड हियर' सिंड्रोम का अनुभव करने का मौका मिला। यह विचार 'पहिया को फिर से खोजने' के समान है। कभी-कभी, टीम और संगठन उन पुस्तकालयों (रत्न) पर भरोसा नहीं करते हैं जिन्हें वे नियंत्रित नहीं कर सकते। विश्वास की कमी उनके लिए पहले से मौजूद रत्न को फिर से खोजने के लिए एक ट्रिगर हो सकती है।
कभी-कभी, एनआईएच का अनुभव करना अच्छी बात हो सकती है। इन-हाउस समाधान बनाना बहुत अच्छा हो सकता है, खासकर यदि आप इसे अन्य समाधानों में सुधारते हैं। यदि आप समाधान को ओपन-सोर्स करने का निर्णय लेते हैं, तो यह और भी बेहतर हो सकता है (रूबी ऑन रेल्स या रिएक्ट पर एक नज़र डालें)। लेकिन अगर आप इसके लिए पहिया को फिर से बनाना चाहते हैं, तो ऐसा न करें। पहिया पहले से ही बहुत बढ़िया है।
यह विषय काफी पेचीदा है, और यदि आप कभी भी ऐसी स्थिति में फंस जाते हैं, तो अपने आप से ये प्रश्न पूछें:
- क्या हमें विश्वास है कि हम मौजूदा समाधान से बेहतर समाधान कर सकते हैं?
- यदि मौजूदा ओपन-सोर्स समाधान हमारी आवश्यकता से भिन्न है, तो क्या हम एक ओपन-सोर्स योगदान कर सकते हैं और इसे सुधार सकते हैं?
- इसके अलावा, क्या हम ओपन-सोर्स समाधान के अनुरक्षक बन सकते हैं और संभवतः बहुत से डेवलपर्स के जीवन में सुधार कर सकते हैं?
लेकिन कभी-कभी, आपको बस अपने तरीके से जाना होगा और खुद एक पुस्तकालय बनाना होगा। हो सकता है कि आपका संगठन किसी ओपन-सोर्स लाइब्रेरी को लाइसेंस देना पसंद नहीं करता है, इसलिए आपको अपनी लाइब्रेरी बनाने के लिए मजबूर होना पड़ता है। लेकिन आप जो कुछ भी करें, मैं कहूंगा कि पहिया को फिर से बनाने से बचें।
ड्यूटी पर लाईफगार्ड (अति-बचाव अपवाद)
लोग मूल रूप से लक्ष्य की तुलना में अधिक अपवादों को बचाते हैं।
यह विषय पिछले वाले की तुलना में कोड से थोड़ा अधिक संबंधित है। यह कुछ के लिए सामान्य ज्ञान हो सकता है, लेकिन इसे समय-समय पर कोड में देखा जा सकता है। उदाहरण के लिए:
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 क्वेरी से आती है या नहीं। यह नीचे कैसा दिखता है:
सम अप
इस ब्लॉग पोस्ट श्रृंखला को पढ़ने के लिए धन्यवाद। मुझे खुशी है कि आप इस दिलचस्प सवारी के लिए मेरे साथ शामिल हुए, जहां हम रेल में पैटर्न और एंटी-पैटर्न पेश करने से लेकर रेल एमवीसी पैटर्न के अंदर क्या हैं, यह जानने के लिए, सामान्य समस्याओं पर इस अंतिम ब्लॉग पोस्ट से पहले।
मुझे आशा है कि आपने बहुत कुछ सीखा है, या कम से कम संशोधित किया है और जो आप पहले से जानते हैं उसे स्थापित किया है। यह सब याद रखने के बारे में तनाव न लें। यदि आपको किसी भी क्षेत्र में परेशानी हो रही है तो आप हमेशा श्रृंखला से परामर्श कर सकते हैं।
आप निश्चित रूप से पैटर्न और विरोधी पैटर्न दोनों का सामना करेंगे क्योंकि यह दुनिया (और विशेष रूप से सॉफ्टवेयर इंजीनियरिंग) आदर्श नहीं है। इससे आपको भी चिंता नहीं होनी चाहिए।
मास्टरिंग पैटर्न और एंटी-पैटर्न आपको एक बेहतरीन सॉफ्टवेयर इंजीनियर बना देंगे। लेकिन जो चीज आपको और भी बेहतर बनाती है वह यह जानना है कि कब उन पैटर्नों और सांचों को तोड़ना है, क्योंकि कोई सटीक समाधान नहीं है।
शामिल होने और पढ़ने के लिए फिर से धन्यवाद। अगले एक में मिलते हैं — और चीयर्स!
पी.एस. यदि आप रूबी मैजिक की पोस्ट प्रेस से छूटते ही पढ़ना चाहते हैं, तो हमारे रूबी मैजिक न्यूजलेटर की सदस्यता लें और एक भी पोस्ट मिस न करें!