কম্পিউটার টিউটোরিয়াল

আপনার রেইলস কোড কোথায় যাবে? নন-সিআরইউডি লজিক সংগঠন

রেইলস টিউটোরিয়াল ফিনিশ করে নিজের অ্যাপ্লিকেশন শুরু করলে জিনিসগুলো গুলগুলি হয়ে যায়। যেন নন-সিআরইউডি, জেনারেল লজিক কোথায় যাবে? টুইটার থেকে ফলোয়ার্স আনা MVC-তে কীভাবে ফিট করে? দুইজনে জিজ্ঞাসা করলে চারটি জবাব পাবেন। অথবা আপনার থ্রেড অনেক বুদ্ধিমান লোকের অপমানেরоронি বিতর্কে পরিণত হবে ঘণ্টা পর ঘণ্টা,その間 আপনি ডেস্কে মাথা খাটছেন। যেভাবেই হোক, আপনি মাথাব্যাথা लेकर বসে থাকেন।

আপনি আপনার স্বপ্নের অ্যাপ্লিকেশন বানাতে পারবেন না কিছু জেনারেল, নন-রেইলস লজিক ছাড়া। তাই আপনার কোড কোথায় রাখবেন, এবং এখনও জিনিসগুলো সিম্পল রাখবেন?

শুরু করার সহজ জায়গা

যখন আমার কাছে লজিক থাকে যা কোনো বিদ্যমান অ্যাক্টিভরেকর্ড মডেলের সাথে রিলেটেড লাগে, আমি সেটাকে সেই মডেলেই রাখতে শুরু করি। উদাহরণস্বরূপ, যদি আমার একটি Game মডেল থাকে এবং আমি CSV ফাইল থেকে অনেক গেম ইম্পোর্ট করতে চাই, তবে সেই মেথডটি আমি Game ক্লাসেই রাখব:

app/models/game.rb
class Game < ActiveRecord::Base def self.parse_from_csv(csv_string) games = [] CSV.parse(csv_string, quote_char: "'") do |row| games << Game.from_csv_row(row) if (row[0] == 'G') end games end def self.from_csv_row(row) Game.new({ dgs_game_id: row[1], opponent_name: row[2], created_at: row[4], updated_at: row[4], }) end end

আপনার মেথডগুলোর প্রয়োজনীয় সব ইনফো হাতে আছে। এটা সহজে টেস্টযোগ্য। এবং সম্ভবত একটি নতুন কন্ট্রিবিউটর সেই লজিক খুঁজতে সেটাই প্রথমে চেক করবে।

তবে আপনি সেই মডেলে যোগ ও পরিবর্তন চালিয়ে থাকলে, সেটা বড় ও জটিল হয়ে যাবে। মডেলের বিভিন্ন অংশ অদ্ভুতভাবে ইন্টারঅ্যাক্ট করবে। আপনি যত পরিবর্তন করবেন, তত পরিবর্তন করা কঠিন হবে।

সেক্ষেত্রে, আপনি সেটাকে নন-অ্যাক্টিভরেকর্ড মডেলে রিফ্যাক্টর করতে চাইবেন।

নন-অ্যাক্টিভরেকর্ড মডেল

শুধু রেইলস অ্যাপ্লিকেশনে থাকা মানে সেটাকে অ্যাক্টিভ/অ্যাকশন-যাইহোক থেকে ইনহেরিট করতে হবে নয়।

আপনি আপনার নিজস্ব রুবি কোড, প্লেইন রুবি অবজেক্টে লিখতে পারেন, এবং সেগুলো আপনার রেইলস অ্যাপ্লিকেশনে ব্যবহার করতে পারেন। এই অবজেক্টগুলো এখনও মডেল বলা যাবে, কারণ সেগুলো আপনার সমস্যার অংশটি মডেল করছে। শুধু তাদের ডেটা স্টোর করার জন্য অ্যাক্টিভরেকর্ড ডাটাবেস নেই।

