Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

रेल्स में फेसेड पैटर्न का उपयोग करके प्रदर्शन और रखरखाव को अनुकूलित करें

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

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

बिना किसी देरी के, आइए सीधे इसमें गोता लगाएं!

MVC पैटर्न के साथ समस्या

MVC (मॉडल-व्यू-कंट्रोलर) पैटर्न एक सॉफ़्टवेयर विकास पैटर्न है जो 1970 के दशक का है। यह सॉफ़्टवेयर इंटरफेस डिज़ाइन करने के लिए एक युद्ध-परीक्षित समाधान है, प्रोग्रामिंग चिंताओं को तीन मुख्य समूहों में अलग करता है जो एक अद्वितीय तरीके से एक दूसरे के साथ संवाद करते हैं।

2000 के दशक की शुरुआत में कई बड़े वेब फ्रेमवर्क MVC पैटर्न को उनकी नींव के रूप में उभरे। स्प्रिंग (जावा के लिए), जैंगो (पायथन के लिए) और रूबी ऑन रेल्स (रूबी के लिए), सभी इस परस्पर जुड़े तत्वों की त्रिमूर्ति के साथ उनके मूल में बने थे। इसके उपयोग न करने वाले सॉफ़्टवेयर से परिणामस्वरूप स्पेगेटी-कोड की तुलना में, MVC पैटर्न सॉफ़्टवेयर विकास और इंटरनेट दोनों के विकास में एक बड़ी उपलब्धि और मोड़ था।

संक्षेप में, मॉडल-व्यू-कंट्रोलर पैटर्न निम्नलिखित की अनुमति देता है: एक उपयोगकर्ता व्यू पर एक एक्शन करता है। व्यू कंट्रोलर को एक अनुरोध ट्रिगर करता है जो संभावित रूप से एक मॉडल बना/पढ़/अपडेट/डिलीट कर सकता है। मॉडल लेनदेन कंट्रोलर को वापस प्रतिक्रिया करता है, जो बदले में कुछ बदलाव प्रस्तुत करता है जो उपयोगकर्ता व्यू में परिलक्षित देखेगा।

इस प्रोग्रामिंग पैटर्न के बहुत सारे फायदे हैं। कुछ सूचीबद्ध करने के लिए:

  • यह चिंताओं को अलग करके कोड रखरखाव में सुधार करता है
  • यह अधिक टेस्टेबिलिटी की अनुमति देता है (मॉडल, व्यू और कंट्रोलर को अलगाव में टेस्ट किया जा सकता है)
  • यह SOLID के सिंगल रिस्पॉन्सिबिलिटी सिद्धांत को लागू करके अच्छी कोडिंग प्रथाओं को प्रोत्साहित करता है: "एक क्लास के पास बदलने का केवल एक कारण होना चाहिए।"

अपने समय के लिए एक अभूतपूर्व उपलब्धि, डेवलपर्स ने जल्द ही महसूस किया कि MVC पैटर्न कुछ हद तक सीमित भी था। वेरिएंट उभरने लगे, जैसे HMVC (हायरार्किकल मॉडल-व्यू-कंट्रोलर), MVA (मॉडल-व्यू-एडाप्टर), MVP (मॉडल-व्यू-प्रेजेंटर), MVVM (मॉडल-व्यू-व्यूमॉडल) और अन्य, जो सभी MVC पैटर्न की सीमाओं को संबोधित करना चाहते थे।

MVC पैटर्न द्वारा पेश की गई समस्याओं में से एक, और आज के लेख का विषय, निम्नलिखित है: जटिल व्यू तर्क को संभालने के लिए कौन जिम्मेदार है? व्यू को केवल डेटा प्रस्तुत करने से संबंधित होना चाहिए, कंट्रोलर केवल मॉडल से प्राप्त संदेश को रिले कर रहा है, और मॉडल को किसी भी व्यू तर्क से संबंधित नहीं होना चाहिए।

इस आम दुविधा से निपटने में मदद के लिए, सभी रेल्स एप्लिकेशन को helpers डायरेक्टरी के साथ इनिशियलाइज़ किया जाता है। helper डायरेक्टरी में मॉड्यूल्स हो सकते हैं जिनमें मेथड्स होते हैं जो जटिल व्यू तर्क में सहायता करते हैं।

