কম্পিউটার

কিভাবে আপনার ক্রমবর্ধমান ব্যবহারকারীদের টেবিল নিয়ন্ত্রণ

ক্লায়েন্ট কিভাবে সেখানে গেল?

বিশদ বিবরণে ডুব দেওয়ার আগে, আসুন বোঝার চেষ্টা করি কীভাবে একটি অ্যাপ এই অবস্থায় শেষ হতে পারে। আমরা একটি সাধারণ users দিয়ে শুরু করি টেবিল কয়েক সপ্তাহ পরে, আমাদের শেষ সাইন ইনের সময় নির্ধারণ করতে সক্ষম হতে হবে যাতে আমরা users.last_sign_in_at যোগ করি . তারপর ব্যবহারকারীর নাম জানতে হবে। আমরা first_name যোগ করি এবং last_name . টুইটার হ্যান্ডেল? আরেকটি কলাম। GitHub প্রোফাইল? ফোন নম্বর? কয়েক মাস পরে টেবিলটি মন দোলা দেয়।

এতে সমস্যা কি?

একটি সারণী যা অনেক বড় সমস্যা নির্দেশ করে:

  1. users একাধিক সম্পর্কহীন দায়িত্ব আছে। এটি বোঝা, পরিবর্তন এবং পরীক্ষা করা আরও কঠিন করে তোলে।
  2. অ্যাপ এবং ডাটাবেসের মধ্যে ডেটা আদান-প্রদানের জন্য অতিরিক্ত ব্যান্ডউইথের প্রয়োজন৷
  3. অ্যাপ্লিকেশানটি ভারী মডেল সংরক্ষণ করতে আরও মেমরির প্রয়োজন৷

অ্যাপটি users নিয়ে এসেছে প্রমাণীকরণ এবং অনুমোদনের উদ্দেশ্যে প্রতিটি অনুরোধে কিন্তু সাধারণত শুধুমাত্র কয়েকটি কলাম ব্যবহার করা হয়। সমস্যা সমাধান করা হলে ডিজাইন এবং কর্মক্ষমতা উভয়ই উন্নত হবে।

একটি টেবিল বের করা

আমরা একটি নতুন টেবিলে (বা টেবিল) কদাচিৎ ব্যবহৃত কলাম বের করে সমস্যার সমাধান করতে পারি . উদাহরণস্বরূপ, আমরা প্রোফাইল তথ্য বের করতে পারি (first_name , ইত্যাদি) profiles-এ নিম্নলিখিত ধাপগুলি সহ:

  1. profiles তৈরি করুন users-এ প্রোফাইল-সম্পর্কিত কলামের নকল কলাম সহ .
  2. profile_id যোগ করুন users কাছে . এটিকে NULL এ সেট করুন আপাতত।
  3. users প্রতিটি সারির জন্য , profiles-এ একটি সারি ঢোকান যা প্রোফাইল-সম্পর্কিত কলামের নকল করে।
  4. পয়েন্ট profile_id users-এর সংশ্লিষ্ট সারির 3-এ সন্নিবেশিত সারিতে।
  5. করুন না users.profile_id তৈরি করুন অ-NULL . অ্যাপটি এখনও তার অস্তিত্ব সম্পর্কে সচেতন নয় তাই এটি ভেঙে যাবে।

আমাদের users.first_name এর রেফারেন্স প্রতিস্থাপন করতে হবে profiles.first_name সহ এবং তাই আমরা যদি মুষ্টিমেয় কিছু রেফারেন্স সহ কয়েকটি কলাম বের করি তাহলে আমি ম্যানুয়ালি এটি করার পরামর্শ দিই। কিন্তু যত তাড়াতাড়ি আমরা নিজেকে ধরি "ওহ, না। এটি এখন পর্যন্ত সবচেয়ে খারাপ কাজ!" আমাদের একটি বিকল্প সন্ধান করা উচিত।

সমস্যাটিকে অবহেলা করবেন না। কোডের একটি অংশ যা প্রত্যেকে এড়িয়ে চলে তা আরও খারাপ হবে এবং আরও বেশি অসাবধানতার শিকার হবে . দুষ্ট বৃত্ত ভাঙ্গার সবচেয়ে সহজ উপায় হল ছোট শুরু করা।

