ডাটাবেস: প্রি - আর পোস্ট -ডেপ্লয়মেন্ট স্ক্রিপ্টের চক্করে!

ডাটাবেস: প্রি - আর পোস্ট -ডেপ্লয়মেন্ট স্ক্রিপ্টের চক্করে!
এপ্রিল ১৮, বুধবার, ২০১৮


আজকে কোড ডেভেলপমেন্ট আর ডেপ্লয়মেন্টে প্রসেসের উপর লিখবো।  যথারীতি কাজ করতে গিয়ে (ঠেকে) শেখা একটা বিষয় নিয়েই লিখছি।  ব্যাপারটা বুঝতে হলে একটু মাথা খাটাতে হবে।  জটিল কিছু না, কিন্তু কয়েকটা বিষয় একসাথে মাথায় রাখতে হবে বলেই 'মাথা খাটাতে' হবে বলে সাবধান করে দিচ্ছি। এক কাপ চা / কফি নিয়ে বসতে পারেন।


কী, রেডি?

প্রথম কথা হচ্ছে কি করতে চাচ্ছিলাম, সেটা বলি: খুব সিম্পল একটা বিষয়, ডাটাবেসে একটা এক্সিস্টিং টেবিলে একটা নতুন কলাম যোগ করতে চাচ্ছিলাম।  'Status' নামে একটা Int টাইপ non-null কলাম যোগ করবো।  কারণ কী? একজন ইউসারের স্ট্যাটাস বোঝানোর জন্য। Active কিংবা Inactive বোঝাতে যথাক্রমে '1' আর  '0' দিয়ে রাখবো। কোডে এই স্ট্যাটাসের উপর ভিত্তি করে ইউসারকে লগইন করতে দিবো কিংবা দিবো না - এইটাই ছিল উদ্দেশ্য।

এই সিম্পল কাজটা করতে গিয়েই কী কী ঝামেলায় পড়লাম আর নতুন করে কী শিখলাম সেইটাই লিখছি।

আচ্ছা, এখন যেসব জিনিস মাথায় রাখতে হবে সেগুলো বলি।  এই জিনিস গুলো কোড ডেভেলপমেন্ট আর ডেপ্লয়মেন্টের প্র্যাক্টিস বা প্রচলিত ধারা।  অন্তত আমি যেই কোম্পানিতে কাজ করি, এরা এইগুলো ফলো করে বা মেনে চলে।  ইন্ডাস্ট্রিতে অন্যরাও কি একই নিয়ম মেনে চলে কিনা আমার জানা নেই (কিন্তু আমার ধারণা এইগুলো বেস্ট প্র্যাক্টিস):

বেস্ট প্র্যাক্টিস-১. ডাটাবেসে কোনো পরিবর্তন করতে হলে (মূলতঃ স্ট্রাকচারাল পরিবর্তন যেমনটা আমি চাচ্ছিলাম) SQL স্ক্রিপ্ট লিখতে হবে।  প্রতি স্ক্রিপ্টের রোলব্যাক স্ক্রিপ্ট থাকবে যেটা মূল স্ক্রিপ্টের উল্টো কাজ করে ডাটাবেসকে আগের জায়গায় নিয়ে যাবে।

বেস্ট প্র্যাক্টিস-২. স্ক্রিপ্ট আর রোলব্যাক স্ক্রিপ্ট এমনভাবে লিখতে হবে যেন কোনো স্ক্রিপ্ট (ভুল করে)  একাধিক বার অথবা যেকোনো ক্রমে (যেমন স্ক্রিপ্টের আগেই রোলব্যাক স্ক্রিপ্ট) চালালেও কোনো এক্সসেপশন হবে না।  ডাটাবেসে পরিবর্তনটা একবারই হবে।