यहां रेल्स एप्लिकेशन के भीतर एक हेल्पर का उदाहरण है:

app/helpers/application_helper.rb

module ApplicationHelper def display_ad_type(advertisement) type = advertisement.ad_type case type when 'foo' content_tag(:span, class: "foo ad-#{type}") { type } when 'bar' content_tag(:p, 'bar advertisement') else content_tag(:span, class: "badge ads-badge badge-pill ad-#{type}") { type } end end end

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

हेल्पर्स अच्छे हैं, लेकिन जटिल व्यू तर्क को संभालने के लिए एक और पैटर्न है जो वर्षों से स्वीकार किया गया है, और वह है फेसेड पैटर्न।

फेसेड पैटर्न का परिचय

रूबी ऑन रेल्स एप्लिकेशन में, फेसेड आमतौर पर app/facades डायरेक्टरी के भीतर रखे जाते हैं।

helpers के समान होते हुए भी, facades एक मॉड्यूल के भीतर मेथड्स का समूह नहीं हैं। एक फेसेड एक PORO (प्लेन ओल्ड रूबी ऑब्जेक्ट) है जिसे कंट्रोलर के भीतर इंस्टेंटिएट किया जाता है, लेकिन वह विस्तृत व्यू व्यावसायिक तर्क को संभालता है। जैसे, यह निम्नलिखित लाभों की अनुमति देता है:

  1. UsersHelper या ArticlesHelper या BooksHelper के लिए एक सिंगल मॉड्यूल होने के बजाय, प्रत्येक कंट्रोलर एक्शन का अपना फेसेड हो सकता है: Users::IndexFacade, Articles::ShowFacade, Books::EditFacade।
  2. मॉड्यूल्स की तुलना में अधिक, फेसेड अच्छी कोडिंग प्रथाओं को प्रोत्साहित करते हैं क्योंकि वे आपको फेसेड को नेस्ट करने की अनुमति देते हैं ताकि सिंगल रिस्पॉन्सिबिलिटी सिद्धांत लागू हो। जबकि आप शायद सैकड़ों स्तरों तक नेस्टेड फेसेड नहीं चाहते, बेहतर रखरखाव और टेस्ट कवरेज के लिए एक या दो लेयर की नेस्टिंग अच्छी बात हो सकती है।

यहां एक विरोधाभासी उदाहरण है:

module Books class IndexFacade attr_reader :books, :params, :user def initialize(user:, params:) @params = params @user = user @books = user.books end def filtered_books @filtered_books ||= begin scope = if query.present? books.where('name ILIKE ?', "%#{query}%") elsif isbn.present? books.where(isbn: isbn) else books end scope.order(created_at: :desc).page(params[:page]) end end def recommended # हमारे पास यहां एक नेस्टेड फेसेड है। # व्यू के `Recommended Books` भाग की # एकल जिम्मेदारी है इसलिए इसे निकालना # इसके एनकैप्सुलेशन और टेस्टेबिलिटी को बेहतर बनाने के लिए सर्वोत्तम है। @recommended ||= Books::RecommendedFacade.new( books: books, user: user ) end private def query @query ||= params[:query] end def isbn @isbn ||= params[:isbn] end end end

फेसेड पैटर्न का उपयोग कब न करें

आइए एक पल के लिए यह भी प्रतिबिंबित करें कि फेसेड क्या नहीं हैं।

  • फेसेड को उन क्लासेस में नहीं रखा जाना चाहिए जो उदाहरण के लिए lib डायरेक्टरी में रहती हैं, कोड के लिए जिसे व्यू में प्रदर्शित करने की आवश्यकता है। फेसेड का जीवनचक्र कंट्रोलर एक्शन में उत्पन्न होना चाहिए और इसके संबंधित व्यू में उपयोग किया जाना चाहिए।

  • फेसेड CRUD एक्शन करने के लिए व्यावसायिक तर्क के लिए नहीं हैं (उसके लिए अन्य पैटर्न हैं, जैसे सर्विसेज या इंटरएक्टर्स—लेकिन यह किसी अन्य दिन का विषय है।) दूसरे शब्दों में, फेसेड बनाने, अपडेट करने या हटाने से संबंधित नहीं होने चाहिए। उनका उद्देश्य व्यू या कंट्रोलर से जटिल प्रस्तुति तर्क को निकालना और उस सभी जानकारी तक पहुंचने के लिए एकल इंटरफेस प्रदान करना है।

  • अंतिम लेकिन कम नहीं, फेसेड सिल्वर बुलेट नहीं हैं। वे आपको MVC पैटर्न को बायपास करने की अनुमति नहीं देते, बल्कि वे इसके साथ खेलते हैं। यदि मॉडल में परिवर्तन होता है, तो यह तुरंत व्यू में परिलक्षित नहीं होगा। MVC के साथ हमेशा की तरह, फेसेड को व्यू पर परिवर्तन प्रदर्शित करने के लिए कंट्रोलर एक्शन को पुनः प्रस्तुत करना होगा।

