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

রুবি কোড লোডার্স মাস্টারিং: Zeitwerk-এ গভীর ডুব

রুবিতে কোড লোডার্স - Zeitwerk বুঝতে

Zeitwerk-এর সাথে, আপনি আপনার প্রোগ্রামিং স্ট্রীমলাইন করতে পারেন জেনে যে ক্লাস এবং মডিউল همه জায়গায় উপলব্ধ।

কোড লোডার্স কী?

কোড লোডার্স ডেভেলপারদের classes এবং modules আলাদা ফাইল এবং ফোল্ডারে ডিফাইন করতে দেয় এবং সেগুলো এক্সপ্লিসিটলি require না করেই পুরো কোডবেসে ব্যবহার করতে দেয়। Rails একটি ভালো উদাহরণ সফটওয়্যারের যা কোড লোডার ব্যবহার করে। রেইলসে প্রোগ্রামিংয়ে মডেলগুলো কন্ট্রোলারে ব্যবহার করার আগে এক্সপ্লিসিট require কল করতে হয় না। আসলে, Rails 6-এ, app ডিরেক্টরির সব কিছু অ্যাপ বুটির সময় অটো-লোড হয়, কিছু এক্সসেপশন ছাড়া।

কোড লোডিং শুধু require কল করার বিষয় বলে ভাবা সহজ, কিন্তু এটা সত্য নয়। কোড লোডিং আরও তিনটি অংশে ভাগ করা যায়:

  • Auto Loading (অটো লোডিং): এর মানে কোড অন-দ-ফ্লাই (on-the-fly) লোড হয় প্রয়োজন অনুযায়ী। উদাহরণস্বরূপ, রেইলসে, rails s চালালে সকল মডেল, কন্ট্রোলার ইত্যাদি লোড হয় না। কিন্তু প্রথমবার User মডেল হিট করলে, এটি অটো লোডিং মেকানিজম চালু করে মডেল খুঁজে বের করে এবং ব্যবহার করে। এটি অটো লোডিং-এর কাজ। এতে ডেভেলপমেন্ট এনভায়রনমেন্টে কিছু সুবিধা আছে, যেমন দ্রুত অ্যাপ এবং rails console স্টার্টআপ টাইম। Rails.config.autoload_path অটো-লোড হওয়া পাথগুলো কন্ট্রোল করে।
  • Eager Loading (ইগার লোডিং): এর মানে কোড অ্যাপ স্টার্টআপে মেমরিতে লোড হয় এবং কনস্ট্যান্ট কল হওয়ার জন্য অপেক্ষা করে না। রেইলসে, প্রোডাকশনে কোড ইগার লোড হয়। উপরের ব্যাখ্যা অনুযায়ী, প্রোডাকশনে কোড অটোলোড করলে প্রতিটি কনস্ট্যান্ট অন-দ-ফ্লাই রিকোয়ার করায় স্লো রেসপন্স টাইম হবে। Rails.config.eager_load_paths ইগার লোড হওয়া পাথগুলো কন্ট্রোল করে।
  • Reloading (রিলোডিং): কোড লোডার কনস্ট্যান্টলি autoload_path-এ ফাইল চেঞ্জ করলে সেগুলো রিলোড করে। রেইলসে, এটি ডেভেলপমেন্টে খুব উপকারী, কারণ এটি আমাদের rails s চালিয়ে সিমাল্টেনিয়াসলি পরিবর্তন করতে দেয় রেইলস সার্ভার রিস্টার্ট ছাড়া। এটি রিলোডিং-এ একশন।

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

Zeitwerk কী?

Zeitwerk রুবির জন্য একটি এফিশিয়েন্ট এবং থ্রেড-সেফ (thread-safe) কোড লোডার এবং যেকোনো রুবি প্রজেক্টে ব্যবহার করা যায়, যার মধ্যে Web ফ্রেমওয়ার্ক (Rails, Hanami, Sinatra), CLI টুলস, এবং জেমস। এর সাথে, আপনি আপনার প্রোগ্রামিং স্ট্রীমলাইন করতে পারেন জেনে যে ক্লাস এবং মডিউল সব জায়গায় উপলব্ধ। ঐতিহাসিকভাবে, রেইলস এবং কিছু অন্য জেমের বিল্ট-ইন কোড লোডার আছে এই ফাংশনালিটি ইন্যাবল করার জন্য। তবে, Zeitwerk এই কনসেপ্টগুলো এক্সট্র্যাক্ট করে একটি জেমে এবং রুবিস্টদের তাদের প্রজেক্টে এই কনসেপ্টগুলো অ্যাপ্লাই করার সুযোগ দেয়।

