OO Design in Rails: सामान कहां रखें


244

मैं वास्तव में रेल का आनंद ले रहा हूं (भले ही मैं आमतौर पर बेचैन हूं), और मैं रूबी को बहुत ऊ रहा हूं। फिर भी, विशाल ActiveRecord उपवर्ग और विशाल नियंत्रक बनाने की प्रवृत्ति काफी स्वाभाविक है (भले ही आप प्रति संसाधन एक नियंत्रक का उपयोग करते हैं)। यदि आप गहरी वस्तु दुनिया बनाने के लिए थे, तो आप कक्षाएं कहाँ डालेंगे (और मॉड्यूल, मुझे लगता है)? मैं विचारों के बारे में पूछ रहा हूं (स्वयं सहायकों में?), नियंत्रक और मॉडल।

लीब ठीक है, और मैंने इसे देव वातावरण में पुनः लोड करने के लिए कुछ समाधान ढूंढे हैं , लेकिन मैं यह जानना चाहता हूं कि क्या इस सामान को करने का कोई बेहतर तरीका है। मैं वास्तव में बहुत बड़ी कक्षाओं के बारे में चिंतित हूं। इसके अलावा, इंजन के बारे में क्या और वे कैसे फिट होते हैं?

जवाबों:


384

क्योंकि रेल MVC के संदर्भ में संरचना प्रदान करता है, यह केवल मॉडल, दृश्य और नियंत्रक कंटेनरों का उपयोग करके समाप्त होने के लिए स्वाभाविक है जो आपके लिए प्रदान किए जाते हैं। शुरुआती (और यहां तक ​​कि कुछ मध्यवर्ती प्रोग्रामर) के लिए विशिष्ट मुहावरा ऐप में सभी तर्क को मॉडल (डेटाबेस वर्ग), नियंत्रक या दृश्य में क्रैम करना है।

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

स्कीनी नियंत्रकों, वास्तव में, एक अच्छा विचार है, लेकिन कोरोलरी - मॉडल में सब कुछ डाल देना, वास्तव में सबसे अच्छी योजना नहीं है।

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

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

यह समाधान कुछ मामलों में अच्छी तरह से काम कर सकता है - अन्य मामलों में, आप अपने कोड में उन कक्षाओं का उपयोग करने के बारे में सोचना चाहते हैं जो मॉडल, विचार या नियंत्रक नहीं हैं।

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

आप अवधारणाओं है कि उन बक्से (हठ, अनुरोध / प्रतिक्रिया प्रबंधन) में बड़े करीने से फिट नहीं है है, तो आप शायद कैसे आप के बारे में सोचने के लिए चाहते हैं सवाल में विचार मॉडल। आप गैर-मॉडल कक्षाओं को ऐप / कक्षाओं में, या कहीं और स्टोर कर सकते हैं, और उस निर्देशिका को अपने लोड पथ पर जोड़कर कर सकते हैं:

config.load_paths << File.join(Rails.root, "app", "classes")

यदि आप यात्री या JRuby का उपयोग कर रहे हैं, तो आप संभवतः अपने पथ को उत्सुक लोड पथों में जोड़ना चाहते हैं:

config.eager_load_paths << File.join(Rails.root, "app", "classes")

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

अद्यतन: यह उत्तर रेल पर लागू होता है 2.x और उच्चतर।


डी 'ओह। गैर-मॉडल के लिए एक अलग निर्देशिका जोड़ना मेरे लिए नहीं हुआ था। मैं एक साफ-सुथरा महसूस कर सकता हूँ ...
माइक वुडहाउस

येसुदा, इसके लिए धन्यवाद। बहुत बढ़िया जवाब। ठीक वही है जो मैं उन ऐप्स में देख रहा हूं जो मुझे विरासत में मिले हैं (और जिन्हें मैं बनाता हूं): कंट्रोलर, मॉडल, व्यू में सब कुछ, और हेल्पर्स अपने आप कंट्रोलर और व्यूज के लिए मुहैया कराते हैं। फिर मिक्सिंस लिब से आते हैं, लेकिन वास्तविक ओओ मॉडलिंग करने का प्रयास कभी नहीं होता है। आप सही हैं, हालांकि: "एप्लिकेशन / कक्षाएं, या कहीं और।" बस यह जांचना चाहता था कि क्या कोई मानक उत्तर मुझे याद आ रहा है ...
Dan Rosenstark