আমি তারপর যখন সেই গেম CSV পার্সার নিয়ে কাজ করলাম, Game ক্লাস একটু বড় হয়ে গিয়েছিল। তাই আমি পার্সার লজিককে নিজস্ব GameCSVParser ক্লাসে সরিয়ে ফেললাম।

পুরো কমিটটি এখানে আছে, কিন্তু নন-অ্যাক্টিভরেকর্ড ক্লাসটি এমন দেখায়:

app/models/game_csv_parser.rb
class GameCSVParser def initialize(csv_string) @rows = CSV.parse(csv_string, quote_char: "'") end def games game_rows.map { |row| Game.new(game_attributes(row)) } end private def game_rows @rows.select { |row| is_game_row?(row) } end def game_attributes(row) { dgs_game_id: row[1], opponent_name: row[2], created_at: row[4], updated_at: row[4], } end def is_game_row?(row) row[0] == 'G' end end

আমি সরাসরি একটি নতুন প্লেইন রুবি অবজেক্ট তৈরি করি যদি আমি যে লজিক যোগ করছি সেটা কোনো স্পেসিফিক অ্যাক্টিভরেকর্ড মডেলের সাথে রিলেটেড না লাগে। অথবা যদি কোডটি লাগে যেন কোনো জিনিসের অংশ হওয়া উচিত جو এখনও অ্যাপ্লিকেশনে নেই। অন্যথায়, সেগুলো অধিকাংশ রিফ্যাক্টরিংয়ের মাধ্যমে আড়াল হয়।

প্লেইন রুবি অবজেক্টের সাথে, আপনি কী করতে পারেন। কিন্তু জানা যে আপনি কিছুই করতে পারেন, দিকনির্দেশনা দেয় না। আপনাকে কী মেথড দরকার? আপনার সব নতুন অবজেক্ট কীভাবে ইন্টারঅ্যাক্ট করবে?

অনেক রেইলস অ্যাপ্লিকেশন একই ক্যাটেগরির প্লেইন রুবি অবজেক্ট ব্যবহার করে। এই ক্যাটেগরিগুলো প্যাটার্ন যেগুলো ফলো করে আপনি কোড লিখতে পারেন যেন অন্য ডেভেলপাররা সেটা চেনে। আপনি কয়েকটা শুনে থাকতে পারেন।

সার্ভিস অবজেক্ট, প্রেজেন্টার, এবং জব

সার্ভিস অবজেক্ট, প্রেজেন্টার, এবং জব-এ কিছু স্পেশাল নেই। সেগুলো শুধু প্লেইন রুবি অবজেক্ট যেগুলো একটি নির্দিষ্ট চেনা যোগ্য উপায়ে কাজ করে।

উদাহরণস্বরূপ, একটি রেসকু জব হলো একটি প্লেইন রুবি ক্লাস যেটার একটি perform মেথড এবং একটি @queue আছে:

app/workers/fetch_games_for_player.rb
class FetchGamesForPlayer @queue = :default def self.perform(player_id) player = Player.scoped_by_id(player_id).ready_for_fetching.first player && player.fetch_new_games! end end

perform কল হয় জবটি রান হলে।

একটি প্রেজেন্টার হলো একটি প্লেইন রুবি অবজেক্ট যেসের কোড শুধু ভিউর ভিতরে মানে রেখে।

app/presenters/user_presenter.rb
class UserPresenter def show_related_users? @user.related.count > 3 end end

এটাও রেইলস ভিউ হেল্পার ইনক্লুড করতে পারে, অথবা কয়েকটি আলাদা অবজেক্ট নেয় এবং ভিউর সুবিধার জন্য সেগুলো একসাথে ট্রিট করে।

একটি সার্ভিস অবজেক্ট হলো একটি প্লেইন রুবি অবজেক্ট যেটা একটি প্রসেস রিপ্রেজেন্ট করে যা আপনি সম্পন্ন করতে চান। উদাহরণস্বরূপ, একটি পোস্টে কমেন্ট লেখা কা পারে:

  1. কমেন্ট রেখে দেয়।
  2. পোস্টের লেখককে নোটিফিকেশন মেইল পাঠায়।