Zeitwerk ইনস্টল

প্রথম কাজ, জেমটি ইনস্টল করতে হবে:


gem install zeitwerk
# অথবা আপনার Gemfile-এ
gem 'zeitwerk', '~> 2.4.0'

Zeitwerk কনফিগার

তাহলে বেসিকগুলো থেকে শুরু করি:


require 'zeitwerk'
loader = Zeitwerk::Loader.new
...
loader.setup

উপরের কোড একটি লোডার ইনস্ট্যান্স তৈরি করে এবং setup কল করে। setup কল হওয়ার পর, লোডাররা কোড লোড করার জন্য রেডি। কিন্তু সেটির আগে, loader-এ সমস্ত প্রয়োজনীয় কনফিগারেশন কভার করা উচিত। এই আর্টিকেলে, আমি loader-এর কিছু কনফিগারেশন এবং কোড স্ট্রাকচার করার কনভেনশন কভার করব।

  • ফাইল স্ট্রাকচার: Zeitwerk কাজ করার জন্য, ফাইল এবং ডিরেক্টরি নামগুলো মডিউল এবং ক্লাস নামের সাথে ম্যাচ করতে হবে যেগুলো সেগুলো ডিফাইন করে। উদাহরণস্বরূপ,

lib/my_gem.rb -> MyGem
lib/my_gem/foo.rb -> MyGem::Foo
lib/my_gem/bar_baz.rb -> MyGem::BarBaz
lib/my_gem/woo/zoo.rb -> MyGem::Woo::Zoo
  • রুট نیمস্পেস (Root Namespaces): রুট نیمস্পেস হলো ডিরেক্টরিগুলো যেখানে Zeitwerk আপনার কোড খুঁজে পায়। যখন modules এবং classes রেফারেন্স করা হয়, Zeitwerk মিলে যাওয়া ফাইল নাম সহ রুট نیمস্পেস সার্চ করে। উদাহরণস্বরূপ,

require 'zeitwerk'
loader = Zeitwerk::Loader.new
loader.push_dir("app/models")
loader.push_dir("app/controllers")
// নিচের মত ম্যাচ করে
app/models/user.rb -> User
app/controllers/admin/users_controller.rb -> Admin::UsersController

দুইটি প্রাথমিক উপায় আছে রুট نیمস্পেস ডিফাইন করার জন্য দুটি আলাদা ইউজ কেসের জন্য। ডিফল্ট উপায় নিচে দেখানো হলো:


// init.rb
require 'zeitwerk'
loader = Zeitwerk::Loader.new
loader.push_dir("#{__dir__}/bar")
...
loader.setup

// bar/foo.rb
class Foo; end

এর মানে ক্লাস Foo এক্সপ্লিসিট Bar::Foo ছাড়া রেফারেন্স করা যাবে, কারণ bar ডিরেক্টরি রুট نیمস্পেস হিসেবে কাজ করে। দ্বিতীয় উপায় হলো এক্সপ্লিসিটলি নেমস্পেস স্টেট করা push_dir কলের মধ্যে:


// init.rb
require 'zeitwerk'
module Bar
end
loader = Zeitwerk::Loader.new
loader.push_dir("#{__dir__}/src", namespace: Bar)
loader.setup

// src/foo.rb
class Bar::Foo; end

