एक सर्विस ऑब्जेक्ट एक रूबी ऑब्जेक्ट है जो एक एकल क्रिया करता है। यह आपके डोमेन या बिजनेस लॉजिक में एक प्रक्रिया को एनकैप्सुलेट करता है। कल्पना करें कि आपको एक काल्पनिक लाइब्रेरी एप्लिकेशन में एक बुक इंस्टेंस बनाने की आवश्यकता है; एक साधारण Rails ऐप में, आप निम्नलिखित करेंगे:
class BookController < ApplicationController def create Book.new(*args) end end यह सरल चीजों के लिए ठीक है। हालांकि, जैसे-जैसे ऐप बढ़ता है, आप इसके आसपास बहुत सारे बॉयलरप्लेट के साथ समाप्त हो सकते हैं:
class BookController < ApplicationController def create default_args = { genre: find_genre(), author: find_author() } Book.new(attrs.merge(default_args)) end private def find_genre // ... end def find_author // ... end end सर्विस ऑब्जेक्ट्स आपको इस व्यवहार को एक अलग क्लास में एब्स्ट्रैक्ट करने की अनुमति देते हैं। फिर, आपका कोड फिर से सरल हो जाता है:
class BookController < ApplicationController def BookCreator.create_book end end आपको सर्विस ऑब्जेक्ट्स की आवश्यकता क्यों है
Rails को मूल रूप से MVC (जैसे, मॉडल्स, कंट्रोलर्स, व्यूज़, और हेल्पर्स) संगठनात्मक संरचना का समर्थन करने के लिए डिज़ाइन किया गया है। यह संरचना सरल एप्लिकेशन्स के लिए पर्याप्त है। हालांकि, जैसे-जैसे आपका एप्लिकेशन बढ़ता है, आप मॉडल्स और कंट्रोलर में बिखरे हुए डोमेन/बिजनेस लॉजिक को देखना शुरू कर सकते हैं। ऐसे लॉजिक्स न तो कंट्रोलर से संबंधित हैं और न ही मॉडल से, इसलिए वे कोड को पुन: उपयोग और रखरखाव करना मुश्किल बना देते हैं। एक Rails सर्विस ऑब्जेक्ट एक पैटर्न है जो आपको बिजनेस लॉजिक को कंट्रोलर्स और मॉडल्स से अलग करने में मदद कर सकता है, जिससे मॉडल्स केवल डेटा लेयर बन जाते हैं और कंट्रोलर आपके API का एंट्री पॉइंट बन जाता है।
जब हम बिजनेस लॉजिक को एनकैप्सुलेट करने के लिए सर्विसेज पेश करते हैं, तो हमें बहुत सारे लाभ मिलते हैं, जिनमें निम्नलिखित शामिल हैं:
लीन Rails कंट्रोलर - कंट्रोलर केवल अनुरोधों को समझने और रिक्वेस्ट पैरामीटर्स, सेशन्स, और कुकीज़ को आर्गुमेंट्स में बदलने के लिए जिम्मेदार है जिन्हें सर्विस ऑब्जेक्ट को कार्य करने के लिए पास किया जाता है। कंट्रोलर फिर सर्विस प्रतिक्रिया के अनुसार रीडायरेक्ट या रेंडर करता है। यहां तक कि बड़े एप्लिकेशन्स में, सर्विस ऑब्जेक्ट्स का उपयोग करने वाले कंट्रोलर एक्शन्स आमतौर पर 10 लाइनों से अधिक कोड के नहीं होते हैं।
टेस्टेबल कंट्रोलर्स - चूंकि कंट्रोलर्स लीन हैं और सर्विस के सहयोगी के रूप में काम करते हैं, टेस्ट करना वास्तव में आसान हो जाता है, क्योंकि हम केवल यह जांच सकते हैं कि जब कोई विशेष एक्शन होता है तो कंट्रोलर के भीतर कुछ मेथड्स कॉल किए जाते हैं।
बिजनेस प्रोसेस को आइसोलेशन में टेस्ट करने की क्षमता - सर्विसेज टेस्ट करना आसान और तेज़ है क्योंकि वे छोटे रूबी ऑब्जेक्ट्स हैं जिन्हें उनके एनवायरनमेंट से अलग किया गया है। हम आसानी से सभी सहयोगियों को स्टब कर सकते हैं और केवल यह जांच सकते हैं कि हमारे सर्विस के भीतर कुछ चरण किए जाते हैं।
पुन: उपयोग योग्य सर्विसेज - सर्विस ऑब्जेक्ट्स को कंट्रोलर्स, अन्य सर्विस ऑब्जेक्ट्स, कतारबद्ध जॉब्स आदि द्वारा कॉल किया जा सकता है।
फ्रेमवर्क और बिजनेस डोमेन के बीच अलगाव - Rails कंट्रोलर्स केवल सर्विसेज देखते हैं और उनका उपयोग करके डोमेन ऑब्जेक्ट के साथ इंटरैक्ट करते हैं। कपलिंग में यह कमी स्केलेबिलिटी को आसान बनाती है, खासकर जब आप मोनोलिथ से माइक्रोसर्विस में जाना चाहते हैं। आपकी सर्विसेज को न्यूनतम संशोधन के साथ आसानी से निकाला जा सकता है और एक नई सर्विस में ले जाया जा सकता है।
सर्विस ऑब्जेक्ट बनाना
पहले, आइए एक काल्पनिक लाइब्रेरी प्रबंधन एप्लिकेशन के लिए app/services नामक एक नए फोल्डर में एक नया BookCreator बनाएं:
$ mkdir app/services && touch app/services/book_creator.rb अगला, आइए अपने सभी लॉजिक को एक नई रूबी क्लास में डालें:
# app/services/book_creator.rb class BookCreator def initialize(title:, description:, author_id:, genre_id:) @title = title @description = description @author_id = author_id @genre_id = genre_id end def create_book Boook.create!( title: @title description: @description author_id: @author_id genre_id: @genre_id ) rescue ActiveRecord::RecordNotUnique => e # डुप्लिकेट एंट्री हैंडल करें end end end फिर, हम सर्विस ऑब्जेक्ट को कंट्रोलर में या एप्लिकेशन में कहीं भी कॉल कर सकते हैं:
class BookController < ApplicationController def create BookCreator.new(title: params[:title], description: params[:description], author_id: params[:author_id], genre_id: params[:genre_id]).create_book end end सर्विस ऑब्जेक्ट सिंटैक्टिक शुगर
हम BookCreator.new(arguments).create चेन को एक क्लास मेथड जोड़कर सरल बना सकते हैं जो BookCreator को इंस्टेंटिएट करता है और हमारे लिए create मेथड को कॉल करता है:
# app/services/book_creator.rb class BookCreator def initialize(title:, description:, author_id:, genre_id:) @title = title @description = description @author_id = author_id @genre_id = genre_id end def call(*args) new(*args).create_book end private def create_book Boook.create!( title: @title description: @description author_id: @author_id genre_id: @genre_id ) rescue ActiveRecord::RecordNotUnique => e # डुप्लिकेट एंट्री हैंडल करें end end end कंट्रोलर में, बुक क्रिएटर को अब इस प्रकार कॉल किया जा सकता है:
class BookController < ApplicationController def create BookCreator.call( title: params[:title], description: params[:description], author_id: params[:author_id], genre_id: params[:genre_id]) end end अपने कोड को DRY (Don't Repeat Yourself) रखने और अन्य सर्विस ऑब्जेक्ट्स के साथ इस व्यवहार का पुन: उपयोग करने के लिए, हम call मेथड को एक बेस ApplicationService क्लास में एब्स्ट्रैक्ट कर सकते हैं जिसे हर सर्विस ऑब्जेक्ट इनहेरिट करेगा:
class ApplicationService self.call(*args) new(*args).call end end इस कोड के साथ, हम BookCreator को ApplicationService से इनहेरिट करने के लिए रीफैक्टर कर सकते हैं:
# app/services/book_creator.rb class BookCreator < ApplicationService def initialize(title:, description:, author_id:, genre_id:) @title = title @description = description @author_id = author_id @genre_id = genre_id end def call create_book end private def create_book # ... end end BusinessProcess जेम का उपयोग करके सर्विस ऑब्जेक्ट्स बनाना
BusinessProcess जेम के साथ, आपको बेस एप्लिकेशन सर्विस क्लास बनाने या initialize मेथड डिफाइन करने की आवश्यकता नहीं है क्योंकि जेम में ये सभी कॉन्फ़िगरेशन बिल्ट-इन हैं। आपके सर्विस ऑब्जेक्ट को बस BusinessProcess::Base से इनहेरिट करना होगा।
अपने जेमफाइल में निम्नलिखित जोड़ें:
gem 'business_process' और फिर अपने टर्मिनल में bundle कमांड चलाएं
class BookCreator < BusinessProcess::Base # आवश्यकताएं निर्दिष्ट करें needs :title needs :description needs :author_id needs :genre_id # प्रक्रिया (एक्शन) निर्दिष्ट करें def call create_book end private def create_book # ... end end अच्छे सर्विस ऑब्जेक्ट्स बनाने के लिए दिशानिर्देश
एक पब्लिक मेथड
एक सर्विस ऑब्जेक्ट को एक बिजनेस एक्शन करना चाहिए और उसे अच्छी तरह से करना चाहिए, इसलिए उसे उस काम को करने के लिए केवल एक पब्लिक मेथड उजागर करना चाहिए। अन्य मेथड्स प्राइवेट होने चाहिए और पब्लिक मेथड द्वारा कॉल किए जाने चाहिए। आप पब्लिक मेथड को जो चाहें नाम दे सकते हैं, जब तक नामकरण सभी सर्विस ऑब्जेक्ट्स में सुसंगत है। हमारे उदाहरण में, हमने इसे call नाम दिया है। अन्य पारंपरिक नाम perform और execute हैं।
सर्विस ऑब्जेक्ट्स का नाम उनकी भूमिका के अनुसार रखें
सर्विस ऑब्जेक्ट का नाम यह इंगित करना चाहिए कि वह क्या करता है। सर्विस ऑब्जेक्ट्स को "or" और "er" से समाप्त होने वाले शब्दों से नाम देने का एक लोकप्रिय तरीका है। उदाहरण के लिए, यदि सर्विस ऑब्जेक्ट का काम बुक बनाना है, तो इसे BookCreator नाम दें, और यदि काम बुक पढ़ना है, तो इसे BookReader नाम दें।
सर्विस ऑब्जेक्ट्स को सीधे इंस्टेंटिएट न करें
सर्विस ऑब्जेक्ट्स को कॉल करने के नोटेशन को छोटा करने के लिए सिंटैक्टिक शुगर पैटर्न या BusinessProcess जैसे जेम्स जैसे एब्स्ट्रैक्शन का उपयोग करें। इस दृष्टिकोण का उपयोग करके आप BookCreator.new(*args).call या BookCreator.new.call(*args) को BookCreator.call(*args) में सरल बना सकते हैं, जो छोटा और अधिक पठनीय है।
सर्विस ऑब्जेक्ट्स को नेमस्पेसेस में समूहित करें
सर्विस ऑब्जेक्ट्स पेश करना, विशेष रूप से बड़े एप्लिकेशन में, इसका मतलब है कि आप एक सर्विस ऑब्जेक्ट से दसियों सर्विस ऑब्जेक्ट्स तक बढ़ेंगे। कोड संगठन में सुधार के लिए, सामान्य सर्विस ऑब्जेक्ट्स को नेमस्पेसेस में समूहित करना एक अच्छी प्रथा है। लाइब्रेरी एप्लिकेशन में, उदाहरण के लिए, हम सभी बुक-संबंधित सर्विसेज को एक साथ समूहित करेंगे और सभी ऑथर-संबंधित सर्विसेज को एक अलग नेमस्पेस में समूहित करेंगे। हमारी फोल्डर संरचना अब इस तरह दिखेगी:
services ├── application_service.rb └── book ├── book_creator.rb └── book_reader.rb हमारे सर्विस ऑब्जेक्ट्स इस तरह दिखेंगे:
# services/book/book_creator.rb module Book class BookCreator < ApplicationService ... end end # services/twitter_manager/book_reader.rb module Book class BookReader < ApplicationService ... end end हमारे कॉल अब Book::BookCreator.call(*args) and Book::BookReader.call(*args) बन जाएंगे।
प्रति सर्विस ऑब्जेक्ट एक जिम्मेदारी
एक सर्विस ऑब्जेक्ट होना जो एक से अधिक चीजें करता है, सर्विस ऑब्जेक्ट्स की "बिजनेस एक्शन" मानसिकता के खिलाफ जाता है। पारंपरिक रूप से, एक सामान्य सर्विस ऑब्जेक्ट होना जो कई एक्शन्स करता है, हतोत्साहित किया जाता है। यदि आप सर्विस ऑब्जेक्ट्स के बीच कोड साझा करना चाहते हैं, तो एक बेस या हेल्पर मॉड्यूल बनाएं और अपने सर्विस ऑब्जेक्ट्स में शामिल करने के लिए मिक्सिन्स का उपयोग करें।
अपवादों को रेस्क्यू करें और कस्टम एक्सेप्शन्स उठाएं
सर्विस ऑब्जेक्ट का उद्देश्य इसके अंदर कार्यान्वयन विवरणों को एनकैप्सुलेट करना है, जैसे थर्ड-पार्टी सर्विसेज या लाइब्रेरीज़ के साथ इंटरैक्शन या Rails ActiveRecord के साथ डेटाबेस मैनिपुलेशन। यदि कोई त्रुटि होती है, जैसे ActiveRecord::RecordNotUnique, ActiveRecord के साथ इंटरैक्ट करते समय, सर्विस को अपवाद को उचित तरीके से रेस्क्यू करने की आवश्यकता है। त्रुटियों को कॉल स्टैक तक प्रसारित करने की अनुमति नहीं दी जानी चाहिए। यदि इसे रेस्क्यू ब्लॉक के भीतर नहीं संभाला जा सकता है, तो उस सर्विस ऑब्जेक्ट के लिए विशिष्ट एक कस्टम-डिफाइन्ड एक्सेप्शन उठाएं।