বেস্ট প্র্যাক্টিস-৩. পুরো কোড ডেপ্লয়মেন্ট "On the fly" বা লাইভ হবে, অর্থাৎ প্রোডাকশন এনভায়রনমেন্ট চালু থাকবে, ইউসাররা তাদের কাজ চালিয়ে যাবে।  প্রোডাকশনে একাধিক এপ্লিকেশন সার্ভার থাকে। এই লাইভ ডেপ্লয়মেন্ট মূলত করা হয় এক - একটা সার্ভার ডাউন করে।  অন্য সচল সার্ভার গুলো তখন ইউসারের রিকোয়েস্ট হ্যান্ডেল করে।  ডাটাবেস সার্ভার কিন্তু অনেক ক্ষেত্রেই একটাই থাকে, যেটা সব সময় সচল থাকে।

বেস্ট প্র্যাক্টিস-৪. প্রোডাকশন এনভায়রমেন্টে কোড ডেপ্লয় হবে এই ধাপে : ক) প্রি-প্রোডাকশন SQL স্ক্রিপ্ট রান করবে, খ) এপ্লিকেশন সার্ভারে নতুন কোড ডেপ্লয় করা হবে  গ) কোনো পোস্ট-ডেপ্লয়মেন্ট SQL স্ক্রিপ্ট  থাকলে সেগুলো রান করা হবে।

[বেস্ট প্র্যাক্টিস -৫: একটু পরে বলছি]

এইখানে একটা জিনিস বলে নেই, ৪/'ক' আর ৪/'খ' ধাপের মধ্যে (অর্থাৎ নতুন কোড ডেপ্লয় করার আগে) প্রোডাকশনের সচল সার্ভার গুলোতে কিন্তু পুরোনো কোড চালু থাকছে। 


এবার আসি আমার প্রথম সল্যুশন (আর তার প্রবলেম) কী ছিল সেই আলোচনায়।  একটা নতুন কলাম যোগ করতে আমি একটা প্রি- ডেপ্লয়মেন্ট স্ক্রিপ্ট লিখলাম এইভাবে :

আমার প্রথম প্রি-ডেপ্লয়মেন্ট স্ক্রিপ্ট

প্রথম চেক করে নিচ্ছি 'Status' নামে অলরেডি কোনো কলাম আমার টার্গেট টেবিলে "Survey_Participants") আছে কিনা। থাকলে আর কিছু করবো না।  কারণ বেস্ট প্র্যাক্টিস -২ অনুযায়ী একই স্ক্রিপ্ট একাধিক বার চালালে কোনো এক্সেপশন যেন না হয় -  অলরেডি কলাম থাকলে নতুন করে কলাম তৈরি করতে গেলে এক্সসেপশন খাবে। আর না থাকলে (যেটা স্বাভাবিক), আমি সিম্পলি 'Status' নামে একটা Int টাইপ not-null কলাম যোগ করছি, আর ডিফল্ট ভ্যালু হিসাবে '1' দিয়ে দিচ্ছি।

রোলব্যাক স্ক্রিপ্ট যেটা কিনা এই যোগ করা নতুন কলাম drop করবে, নিচের মতো করে লিখলাম :

আমার প্রথম প্রি-ডেপ্লয়মেন্ট রোলব্যাক স্ক্রিপ্ট
ঝামেলা হলো রোলব্যাক স্ক্রিপ্ট টেস্ট করতে গিয়ে। রোলব্যাক স্ক্রিপ্ট চালালে সেটা কপ্লেইন করতে লাগলো যে 'Status' কলাম ড্রপ করা যাবে না যদি না আগে ডিফল্ট কন্সট্রেইন্ট ড্রপ না করি !!

মানে কি?

একটু ঘাটাঘাটি করে যেটা বুঝলাম, যোগ করা কলামে কোনো ডিফল্ট ভ্যালু  দিয়ে দিলে (আমি যেমন '1' দিয়ে দিয়েছি)  সিস্টেম ব্যাকগ্রাউন্ডে নিজে থেকেই একটা কন্সট্রেইন্ট যোগ করে দেয়।  এই কন্সট্রেইন্ট -এর আবার একটা নামও সিস্টেম নিজেই দিয়ে দেয় যার শেষে একটা রান্ডম নাম্বার  থাকে। সেটা ড্রপ করেই কেবল কলাম ড্রপ করা যাবে।