এই কোড থেকে কিছু কথা লক্ষ্য করুন:

  1. মডিউল Bar push_dir দ্বারা ব্যবহার করার আগে ইতিমধ্যে ডিফাইন করা ছিল। যদি আমরা যে মডিউল ব্যবহার করতে চাই সেটি থার্ড-পার্টি দ্বারা ডিফাইন করা থাকে, তবে একটি সিম্পল require সেটি ডিফাইন করবে push_dir-এ ব্যবহার করার আগে।
  2. push_dir এক্সপ্লিসিটলি নেমস্পেস Bar স্পেসিফাই করে।
  3. ফাইল src/foo.rb Bar::Foo ডিফাইন করে, Foo না, এবং src/bar/foo.rb এর মত ডিরেক্টরি তৈরি করার দরকার পড়ল না।
  • ইনডিপেন্ডেন্ট কোড লোডার: ডিজাইনে, Zeitwerk প্রতিটি প্রজেক্ট বা অ্যাপ ডিপেন্ডেন্সিকে তার নিজস্ব প্রজেক্ট ট্রি ম্যানেজ করতে দেয়। এর মানে প্রতিটি ডিপেন্ডেন্সির কোড লোডিং মেকানিজম সেটি নিজে ম্যানেজ করে। উদাহরণস্বরূপ, Rails 6-এ, Zeitwerk রেইলস অ্যাপের কোড লোডিং হ্যান্ডেল করে এবং প্রতিটি জেম ডিপেন্ডেন্সিকে তার নিজস্ব প্রজেক্ট ট্রি আলাদাভাবে ম্যানেজ করতে দেয়। একাধিক কোড লোডারের মধ্যে ওভারল্যাপিং ফাইল থাকা একটি এরর কন্ডিশন।
  • অটোলোডিং: উপরের সেটআপে, একবার setup কল হলে, সব ক্লাস এবং মডিউল ডিমান্ড অনুযায়ী উপলব্ধ হবে।
  • রিলোডিং: রিলোডিং ইন্যাবল করতে, loader-কে এক্সপ্লিসিটলি কনফিগার করতে হবে। উদাহরণস্বরূপ,

loader = Zeitwerk::Loader.new
...
loader.enable_reloading # setup-এর আগে অপ্ট-ইন করতে হবে
loader.setup
...
loader.reload

loader.reload কল প্রজেক্ট ট্রি অন-দ-ফ্লাই রিলোড করে, এবং যেকোনো নতুন পরিবর্তন tứcমোত দৃশ্যমান হয়। তবে, আমাদের এখনো একটি সারাউন্ডিং মেকানিজম দরকার ফাইল সিস্টেম চেঞ্জ ডিটেক্ট করে loader.reload কল করার জন্য। একটি সিম্পল ভার্সন নিচে:


require 'filewatcher'
loader = Zeitwerk::Loader.new
...
loader.enable_reloading
loader.setup
...
my_filewatcher = Filewatcher.new('lib/')
Thread.new(my_filewatcher) {|fw| fw.watch {|filename| loader.reload } }

রেইলসে Zeitwerk ব্যবহার

Zeitwerk রেইলস ৬.০-এ ডিফল্টভাবে ইন্যাবলড। তবে, আপনি অপ্ট-আউট করে রেইলস classic কোড লোডার ব্যবহার করতে পারেন।


# config/application.rb
config.load_defaults "6.0"
config.autoloader = :classic

জেমসে Zeitwerk ব্যবহার

Zeitwerk জেমসের জন্য একটি সুবিধাজনক মেথড দেয়, যতক্ষণ না তারা স্ট্যান্ডার্ড জেম স্ট্রাকচার (lib/special_gem) ব্যবহার করে। এই কনভেনিয়েন্স মেথডটি নিচের মত ব্যবহার করা যায়:


# lib/special_gem.rb
require 'zeitwerk'
module SpecialGem
end
loader = Zeitwerk::Loader.for_gem
loader.setup

স্ট্যান্ডার্ড জেম স্ট্রাকচারের সাথে, for_gem কল lib ডিরেক্টরিকে রুট نیمস্পেস হিসেবে যোগ করে, যাতে lib ডিরেক্টরির সব কোড অটোমেটিক্যালি খুঁজে পাওয়া যায়।

আরো অনুপ্রেরণার জন্য, Zeitwerk ব্যবহার করা জেমগুলো চেক আউট করুন:

  • Karafka
  • Jets

রেফারেন্স

Rails autoloading — how it works, and when it doesn't

Zeitwerk

  1. রুবিতে সিলেকশন সর্ট মাস্টার করুন: স্টেপ-বাই-স্টেপ ইমপ্লিমেন্টেশন

  2. রুবি দিয়ে ইন্সারশন সর্টিং দক্ষতা অর্জন: ধাপে ধাপে গাইড

  3. রুবিতে Dup বনাম Clone: অবজেক্ট কপি করার কৌশলকে মাস্টার করুন

  4. রুবিতে স্ট্যাটিক অ্যানালাইসিস মাস্টার করুন: Parser Gem দিয়ে মেথড ও প্যারামিটার এক্সট্রাক্ট করুন