পড়ুন, যদি আপনি জানতে চান কিভাবে আমার ক্লায়েন্ট সমস্যার সমাধান করেছে।

কোডটি একবারে একটি লাইন ঠিক করা

সবচেয়ে ক্রমবর্ধমান পদ্ধতি হল এক সময়ে পুরানো কলামের একটি রেফারেন্স ঠিক করা। চলুন first_name সরানোর উপর ফোকাস করা যাক users থেকে profiles-এ .

প্রথমে, profiles তৈরি করুন সাথে:

rails generate model Profile first_name:string

তারপর users থেকে একটি রেফারেন্স যোগ করুন profiles-এ এবং users.first_name কপি করুন profiles-এ :

class ExtractUsersFirstNameToProfiles < ActiveRecord::Migration
  # Redefine the models to break dependency on production code. We need
  # vanilla models without callbacks, etc. Also, removing a model in the future
  # might break the migration.
  class User < ActiveRecord::Base; end
  class Profile < ActiveRecord::Base; end
 
  def up
    add_reference :users, :profile, index: true, unique: true, foreign_key: true
 
    User.find_each do |user|
      profile = Profile.create!(first_name: user.first_name)
      user.update!(profile_id: profile.id)
    end
 
    change_column_null :users, :profile_id, false
  end
 
  def down
    remove_reference :users, :profile
  end
end

কারণ এটি প্রতিটি ব্যবহারকারীকে ঠিক একটি প্রোফাইল, users থেকে একটি রেফারেন্স রাখতে বাধ্য করে profiles-এ বিপরীত রেফারেন্সের জন্য পছন্দনীয়।

ডাটাবেস কাঠামো ঠিক রেখে, আমরা first_name অর্পণ করতে পারি users থেকে Profile . আমার ক্লায়েন্টের বেশ কিছু প্রয়োজনীয়তা ছিল:

  1. অ্যাক্সেসরদের সংশ্লিষ্ট profiles ব্যবহার করা উচিত . তাদেরও লগ করা উচিত যেখান থেকে ডেপ্রেকেটেড অ্যাকসেসর কল করা হয়েছে।
  2. users সংরক্ষণ করা হচ্ছে স্বয়ংক্রিয়ভাবে profiles সংরক্ষণ করা উচিত অবচয়িত অ্যাক্সেসর ব্যবহার করে কোড ভাঙা এড়াতে।
  3. User#first_name_changed? এবং অন্যান্য ActiveModel::Dirty পদ্ধতিগুলি এখনও কাজ করা উচিত।

এর মানে users এই মত দেখতে হবে:

class User < ActiveRecord::Base
  # We need autosave as the client code might be unaware of
  # Profile#first_name and still reference User#first_name.
  belongs_to :profile, autosave: true
 
  def first_name
    log_backtrace(:first_name)
    profile.first_name
  end
 
  def first_name=(new_first_name)
    log_backtrace(:first_name)
 
    # Call super so that User#first_name_changed? and similar still work as
    # expected.
    super
 
    profile.first_name = new_first_name
  end
 
  private
 
  def log_backtrace(name)
    filtered_backtrace = caller.select do |item|
      item.start_with?(Rails.root.to_s)
    end
    Rails.logger.warn(<<-END)
A reference to an obsolete attribute #{name} at:
#{filtered_backtrace.join("\n")}
END
  end
end

এই পরিবর্তনগুলির পরে, অ্যাপটি একই কাজ করে তবে profiles-এর অতিরিক্ত উল্লেখের কারণে এটি কিছুটা ধীর হতে পারে (যদি কর্মক্ষমতা একটি সমস্যা হয়ে ওঠে শুধু AppSignal এর মত একটি টুল ব্যবহার করুন)। কোডটি লিগ্যাসি অ্যাট্রিবিউটের সমস্ত রেফারেন্স লগ করে, এমনকি অপ্রতিরোধ্য (যেমন user[attr] = ... অথবা user.send("#{attr}=", ...) ) তাই আমরা grep থাকাকালীনও তাদের সকলকে সনাক্ত করতে সক্ষম হব অসহায়৷