ভালো ঝামেলা হলো! প্রোডাকশনে এই রান্ডম নাম্বার কি হবে আমি আগে থেকে জানবো কিভাবে?

আরেকটু ঘাটাঘাটি করে এই লিংক থেকে আইডিয়া পেলাম যে, সিস্টেমের উপর নির্ভর না করে একটা কন্সট্রেইন্ট (আর তার নাম) আমরাই তৈরি করে দিতে পারি।  সেই নাম ব্যবহার করে রোলব্যাক স্ক্রিপ্টে কন্সট্রেইন্ট ড্রপ করে সহজেই কলাম ড্রপ করা যাবে।  সুতরাং,  স্ক্রিপ্ট আর রোলব্যাক স্ক্রিপ্টের পরিবর্তিত চেহারা দাঁড়ালো এই রকম:

 
এসো নিজে কন্সট্রেইন্ট অ্যাড করি :)


আমার কন্সট্রেইন্ট আমি ড্রপ করবো, যেভাবে ইচ্ছা সেভাবে করবো 

আমি খুশি মনে আমার কোড আর SQL স্ক্রিপ্ট পুশ করে, গিট পুল রিকোয়েস্ট করে বসলাম। DBA বা ডেটাবেস এডমিন কে রিভিউয়ার করেছিলাম। সেও এপ্রুভ করে দিলো।  আমি আরেকজন ডেভেলপার রিভিউয়ারের এপ্রোভাল-র  অপেক্ষায় বসে আছি।  কনফিডেন্সের চোটে ভাব নিয়ে QA/Tester -কে জানিয়ে দিলাম, রেডি থাকো আমার কোড 'রেডি ফর টেস্টিং' হচ্ছে একটু পরেই!!

কোম্পানির স্বয়ং চিফ টেকনোলজি অফিসার রিভিউ করে 'Needs work' বলে আমার পুল রিকোয়েস্ট ডিক্লাইন করে বসলেন।

বড় রকমের ঝামেলার যে সবে শুরু তখনো আমি তা আন্দাজ করি নাই।  যাই হোক, সাহস করে উনাকে জিজ্ঞেস করাতে উনি বুঝিয়ে বললেন যে মূল ঝামেলাটা কোথায়। প্রথমতঃ, ডাটাবেসে নতুন ডাটা কোড দিয়ে যোগ করতে হবে, SQL স্ক্রিপ্ট লিখে নয়। এটাই বেস্ট প্র্যাক্টিস-৫। আমি কন্সট্রেইন্ট তৈরি করে 'Status' কলামের ভ্যালু ঠিক করে দিচ্ছি, এটা ঠিক না।  দ্বিত্বীয়ত, আমার এপ্রোচে আসলে উপরের বেস্ট প্র্যাক্টিসের ৪ নম্বরে (ডেপ্লয়মেন্ট প্রসেসে) প্রবলেম হবে।

ব্যাখ্যা করা যাক।  ধরা যাক, ধাপ 'ক' তে আমাদের প্রি-ডেপ্লয়মেন্ট স্ক্রিপ্ট রান করা হলো ঠিক ভাবেই। রোলব্যাক করা লাগলো না।  এখন ধাপ 'খ' তে যাওয়ার আগে (অর্থাৎ, নতুন কোড ডেপ্লয় হওয়ার আগে) সিস্টেমের অবস্থাটা কী হবে দেখা যাক: ডাটাবেসে আমাদের টার্গেট টেবিলে নন-নাল, ডিফল্ট ভ্যালু সহ নতুন কলাম যোগ হয়ে গেছে।  কিন্তু যেহেতু নতুন কোড এখনো ডেপ্লয় হয় নাই, পুরোনো কোড - যাতে কিনা এই নতুন কলাম হ্যান্ডেল করার কোনো কোড নেই, সেটা ব্যবহার করে কোনো ইউসার আমাদের টেবিলে কোনো row অ্যাড করতে গেলেই এক্সসেপশন হবে।  কেননা, পুরোনো কোড এই 'Status' কলামে কিছু অ্যাড করবে না, কিন্তু ডাটাবেসে কন্সট্রেইন্ট হচ্ছে এটা Null হতে পারবে না - সুতরাং এক্সসেপশন!