একটি সার্ভিস অবজেক্ট দুটোই করতে পারে, এবং সেই লজিক কন্ট্রোলার থেকে বের করে রাখতে পারে।

সার্ভিস অবজেক্ট নিয়ে এখানে একটি দুর্দান্ত টেক আছে। উদাহরণ পূর্ণ।

সিম্পল প্রসেসের জন্য, আমি সার্ভিস অবজেক্টের ঝামেলায় পড়ি না। কিন্তু কন্ট্রোলার যদি খুব ভারী হয়ে যাবে, তবে অতিরিক্ত লজিক রাখার জন্য সেটা ভালো জায়গা।

আপনি এই প্যাটার্নগুলো ব্যবহার করে আপনার বიზনেস লজিক সংগঠিত করতে পারেন। সেগুলো শুধু প্লেইন রুবি অবজেক্ট, কিন্তু সেগুলো রুবি অবজেক্ট যেগুলো একটি নির্দিষ্ট ফ্লেভার শেয়ার করে, যাদের একটি নাম আছে, এবং যেগুলো নিয়ে আপনি অন্য ডেভেলপারদের সাথে কথা বলতে পারেন।

কোথায় থেকে শুরু করবেন?

আপনার নন-রেইলস বিজনেস লজিক যেতে পারে অনেক জায়গায়। বেছে নেওয়া কঠিন হতে পারে। তাই আমি কী করি:

  1. যদি লজিকটি অধিকাংশ কোনো বিদ্যমান ক্লাসের সাথে রিলেটেড থাকে, এমনকি সেটা অ্যাক্টিভরেকর্ড মডেল হোক, আমি সেটাকে সেটাই ক্লাসে রাখি।
  2. যদি সেটা কোনো বিদ্যমান ক্লাসে ফিট না করে, আমি একটি নতুন প্লেইন রুবি ক্লাস তৈরি করি লজিক রাখতে।
  3. যদি লাগে লজিকটি কোনো জিনিসের অংশ হওয়া উচিত جو এখনও নেই, আমি সেটার জন্য একটি নতুন প্লেইন রুবি ক্লাস তৈরি করি।
  4. যদি পরে কোডে ফিরে আসি, এবং মডেল খুব জটিল হয়ে যায়, অথবা কোডটি সেটা মডেলে আর মানে রাখে না, আমি সেটাকে নিজস্ব প্লেইন রুবি ক্লাসে রিফ্যাক্টর করি।
  5. যদি কোডটি শুধু ভিউতে মানে রাখে, আমি হেল্পারে যোগ করি অথবা একটি প্রেজেন্টার তৈরি করি।
  6. যদি কোডটি HTTP রিকোয়েস্টের সময় রান করতে না চায়, অথবা ব্যাকগ্রাউন্ডে রান করতে হয়, সেটা জবে যায়।
  7. যদি আমি অনেকগুলো আলাদা মডেল বা প্রসেসের স্টেজ জাগল করি, এবং সেটা কন্ট্রোলারকে খুব কঠিন করে দেয়, আমি সেটাকে একটি সার্ভিস অবজেক্টে রাখি।

আপনার কোড কোথায় যায়? এবং এইসব বাইরো কোনো প্যাটার্ন আছে যা আপনি হেল্পফুল পেয়েছেন? কমেন্টে জানান।

আপনার যদি কোনো প্রসেস না থাকে, আমারটা ট্রাই করুন। দেখুন কীভাবে ফিট করে। কোড লেখার কোনো পারফেক্ট উপায় নেই, কিন্তু আপনি আটকে থাকলে এই টাইপের প্রসেস আপনাকে শুরু করতে সাহায্য করবে।

  1. ফেসটাইমের ফটোগুলো কোথায় যায়? আপনার ফেসটাইম ফটো খুঁজে পাওয়ার পদ্ধতি

  2. আপনার ফোন কোথা থেকে আসে? (Where Does Your Phone Come From?)

  3. রুবি কোড উন্নত করুন: ক্লিনার OOP ডিজাইনের জন্য Cohesion & Coupling আয়ত্ত করুন

  4. রুবির MRI সোর্স কোডে গভীর ডুব