33
अधिक हाल के संस्करणों के साथ, config.autoload_paths ऐप के अंतर्गत सभी निर्देशिकाओं में चूक करता है। इसलिए आपको ऊपर वर्णित अनुसार config.load_paths को बदलने की आवश्यकता नहीं है। हालांकि, मैं उत्सुक (लोड) (अभी तक) के बारे में निश्चित नहीं हूं और उस पर गौर करने की जरूरत है। क्या किसी को पहले से ही पता है?
श्याम हबारकदा

इंटरमीडिएट के लिए निष्क्रिय आक्रामक: पी
सेबस्टियन पैटन

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

62

अद्यतन : चिंता का उपयोग रेल 4 में नए डिफ़ॉल्ट के रूप में पुष्टि की गई है

यह वास्तव में मॉड्यूल की प्रकृति पर ही निर्भर करता है। मैं आमतौर पर एप्लिकेशन के भीतर / चिंता फ़ोल्डर में नियंत्रक / मॉडल एक्सटेंशन रखता हूं।

# concerns/authentication.rb
module Authentication
  ...
end    

# controllers/application_controller.rb
class ApplicationController
  include Authentication
end



# concerns/configurable.rb
module Configurable
  ...
end    

class Model 
  include Indexable
end 

# controllers/foo_controller.rb
class FooController < ApplicationController
  include Indexable
end

# controllers/bar_controller.rb
class BarController < ApplicationController
  include Indexable
end

/ lib सामान्य प्रयोजन पुस्तकालयों के लिए मेरी पसंदीदा पसंद है। मेरे पास हमेशा एक प्रोजेक्ट नेमस्पेस होता है, जहां मैं सभी एप्लिकेशन-विशिष्ट लाइब्रेरी रखता हूं।

/lib/myapp.rb
module MyApp
  VERSION = ...
end

/lib/myapp/CacheKey.rb
/lib/myapp/somecustomlib.rb

रूबी / रेल कोर एक्सटेंशन आमतौर पर कॉन्फ़िगरेशन इनिशियलाइज़र में होते हैं ताकि लाइब्रेरी केवल एक बार रेल बूस्टर पर लोड हो।

/config/initializer/config.rb
/config/initializer/core_ext/string.rb
/config/initializer/core_ext/array.rb

पुन: प्रयोज्य कोड के टुकड़े के लिए, मैं अक्सर (माइक्रो) प्लगइन्स बनाता हूं ताकि मैं उन्हें अन्य परियोजनाओं में फिर से उपयोग कर सकूं।

हेल्पर फाइलें आमतौर पर सहायक विधियों और कभी-कभी कक्षाओं में रखती हैं जब ऑब्जेक्ट का उपयोग सहायकों द्वारा किया जाता है (उदाहरण के लिए फॉर्म बिल्डर्स)।

यह वास्तव में सामान्य अवलोकन है। यदि आप अधिक अनुकूलित सुझाव प्राप्त करना चाहते हैं तो कृपया विशिष्ट उदाहरणों के बारे में अधिक जानकारी प्रदान करें। :)


विचित्र बात। मुझे यह आवश्यकता नहीं मिल सकती है। निर्भरता से बाहर कुछ के साथ काम करने के लिए यह निर्भरता RIDS_ROOT + "/ lib / my_module" है। यह निश्चित रूप से निष्पादित और शिकायत करता है यदि फ़ाइल नहीं मिली है, लेकिन यह इसे फिर से लोड नहीं करता है।
डैन रोसेनस्टार्क

रूबी की आवश्यकता केवल एक बार चीजों को लोड करती है। यदि आप बिना शर्त कुछ लोड करना चाहते हैं, तो लोड का उपयोग करें।
चक

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

आप आवश्यकता के बजाय requ_d निर्भरता का उपयोग क्यों करते हैं? यह भी ध्यान दें कि यदि आप नामकरण परंपराओं का पालन करते हैं, तो आपको आवश्यकता का उपयोग करने की आवश्यकता नहीं है। यदि आप MyModule को lib / my_module में बनाते हैं, तो आप MyModule को पिछली आवश्यकता के बिना लागू कर सकते हैं (भले ही आवश्यकता का उपयोग तेजी से और कभी-कभी अधिक पठनीय होना चाहिए)। यह भी ध्यान दें कि फ़ाइल / lib केवल बूटस्ट्रैप पर एक बार लोड होती हैं।
सिमोन कारलेटी