তাহলে উপায়?

উনি বললেন, প্রি-ডেপ্লয়মেন্ট স্ক্রিপ্টে 'Status' কলামকে Nullable করতে হবে।  তাতে করে পুরোনো কোড ব্যবহার করে কেউ কোনো নতুন row  অ্যাড করলেও এক্সসেপশন হবে না।  আর পোস্ট-ডেপ্লয়মেন্ট স্ক্রিপ্টে (যেটা কিনা নতুন কোড ডেপ্লয় হবার পরের ধাপ -গ তে চালানো হবে) 'Status' কলামের সব Null ভ্যালুকে '1' করে দিয়ে কলামকে 'Not Null' করে দিতে হবে।

ব্যাস হয়ে গেলো। তাই না?  কিন্তু না, হবে না।  আবারো রোলব্যাক স্ক্রিপ্টের বাগড়া! পোস্ট-ডেপ্লয়মেন্ট স্ক্রিপ্টের রোলব্যাক স্ক্রিপ্ট - যা কিনা উল্টো কাজ করবে, অর্থাৎ, 'Status' কলামের সব '1' ভ্যালুকে কে null করে দিয়ে কলামটাকে Nullable করবে  - সেখানে একটা সুক্ষ ঝামেলা হতে পারে।  ভেবে দেখুন তো কি হতে পারে? একটা হিন্টস দেই: কোনো কারণে রোলব্যাক স্ক্রিপ্ট চালানোর আগেই যদি কোনো ইউসার এসে আমাদের টেবিলে কোনো row অ্যাড করে দেয় ঝামেলাটা তখনই হবে।


ধরতে পারলেন? না পারলেও সমস্যা নেই, বুঝিয়ে বলছি।  নতুন কোডে কিন্তু 'Status' কলাম হ্যান্ডলার কোড আছে।  সেটা Active বা '1' ভ্যালু বসিয়ে দিবে।  কিন্তু পোস্ট-ডেপ্লয়মেন্টে রোলব্যাক স্ক্রিপ্ট কিভাবে জানবে যে কোনটা ইউসারের বসানো 1 আর কোনটা স্ক্রিপ্টের বসানো 1? রোলব্যাক স্ক্রিপ্ট তো সব 1 ভ্যালুকেই null করে দিবে, তাই না ? সেটা তো ঠিক হলো না।

এই সমস্যা দূর করতে যা করতে হবে সেটা হচ্ছে : পোস্ট - ডেপ্লয়মেন্ট স্ক্রিপ্টে শুরুতেই, কোনো পরিবর্তনের আগেই আমাদের টার্গেট টেবিলের একটা ব্যাকআপ নিতে হবে।  আর পোস্ট - ডেপ্লয়মেন্ট রোলব্যাক স্ক্রিপ্টে এই ব্যাকআপ টেবিল রিস্টোর করতে হবে।  তাতে করে ইউসারের অ্যাড করা row হয়তো থাকবে না, কিন্তু ডাটাবেসের টেবিলে কোনো ভুল স্টেট থাকছে না।

মাথায় ঢুকছে না? মাথা ঘুরছে? তাহলে আর ডিটেইলসে না গিয়ে ফাইনাল প্রি- আর পোস্ট ডেপ্লয়মেন্ট স্ক্রিপ্ট আর তাদের রোলব্যাক স্ক্রিপ্ট গুলো দিয়ে নিচে দিচ্ছি। স্ক্রিপ্টে কমেন্ট করা আছে, আশা করি পড়ে বুঝতে পারবেন।


