একটি পরিষেবা বস্তু একটি রুবি বস্তু যা একটি একক ক্রিয়া সম্পাদন করে। এটি আপনার ডোমেন বা ব্যবসায়িক যুক্তিতে একটি প্রক্রিয়া অন্তর্ভুক্ত করে। কল্পনা করুন যে আপনাকে একটি কাল্পনিক লাইব্রেরি অ্যাপ্লিকেশনে একটি বইয়ের উদাহরণ তৈরি করতে হবে; একটি সাধারণ রেল অ্যাপে, আপনি নিম্নলিখিতগুলি করবেন:
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
কেন আপনার পরিষেবার বস্তুর প্রয়োজন
MVC (যেমন, মডেল, কন্ট্রোলার, ভিউ এবং সাহায্যকারী) সাংগঠনিক কাঠামোকে স্থানীয়ভাবে সমর্থন করার জন্য রেলগুলি ডিজাইন করা হয়েছে। এই গঠন সহজ অ্যাপ্লিকেশনের জন্য পর্যাপ্ত. যাইহোক, আপনার অ্যাপ্লিকেশন বাড়ার সাথে সাথে আপনি মডেল এবং কন্ট্রোলার জুড়ে ডোমেইন/ব্যবসায়িক যুক্তি দেখতে শুরু করতে পারেন। এই ধরনের যুক্তিগুলি নিয়ামক বা মডেলের অন্তর্গত নয়, তাই তারা কোডটিকে পুনরায় ব্যবহার এবং বজায় রাখা কঠিন করে তোলে। একটি রেল পরিষেবা অবজেক্ট হল একটি প্যাটার্ন যা আপনাকে কন্ট্রোলার এবং মডেলগুলি থেকে ব্যবসায়িক যুক্তিকে আলাদা করতে সাহায্য করতে পারে, মডেলগুলিকে সহজভাবে ডেটা স্তর এবং আপনার API-তে কন্ট্রোলার এন্ট্রি পয়েন্ট হতে সক্ষম করে৷
আমরা যখন নিম্নলিখিতগুলি সহ ব্যবসায়িক যুক্তিকে এনক্যাপসুলেট করার জন্য পরিষেবাগুলি চালু করি তখন আমরা অনেক সুবিধা পাই:
-
লিন রেল কন্ট্রোলার - নিয়ন্ত্রক শুধুমাত্র অনুরোধগুলি বোঝার জন্য এবং অনুরোধের প্যারাম, সেশন এবং কুকিগুলিকে আর্গুমেন্টে পরিণত করার জন্য দায়ী যা কাজ করার জন্য পরিষেবা বস্তুতে পাস করা হয়। নিয়ামক তারপর পরিষেবা প্রতিক্রিয়া অনুযায়ী পুনঃনির্দেশ বা রেন্ডার করে। এমনকি বড় অ্যাপ্লিকেশনগুলিতে, পরিষেবা বস্তুগুলি ব্যবহার করে কন্ট্রোলার অ্যাকশনগুলি সাধারণত 10 লাইনের বেশি কোড নয়৷
-
পরীক্ষাযোগ্য কন্ট্রোলার - যেহেতু কন্ট্রোলাররা চর্বিহীন এবং পরিষেবার সহযোগী হিসাবে কাজ করে, তাই এটি পরীক্ষা করা সত্যিই সহজ হয়ে যায়, কারণ আমরা শুধুমাত্র পরীক্ষা করতে পারি যে যখন একটি নির্দিষ্ট ক্রিয়া ঘটে তখন কন্ট্রোলারের মধ্যে নির্দিষ্ট পদ্ধতিগুলিকে কল করা হয় কিনা৷
-
বিচ্ছিন্নভাবে ব্যবসায়িক প্রক্রিয়া পরীক্ষা করার ক্ষমতা - পরিষেবাগুলি পরীক্ষা করা সহজ এবং দ্রুত কারণ এগুলি ছোট রুবি বস্তু যা তাদের পরিবেশ থেকে আলাদা করা হয়েছে৷ আমরা সহজেই সমস্ত সহযোগীদের আটকাতে পারি এবং শুধুমাত্র আমাদের পরিষেবার মধ্যে নির্দিষ্ট পদক্ষেপগুলি সম্পাদিত হয়েছে কিনা তা পরীক্ষা করতে পারি৷
৷ -
পুনরায় ব্যবহারযোগ্য পরিষেবাগুলি৷ - পরিষেবা বস্তুগুলিকে কন্ট্রোলার, অন্যান্য পরিষেবা বস্তু, সারিবদ্ধ কাজ, ইত্যাদি দ্বারা কল করা যেতে পারে৷
-
ফ্রেমওয়ার্ক এবং ব্যবসায়িক ডোমেনের মধ্যে বিচ্ছেদ - রেল কন্ট্রোলার শুধুমাত্র পরিষেবাগুলি দেখে এবং সেগুলি ব্যবহার করে ডোমেন অবজেক্টের সাথে ইন্টারঅ্যাক্ট করে৷ কাপলিংয়ের এই হ্রাস স্কেলেবিলিটি সহজ করে তোলে, বিশেষ করে যখন আপনি একটি মনোলিথ থেকে একটি মাইক্রোসার্ভিসে যেতে চান। আপনার পরিষেবাগুলি সহজেই বের করা যেতে পারে এবং ন্যূনতম পরিবর্তন সহ একটি নতুন পরিষেবাতে স্থানান্তরিত করা যেতে পারে৷
৷
একটি পরিষেবা বস্তু তৈরি করা
প্রথমে, আসুন একটি কাল্পনিক লাইব্রেরি পরিচালনা অ্যাপ্লিকেশনের জন্য অ্যাপ/পরিষেবা নামে একটি নতুন ফোল্ডারে একটি নতুন 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
# handle duplicate entry
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
# handle duplicate entry
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(নিজেকে পুনরাবৃত্তি করবেন না) রাখতে এবং অন্যান্য পরিষেবা বস্তুর সাথে এই আচরণটি পুনরায় ব্যবহার করতে, আমরা 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 রত্ন দিয়ে, আপনাকে একটি বেস অ্যাপ্লিকেশন পরিষেবা ক্লাস তৈরি করতে হবে না বা initialize
সংজ্ঞায়িত করতে হবে না পদ্ধতি কারণ রত্নটির মধ্যে এই সমস্ত কনফিগারেশন রয়েছে। আপনার পরিষেবা বস্তুটিকে কেবল BusinessProcess::Base
থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হতে হবে .
আপনার রত্ন ফাইলে, নিম্নলিখিত যোগ করুন:
gem 'business_process'
এবং তারপর bundle
চালান আপনার টার্মিনালে কমান্ড
class BookCreator < BusinessProcess::Base
# Specify requirements
needs :title
needs :description
needs :author_id
needs :genre_id
# Specify process (action)
def call
create_book
end
private
def create_book
# ...
end
end
ভাল পরিষেবার বস্তু তৈরি করার নির্দেশিকা
একটি সর্বজনীন পদ্ধতি
একটি পরিষেবা অবজেক্ট একটি ব্যবসায়িক ক্রিয়া সম্পাদন করে এবং এটি ভাল করে বলে অনুমিত হয়, তাই এটি করার জন্য এটি শুধুমাত্র একটি একক সর্বজনীন পদ্ধতি প্রকাশ করা উচিত। অন্যান্য পদ্ধতিগুলি ব্যক্তিগত হওয়া উচিত এবং পাবলিক পদ্ধতিতে বলা উচিত। আপনি যা পছন্দ করেন তা সর্বজনীন পদ্ধতির নামকরণ করতে পারেন, যতক্ষণ না নামকরণ সমস্ত পরিষেবা বস্তুতে সামঞ্জস্যপূর্ণ থাকে। আমাদের উদাহরণে, আমরা এটির নাম দিয়েছি call
. অন্যান্য প্রচলিত নাম হল perform
এবং execute
.
তারা যে ভূমিকা পালন করে সেই অনুযায়ী সার্ভিস অবজেক্টের নাম দিন
একটি পরিষেবা বস্তুর নাম এটি কি করে তা নির্দেশ করা উচিত। "বা" এবং "er" দিয়ে শেষ হওয়া শব্দগুলির সাথে পরিষেবা বস্তুর নামকরণের একটি জনপ্রিয় উপায় রয়েছে। উদাহরণস্বরূপ, যদি পরিষেবা বস্তুর কাজ একটি বই তৈরি করা হয়, তবে এটির নাম দিন BookCreator, এবং কাজটি যদি একটি বই পড়া হয়, তাহলে সেটির নাম দিন BookReader৷
সরাসরি পরিষেবার বস্তুগুলিকে ইনস্ট্যান্টিয়েট করবেন না
কলিং পরিষেবা বস্তুর স্বরলিপি সংক্ষিপ্ত করতে সিনট্যাকটিক চিনির প্যাটার্ন বা বিজনেসপ্রসেসের মতো রত্নগুলির মতো বিমূর্ততা ব্যবহার করুন। এই পদ্ধতির ব্যবহার আপনাকে 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 এর সাথে ইন্টারঅ্যাক্ট করার সময়, পরিষেবাটিকে সঠিকভাবে ব্যতিক্রমটি উদ্ধার করতে হবে। কল স্ট্যাক প্রচার করার জন্য ত্রুটিগুলিকে অনুমতি দেওয়া উচিত নয়৷ যদি রেসকিউ ব্লকের মধ্যে এটি পরিচালনা করা না যায়, তবে সেই পরিষেবা বস্তুর জন্য নির্দিষ্ট একটি কাস্টম-সংজ্ঞায়িত ব্যতিক্রম উত্থাপন করুন৷
উপসংহার
সার্ভিস অবজেক্ট প্যাটার্ন আপনার অ্যাপ্লিকেশনের সামগ্রিক নকশাকে ব্যাপকভাবে উন্নত করতে পারে কারণ আপনি আপনার অ্যাপ্লিকেশনে নতুন বৈশিষ্ট্য যুক্ত করেন। এটি আপনার কোডবেসকে আরও অভিব্যক্তিপূর্ণ, বজায় রাখা সহজ এবং পরীক্ষা করার জন্য কম বেদনাদায়ক করে তুলবে৷