1
चिंताओं का प्रयोग संबंधित है
7

10

... विशाल ActiveRecord उपवर्ग और विशाल नियंत्रक बनाने की प्रवृत्ति काफी स्वाभाविक है ...

"विशाल" एक चिंताजनक शब्द है ... ;-)

आपके नियंत्रक कैसे विशाल हो रहे हैं? यह कुछ ऐसा है जिसे आपको देखना चाहिए: आदर्श रूप से, नियंत्रकों को पतला होना चाहिए। पतली हवा से एक नियम-अंगूठा उठाते हुए, मैं सुझाव देता हूं कि यदि आपके पास नियमित रूप से अधिक है, तो कहें कि प्रति नियंत्रक विधि (कार्रवाई) में कोड की 5 या 6 लाइनें हैं, तो आपके नियंत्रक शायद बहुत मोटे हैं। क्या दोहराव है जो एक सहायक कार्य या एक फिल्टर में स्थानांतरित हो सकता है? क्या व्यावसायिक तर्क है जिसे मॉडल में नीचे धकेला जा सकता है?

आपके मॉडल कैसे विशाल हो सकते हैं? क्या आपको प्रत्येक कक्षा में जिम्मेदारियों की संख्या को कम करने के तरीकों को देखना चाहिए? क्या कोई सामान्य व्यवहार है जिसे आप मिक्सी में निकाल सकते हैं? या कार्यक्षमता के क्षेत्र आप सहायक वर्गों को सौंप सकते हैं?

संपादित करें: थोड़ा विस्तार करने की कोशिश कर रहा है, उम्मीद है कि बहुत बुरी तरह से कुछ भी विकृत नहीं ...

सहायकों: में रहते हैं app/helpersऔर ज्यादातर विचारों को सरल बनाने के लिए उपयोग किया जाता है। वे या तो नियंत्रक-विशिष्ट (उस नियंत्रक के सभी विचारों के लिए भी उपलब्ध हैं) या आम तौर पर उपलब्ध ( module ApplicationHelperapplication_helper.rb में)।

फ़िल्टर: मान लें कि आपके पास कई क्रियाओं में कोड की एक ही पंक्ति है (बहुत बार, किसी वस्तु का उपयोग params[:id]या इसी तरह की पुनर्प्राप्ति )। उस दोहराव को पहले एक अलग तरीके से अमूर्त किया जा सकता है और फिर पूरी तरह से कक्षा की परिभाषा में एक फिल्टर घोषित करके क्रियाओं से बाहर किया जा सकता है, जैसे कि before_filter :get_objectएक्शनकंट्रोलर गाइड में सेक्शन 6 देखें। डिक्लेक्टिव प्रोग्रामिंग को अपना दोस्त बनने दें।

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

रेल मॉडल को ActiveRecord :: Base का उपवर्ग नहीं होना चाहिए। या इसे किसी अन्य तरीके से रखने के लिए, एक मॉडल को तालिका के अनुरूप होने की ज़रूरत नहीं है, या यहां तक ​​कि कुछ भी संग्रहीत से संबंधित नहीं है। इससे भी बेहतर, जब तक आप अपनी फ़ाइल app/modelsको रेल्स कन्वेंशन (कॉल #underscore के अनुसार क्लास के नाम पर कॉल करते हैं, यह पता लगाने के लिए कि रेल क्या देखेगा), रेल इसे बिना किसी requireआवश्यक होने के लिए पाएंगे ।


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

1

यहाँ "पतले नियंत्रक" दार्शनिक से उत्पन्न होने वाले वसा मॉडल को फिर से दर्शाने के बारे में एक उत्कृष्ट ब्लॉग पोस्ट है:

http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

मूल संदेश है "मोटी मॉडल से मिक्स एक्स्ट्रैक्ट्स न निकालें", इसके बजाय सेवा वर्गों का उपयोग करें, लेखक ऐसा करने के लिए 7 पैटर्न प्रदान करता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.