ফাইনাল প্রি-ডেপ্লয়মেন্ট স্ক্রিপ্ট 


ফাইনাল প্রি-ডেপ্লয়মেন্ট রোলব্যাক স্ক্রিপ্ট

ফাইনাল পোস্ট-ডেপ্লয়মেন্ট স্ক্রিপ্ট


ফাইনাল পোস্ট-ডেপ্লয়মেন্ট রোলব্যাক স্ক্রিপ্ট

একটা জিনিস খেয়াল করিয়ে দেই: ব্যাকআপ টেবিল রিস্টোর করার আগে কিন্তু মূল টেবিলের (যদি টেবিলে প্রাইমারি কী থাকে) সব ডেটা ডিলিট করতে হবে ।  তা না হলে, রিস্টোর করার সময় row এপেন্ড হয়ে আবার ডুপ্লিকেট কী কপি হয়ে যাচ্ছে বলে সিস্টেম কমপ্লেইন করবে, এরর খাবে।

আর পরের সপ্তাহে মনে করে ব্যাকআপ ডামি টেবিলটা ড্রপ করতে হবে। সেজন্য আবার একটা প্রি ডেপ্লয়মেন্ট স্ক্রিপ্ট লিখতে হবে।  এই স্ক্রিপ্টের রোলব্যাক বলে আদতে কোনো স্ক্রিপ্ট থাকবে না, বাঁচা গেলো। কিন্তু নিয়ম রক্ষার্থে একটা এম্পটি (শুধু কমেন্ট করা) রোলব্যাক স্ক্রিপ্ট নাকি লিখতে হবে!! DBA রা নাকি নাহলে ঝামেলা করতে পারে!

একটা সামান্য কলাম অ্যাড করা নিয়ে যে এতো ঝামেলা হবে কে জানতো!

যাক সুখবর হলো: আমার কোড ১৩ কমিটের পরে ফাইনালি এপ্রুভ হয়ে মার্জ হয়েছে। আহ শান্তি!

সবশেষে আমার শিক্ষণীয়:
১. ডেভেলপমেন্টে কোনো কাজই ছোট না।  এস্টিমেট করার সময় যেকোনো কাজকেই সমীহ করতে হবে।
২. সাত-পাঁচ ভেবে, দরকার হলে অন্য ডেভেলপারদের সাথে আলাপ করে তবেই কোড সাবমিট করতে হবে, পুল রিকোয়েস্ট করতে হবে। নতুবা অসংখ্যবার কোড কমিট করতে হতে পারে।
৩. QA বা অন্যদের সাথে ভাব নেয়া যাবে না। আমার কোডে কোনো ঝামেলা নেই - কোড এপ্রুভ হয়ে মার্জ হওয়া  ১ ,২, ৩ ব্যাপার - টাইপ ভাব নেয়াটা খুবই খারাপ।

ধন্যবাদ। 

1 comment:

  1. Great post I would like to thank you for the efforts you have made in writing this interesting and knowledgeable article.
    will help you more:
    谷歌优化,baidu seo,谷歌seo,外贸网站建设,独立站引流,海外推广,web development outsourcing China ,web design ,web design China,谷歌推广,外贸英文网站建设,谷歌优化最牛的公司,谷歌排名,英文网站翻译,西安facebook营销,上海谷歌优化,上海谷歌seo,北京谷歌优化,facebook,北京谷歌seo
    外贸建站 推广

    ReplyDelete

কাজের জায়গায় ভুল থেকে শেখা: regex 'র একটা খুব কমন বিষয় যেটা এতদিন ভুল জানতাম

কাজের জায়গায় ভুল থেকে শেখা: regex 'র একটা খুব কমন বিষয় যেটা এতদিন ভুল জানতাম  ৩ ফেব্রুয়ারি, শনিবার, ২০২৪ রেগুলার এক্সপ্রেশন (Regular Exp...