कंट्रोलर लाभ

फेसेड के मुख्य, स्पष्ट लाभों में से एक यह है कि वे आपको कंट्रोलर तर्क को नाटकीय रूप से कम करने की अनुमति देंगे।

आपका कंट्रोलर कोड इससे:

class BooksController < ApplicationController def index @books = if params[:query].present? current_user.books.where('name ILIKE ?', "%#{params[:query]}%") elsif params[:isbn].present? current_user.books.where(isbn: params[:isbn]) else current_user.books end @books.order(created_at: :desc).page(params[:page]) @recommended = @books.where(some_complex_query: true) end end

इसमें कम हो जाएगा:

class BooksController < ApplicationController def index @index_facade = Books::IndexFacade.new(user: current_user, params: params) end end

व्यू लाभ

व्यूज़ के लिए, फेसेड का उपयोग करते समय दो मुख्य लाभ हैं:

  1. सशर्त जांच, इंलाइन क्वेरी और अन्य तर्क को टेम्पलेट से बड़े करीने से निकाला जा सकता है जिससे कोड कहीं अधिक पठनीय हो जाता है। उदाहरण के लिए, आप इसे फॉर्म में उपयोग कर सकते हैं:
<%= f.label :location %> <%= f.select :location, options_for_select(User::LOCATION_TYPES.map { |type| [type.underscore.humanize, type] }.sort.prepend(['All', 'all'])), multiple: (current_user.active_ips.size > 1 && current_user.settings.use_multiple_locations?) %>

बस बन सकता है:

<%= f.label :location %> <%= f.select :location, options_for_select(@form_facade.user_locations), multiple: @form_facade.multiple_locations? %>
  1. वेरिएबल्स जिन्हें कई बार कॉल किया जाता है, उन्हें कैश किया जा सकता है। यह आपके ऐप के लिए महत्वपूर्ण प्रदर्शन सुधार प्रदान कर सकता है और pesky N+1 क्वेरीज़ को हटाने में मदद कर सकता है:
// व्यू में कहीं, एक क्वेरी की जाती है। <% current_user.books.where(isbn: params[:isbn]).each do |book| %> // चीजें करें <% end %> // व्यू में कहीं और, वही क्वेरी फिर से की जाती है। <% current_user.books.where(isbn: params[:isbn]).each do |book| %> // चीजें करें <% end %>

बन जाएगा:

// व्यू में कहीं, एक क्वेरी की जाती है। <% @index_facade.filtered_books.each do |book| %> // चीजें करें <% end %> // व्यू में कहीं और। // इंस्टेंस वेरिएबल कैशिंग के कारण दूसरी क्वेरी नहीं की जाती। <% @index_facade.filtered_books.each do |book| %> // चीजें करें <% end %>

टेस्टिंग लाभ

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

चूंकि आप सिंगल POROs का टेस्ट करेंगे, यह एक तेज़ टेस्ट सूट बनाए रखने में मदद करेगा।

यहां प्रदर्शन उद्देश्यों के लिए Minitest में लिखे गए एक टेस्ट का सरल उदाहरण है:

require 'test_helper' module Books class IndexFacadeTest < ActiveSupport::TestCase attr_reader :user, :params setup do @user = User.create(first_name: 'Bob', last_name: 'Dylan') @params = {} end test "#filtered_books returns all user's books when params are empty" index_facade = Books::IndexFacade.new(user: user, params: params) expectation = user.books.order(created_at: :desc).page(params[:page]) # पूरे कंट्रोलर टेस्ट या # इंटीग्रेशन टेस्ट लिखे बिना, हम जांच सकते हैं कि क्या फेसेड का उपयोग करके # खाली पैरामीटर्स के साथ उपयोगकर्ता को सही परिणाम लौटाए जाएंगे। assert_equal expectation, index_facade.filtered_books end test "#filtered_books returns books matching a query" @params = { query: 'Lord of the Rings' } index_facade = Books::IndexFacade.new(user: user, params: params) expectation = user .books .where('name ILIKE ?', "%#{params[:query]}%") .order(created_at: :desc) .page(params[:page]) assert_equal expectation, index_facade.filtered_books end end end

यूनिट टेस्टिंग फेसेड टेस्ट सूट प्रदर्शन में काफी सुधार करता है, और हर बड़ी कंपनी अंततः धीमे टेस्ट सूट का सामना करेगी जब तक कि ऐसी समस्याओं को कुछ स्तर की गंभीरता के साथ संबोधित नहीं किया जाता।

एक फेसेड, दो फेसेड, तीन फेसेड, अधिक?

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

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

यहां कुछ सामान्य प्रश्न हैं जो आप विकास के दौरान खुद से पूछ सकते हैं:

  • क्या फेसेड उस तर्क को एनकैप्सुलेट करता है जिसे मैं व्यू पर प्रस्तुत करने की कोशिश कर रहा हूं?
  • क्या फेसेड के भीतर मेथड इस संदर्भ में मायने रखता है?
  • क्या कोड अब पालन करना आसान है, या कठिन?

संदेह में, हमेशा अपने कोड को यथासंभव आसान बनाने का प्रयास करें।

निष्कर्ष

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

हालांकि, किसी भी प्रोग्रामिंग प्रतिमान की तरह, कोई सिल्वर बुलेट नहीं है। यहां तक कि हाल के वर्षों में उभरे पैटर्न की भीड़ (HMVC, MVVM, आदि.) सॉफ़्टवेयर विकास की जटिलताओं के लिए बी-ऑल-एंड-ऑल समाधान नहीं हैं।

थर्मोडायनामिक्स के दूसरे नियम के समान, जो बताता है कि एक बंद सिस्टम में एन्ट्रॉपी की स्थिति हमेशा बढ़ेगी, वैसे ही किसी भी सॉफ़्टवेयर प्रोजेक्ट में जटिलता समय के साथ बढ़ती और विकसित होती है। लंबे समय में, लक्ष्य ऐसा कोड लिखना है जो पढ़ने, टेस्ट करने, बनाए रखने और पालन करने में यथासंभव आसान हो; फेसेड ठीक यही प्रदान करते हैं।

P.S. यदि आप रूबी मैजिक पोस्ट को प्रेस से निकलते ही पढ़ना चाहते हैं, तो हमारे रूबी मैजिक न्यूज़लेटर की सदस्यता लें और कभी भी एक भी पोस्ट मिस न करें!


  1. गेमिंग और परफॉर्मेंस के लिए विंडोज 10 को ऑप्टिमाइज़ कैसे करें गेमिंग और परफॉर्मेंस के लिए विंडोज 10 को ऑप्टिमाइज़ कैसे करें

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

  1. कीमत और प्रदर्शन के लिए सर्वश्रेष्ठ Chromebox मिनी PC कीमत और प्रदर्शन के लिए सर्वश्रेष्ठ Chromebox मिनी PC

    डेस्कटॉप के लिए Google का हल्का Chrome OS एक बड़े PC की आवश्यकता नहीं है। मिनी PC पर लोड किया गया जिन्हें आप अपने मॉनिटर के पीछे माउंट कर सकते हैं, ये सस्ते Chromebox उत्कृष्ट खरीद हैं। आपको पता होना चाहिए कि जैसे-जैसे ये डेस्कटॉप PC छोटे होते जाते हैं, वैसे-वैसे उनकी क्षमता भी कम होती जाती है। लेकि

  1. पैरेलल्स डेस्कटॉप 17 मैक के लिए: नया रिलीज़ तेज़ प्रदर्शन और विंडोज 11 संगतता प्रदान करता है पैरेलल्स डेस्कटॉप 17 मैक के लिए: नया रिलीज़ तेज़ प्रदर्शन और विंडोज 11 संगतता प्रदान करता है

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