এই পরিকাঠামোর জায়গায়, আমরা users.first_name এর একটি রেফারেন্স ঠিক করতে প্রতিশ্রুতিবদ্ধ হতে পারি একটি নিয়মিত সময়সূচীতে, যেমন প্রতিদিন সকালে (একটি দ্রুত জয় দিয়ে দিন শুরু করতে) বা দুপুরের দিকে (একটি ফোকাসড সকালের পরে সহজ কিছুতে কাজ করতে)। এই প্রতিশ্রুতি অপরিহার্য কারণ আমাদের লক্ষ্য হল সমস্যা সমাধানের জন্য মানসিক বাধাগুলি কমানো . কোনো ব্যবস্থা না নিয়ে উপরের কোডটি যথাস্থানে রেখে দিলে অ্যাপটি আরও দরিদ্র হয়ে যাবে।

সমস্ত অপসারিত রেফারেন্স মুছে ফেলার পরে (এবং grep দিয়ে নিশ্চিত করা এবং লগ) আমরা অবশেষে users.first_name বাদ দিতে পারি :

class RemoveUsersFirstName < ActiveRecord::Migration
  def change
    remove_column :users, :first_name, :string
  end
end

আমাদের User-এ যোগ করা কোড থেকেও মুক্তি পাওয়া উচিত যেহেতু এটি আর প্রয়োজন নেই৷

সীমাবদ্ধতা

পদ্ধতিটি আপনার ক্ষেত্রে প্রযোজ্য হতে পারে তবে এর কিছু সীমাবদ্ধতা মনে রাখবেন:

  • এটি User.update_all এর মত বাল্ক প্রশ্নগুলি পরিচালনা করে না .
  • এটি কাঁচা SQL কোয়েরি পরিচালনা করে না।
  • এটি বানর-প্যাচগুলি ভেঙে দিতে পারে (মনে রাখবেন যে নির্ভরতা তাদেরও পরিচয় করিয়ে দিতে পারে)।
  • users এবং profiles সিঙ্কের বাইরে হতে পারে, যদি profiles.first_name আপডেট করা হয়েছে কিন্তু users.first_name হয় না।

আপনি তাদের কিছু অতিক্রম করতে সক্ষম হতে পারে. উদাহরণস্বরূপ, আপনি মডেলগুলিকে কোনও পরিষেবা বস্তুর সাথে সিঙ্কে রাখতে পারেন বা profiles-এ একটি কলব্যাক রাখতে পারেন . অথবা যদি আপনি PostgreSQL ব্যবহার করেন তাহলে আপনি অন্তর্বর্তী সময়ে একটি বস্তুগত দৃশ্য ব্যবহার করার কথা বিবেচনা করতে পারেন।

এটাই!

নিবন্ধের সবচেয়ে গুরুত্বপূর্ণ পাঠ হল গন্ধযুক্ত কোড এড়িয়ে যাবেন না বরং এটিকে সামলে নিন . যদি কাজটি অপ্রতিরোধ্য হয় তবে নিয়মিত সময়সূচীতে পুনরাবৃত্তিমূলকভাবে কাজ করুন। নিবন্ধটি উপস্থাপন করা হয়েছে a একটি টেবিল নিষ্কাশন করার সময় বিবেচনা করার পদ্ধতি কঠিন। আপনি যদি এটি প্রয়োগ করতে না পারেন তবে অন্য কিছু সন্ধান করুন। যদি আপনার কোন ধারণা না থাকে তবে আমাকে একটি লাইন ড্রপ করুন। আমি সাহায্য করার চেষ্টা করব. আপনার বিট পচা যাক না.


  1. কিভাবে আপনার পিসিকে একটি টিভিতে সংযুক্ত করবেন

  2. কিভাবে আপনার পিসিতে MX প্লেয়ার ইনস্টল করবেন?

  3. কিভাবে আপনার Windows 10 পিসির গতি বাড়াবেন।

  4. কিভাবে Facebook আপনার বিশ্বাস পুনরুদ্ধার করার চেষ্টা করছে?