এটি সকলের সাথে হয়। সফটওয়্যার প্রজেক্ট বড় হলে, কোডবেসের অংশগুলো প্রোডাকশনে চলে যায় একটি কম্প্রিহেনসিভ টেস্ট স্যুট ছাড়া। কয়েক ماه পর আপনি যখন কোডের একই এলিয়ায়ে আবার তাকান, তবে সেটা বুঝতে কঠিন হতে পারে; আরও খারাপ, সেখানে একটি বাগ থাকতে পারে, এবং আমরা জানি না কোথায় থেকে ফিক্স শুরু করব।
টেস্ট ছাড়া কোড মডিফাই করা একটি বড় চ্যালেঞ্জ। আমরা নিশ্চিত হতে পারি না আমরা কী ব্রেক করব প্রসেসে, এবং সব কিছু ম্যানুয়ালি চেক করা, সেরা কেসে, মিস্টেক-প্রোন; সাধারণত, অসম্ভব।
এই ধরণের কোড ডিল করা ডেভেলপাররা যেসব সবচেয়ে কমন টাস্ক পারফর্ম করে, এবং বছরের পর বছর অনেক টেকনিক এই ইস্যুতে ফোকাস করেছে, যেমন ক্যারাক্টারাইজেশন টেস্ট, যা আমরা একটি পূর্ববর্তী আর্টিকেলে আলোচনা করেছি।
আজ, আমরা আরেকটি টেকনিক কভার করব যা ক্যারাক্টারাইজেশন টেস্টের ওপর ভিত্তি করে এবং কেন্ট বেক দ্বারা প্রস্তাবিত, যিনি বহু বছর আগে মডার্ন প্রোগ্রামিং ওয়ার্ল্ডে TDD প্রবর্তন করেছিলেন।
TCR কী?
TCR মানে "টেস্ট, কমিট, রিভার্ট", তবে এর আরও সঠিক নাম হবে "টেস্ট && কমিট || রিভার্ট"। দেখুন কেন।
এই টেকনিক লিগ্যাসি কোড টেস্ট করার একটি ওয়ার্কফ্লো বর্ণনা করে। আমরা একটি স্ক্রিপ্ট ব্যবহার করব যা প্রজেক্ট ফাইলগুলো সেভ করার 때마다 টেস্ট রান করবে। প্রসেসটি নিচের মতো:
- প্রথম, আমরা লিগ্যাসি কোডের যে অংশটি টেস্ট করতে চাই সেটার জন্য একটি খালি ইউনিট টেস্ট তৈরি করি।
- তারপর, আমরা একটি সিংগল অ্যাসারশন যোগ করি এবং টেস্টটি সেভ করি।
- যেহেতু আমাদের স্ক্রিপ্ট সেট আপ করা আছে, টেস্ট অটোমেটিক্যালি রান হবে। যদি এটি সফল হয়, তবে চেঞ্জটি কমিট হবে। যদি ফেইল করে, তবে চেঞ্জটি ডিলিট হবে (রিভার্ট), এবং আমাদের আবার চেষ্টা করতে হবে।
একবার টেস্ট পাস করলে, আমরা তারপর একটি নতুন টেস্ট কেস যোগ করতে পারি।
অসলে, TCR হলো আপনার কোডকে একটি "গ্রিন" স্টেটে রাখা বরং একটি ফেইলিং টেস্ট লিখে (রেড) এবং তারপর পাস করানো (গ্রিন), যেন আমরা টেস্ট-ড্রাইভেন ডেভেলপমেন্টে করি। আপনি যদি একটি ফেইলিং টেস্ট লিখেন, তবে সেটা শুধু গায়েব হয়ে যাবে, এবং আপনাকে আবার "গ্রিন" স্টেটে ফেরত আনবে।
উদ্দেশ্য
এই টেকনিকের মূল লক্ষ্য হলো প্রতিবার একটি টেস্ট কেস যোগ করার সাথে সাথে কোডটিকে একটু ভালোভাবে বুঝতে। এটি স্বাভাবিকভাবেই টেস্ট কভারেজ বাড়াবে এবং অনেক রিফ্যাক্টরিং আনব্লক করবে যা অন্যথায় সম্ভব হতো না।
TCR-এর একটি সুবিধা হলো এটি অনেক সিনেরিওতে উপযোগী। আমরা এটাকে কোড যা কোনো টেস্ট নেই সেটার সাথে বা আংশিকভাবে টেস্ট করা কোডের সাথে ব্যবহার করতে পারি। যদি টেস্ট পাস না করে, তবে আমরা শুধু চেঞ্জটি রিভার্ট করি এবং আবার চেষ্টা করি।
আমরা কীভাবে এটি ব্যবহার করতে পারি?
কেন্ট বেক আলাদা আর্টিকেল এবং ভিডিওতে (শেষে লিংক করা আছে) দেখিয়েছেন যে, একটি ভালো পদ্ধতি হলো একটি স্ক্রিপ্ট ব্যবহার করা যা নির্দিষ্ট প্রজেক্ট ফাইল সেভ হওয়ার পর রান করে।
এটি প্রজেক্টের ওপর অনেক বেশি ডিপেন্ড করবে যেটি আপনি টেস্ট করার চেষ্টা করছেন। নিচের মত একটি স্ক্রিপ্ট, যা এক্সিকিউট হয় প্রতিবার আমরা এক্সটেনশন দিয়ে এডিটরে ফাইল সেভ করলে, একটি ভালো শুরু:
(rspec && git commit -am "WIP") || git reset --hard
আপনি যদি ভিজ্যুয়াল স্টুডিও কোড ব্যবহার করেন, তবে "runonsave" একটি ভালো প্লাগইন যা প্রতিবার সেভে এক্সিকিউট করে। আপনি উপরের কমান্ড বা আপনার প্রজেক্টের জন্য সিমিলার একটি কমান্ড ইনক্লুড করতে পারেন। এই কেসে, পুরো কনফিগ ফাইল হবে
{ "folders": [{ "path": "." }], "settings": { "emeraldwalk.runonsave": { "commands": [ { "match": "*.rb", "cmd": "cd ${workspaceRoot} && rspec && git commit -am WIP || git reset --hard" } ] } } }
মনে রাখবেন যে পরে, আপনি কমিট স্কোয়াশ করতে পারেন গিট দিয়ে সরাসরি কমান্ড লাইনে বা PR মержа করার সময় যদি আপনি গিটহাব ব্যবহার করেন:
.
এর মানে আমরা মেইন ব্রাঞ্চে শুধু একটি কমিট পাবো আমাদের ব্রাঞ্চে করা সকল কমিটের জন্য যেটিতে আমরা কাজ করছি। গিটহাব থেকে এই ডায়াগ্রামটি ভালোভাবে এক্সপ্লেইন করে:
.
TCR-এ আমাদের প্রথম টেস্ট লিখা
আমরা একটি সিম্পল উদাহরণ ব্যবহার করব টেকনিকটি ইলাস্ট্রেট করার জন্য। আমাদের একটি ক্লাস আছে যা আমরা জানি কাজ করছে, কিন্তু আমাদের এটাকে মডিফাই করতে হবে।
আমরা শুধু একটি চেঞ্জ করতে পারতাম এবং চেঞ্জগুলো ডিপ্লয় করতে পারতাম। কিন্তু, আমরা নিশ্চিত হতে চাই যে প্রসেসে আমরা কিছু ব্রেক করছি না, যা সবসময় একটি ভালো আইডিয়া।
# worker.rb class Worker def initialize(age, active_years, veteran) @age = age @active_years = active_years @veteran = veteran end def can_retire? return true if @age >= 67 return true if @active_years >= 30 return true if @age >= 60 && @active_years >= 25 return true if @veteran && @active_years > 25 false end end
প্রথম স্টেপ হবে টেস্টের জন্য একটি নতুন ফাইল তৈরি করা, যাতে আমরা সেখানে টেস্ট যোগ করা শুরু করতে পারি। আমরা can_retire? মেথডের প্রথম লাইনটি দেখেছি
def can_retire? return true if @age >= 67 ... ... end
তাই, আমরা এই কেসটি প্রথমে টেস্ট করতে পারি:
# specs/worker_spec.rb require_relative './../worker' describe Worker do describe 'can_retire?' do it "should return true if age is higher than 67" do end end end
এখানে একটি কুইক টিপ: TCR-এ কাজ করার সময়, প্রতিবার সেভ করলে, লেটেস্ট চেঞ্জগুলো গায়েব হয়ে যাবে যদি টেস্টগুলো পাস না করে। তাই, আমরা যতটা সম্ভব কোড "সেট আপ" করার জন্য টেস্টের আগে রাখতে চাই আসলে অ্যাসারশনের লাইন বা লাইনগুলো লিখে সেভ করার আগে।
আমরা উপরের ফাইলটি সেভ করলে, তারপর টেস্টের জন্য একটি লাইন যোগ করতে পারি।
require_relative './../worker' describe Worker do describe 'can_retire?' do it "should return true if age is higher than 67" do expect(Worker.new(70, 10, false).can_retire?).to be_true ## এই লাইন সেভ করার সময় গায়েব হয়ে যেতে পারে এখন end end end
যখন আমরা সেভ করি, যদি নতুন লাইন গায়েব না হয়, তবে আমরা ভালো কাজ করেছি; টেস্ট পাস করেছে!
আরও টেস্ট যোগ করা
একবার আমাদের প্রথম টেস্ট হলে, আমরা আরও কেস যোগ করতে পারি ফ্যালস কেসগুলো ধরে রেখে। কিছু কাজ করার পর, আমাদের এরকম কিছু থাকবে:
# frozen_string_literal: true require_relative './../worker' describe Worker do describe 'can_retire?' do it 'should return true if age is higher than 67' do expect(Worker.new(70, 10, false).can_retire?).to be true end it 'should return true if age is 67' do expect(Worker.new(67, 10, false).can_retire?).to be true end it 'should return true if age is less than 67' do expect(Worker.new(50, 10, false).can_retire?).to be false end it 'should return true if active years is higher than 30' do expect(Worker.new(60, 31, false).can_retire?).to be true end it 'should return true if active years is 30' do expect(Worker.new(60, 30, false).can_retire?).to be true end end end
প্রতিটি কেসে, আমরা "it" ব্লকটি প্রথম লিখি, সেভ করি, এবং তারপর expect(...) দিয়ে অ্যাসারশন যোগ করি।
স্বাভাবিকভাবেই, আমরা যতটা চাই ততটুকু টেস্ট যোগ করতে পারি, তবে একবার আমরা יחসত নিশ্চিত হয়ে যাই সবকিছু কভার করা হয়েছে, তারপর বেশি টেস্ট যোগ করা যৌক্তিক নয়।
এখনও কিছু কেস কভার করতে বাকি, তাই সম্পূর্ণতার জন্য সেগুলো যোগ করি।
চূড়ান্ত টেস্ট
এখানে স্পেস ফাইলটি তার চূড়ান্ত রূপে। আপনি দেখতে পাচ্ছেন, আমরা এখনও আরও কেস যোগ করতে পারতাম, কিন্তু আমি মনে করি এটি TCR প্রসেস ইলাস্ট্রেট করার জন্য যথেষ্ট।
# frozen_string_literal: true require_relative './../worker' describe Worker do describe 'can_retire?' do it 'should return true if age is higher than 67' do expect(Worker.new(70, 10, false).can_retire?).to be true end it 'should return true if age is 67' do expect(Worker.new(67, 10, false).can_retire?).to be true end it 'should return true if age is less than 67' do expect(Worker.new(50, 10, false).can_retire?).to be false end it 'should return true if active years is higher than 30' do expect(Worker.new(60, 31, false).can_retire?).to be true end it 'should return true if active years is 30' do expect(Worker.new(20, 30, false).can_retire?).to be true end it 'should return true if age is higher than 60 and active years is higher than 25' do expect(Worker.new(60, 30, false).can_retire?).to be true end it 'should return true if age is higher than 60 and active years is higher than 25' do expect(Worker.new(61, 30, false).can_retire?).to be true end it 'should return true if age is 60 and active years is higher than 25' do expect(Worker.new(60, 30, false).can_retire?).to be true end it 'should return true if age is higher than 60 and active years is 25' do expect(Worker.new(61, 25, false).can_retire?).to be true end it 'should return true if age is 60 and active years is 25' do expect(Worker.new(60, 25, false).can_retire?).to be true end it 'should return true if is veteran and active years is higher than 25' do expect(Worker.new(60, 25, false).can_retire?).to be true end end end
রিফ্যাক্টর করার পথগুলো
আপনি যদি এতক্ষণ পড়েছেন, তবে সম্ভবত কিছু অদ্ভুত লাগছে কোডের সাথে। আমাদের অনেক "ম্যাজিক্যাল নাম্বার" আছে যা কনস্ট্যান্টে এক্সট্রাক্ট করা উচিত, টেস্ট এবং Worker ক্লাস দুটোতে।
আমরা মেইন can_retire? পাবলিক মেথডের প্রতিটি কেসের জন্য প্রাইভেট মেথডও তৈরি করতে পারি।
আমি উভয় সম্ভাব্য রিফ্যাক্টরিং আপনার জন্য এক্সারসাইজ হিসেবে রেখে দিচ্ছি। কিন্তু, এখন আমাদের টেস্ট আছে, তাই আপনি যদি কোনো স্টেপে মিস্টেক করেন, সেগুলো আপনাকে জানাবে।
উপসংহার
আপনি TCR আপনার প্রজেক্টের সাথে ট্রাই করার জন্য আমি উৎসাহিত করছি। এটি খুব সস্তা এক্সপেরিমেন্ট কারণ আপনাকে কোনো ফ্যান্সি সিআই এক্সটার্নাল সার্ভারে বা নতুন লাইব্রেরির সাথে ডিপেন্ডেন্সি লাগে না। আপনার কম্পিউটারে নির্দিষ্ট ফাইল সেভ হওয়ার সাথে সাথে একটি কমান্ড এক্সিকিউট করার উপায় থাকলেই হবে।
এটি আপনাকে টেস্ট যোগ করার সময় একটি "গেমিং" এক্সপেরিয়েন্স দেবে, যা সবসময় ফান এবং ইন্ড্রেস্টিং। এডিশনালি, ফেইলিং টেস্ট আপনার এডিটর থেকে রিমুভ হওয়ার ডিসিপ্লিন আপনাকে একটি এক্সট্রা সেফটি নেট দেবে কনফার্ম করে যে আপনি রিপোজিটরিতে যেসব টেস্ট পশ করছেন সেগুলো পাস করছে।
আশা করি লিগ্যাসি কোড ডিল করার সময় আপনি এই নতুন টেকনিকটি উপযোগী পাবেন। আমি গত কয়েক মাসে একাধিকবার ব্যবহার করেছি, এবং এটি সবসময় এক্টু 플েজার দিয়েছে।
এক্সট্রা রিসোর্স
- ভালো ভিডিও ইন্ট্রোডাকশন হিসেবে।
- কেন্ট বেকের TCR ভিএস কোডে কীভাবে ব্যবহার করবেন সেটা নিয়ে মতামত।
- ভিএস কোডের প্লাগইন সেভে স্ক্রিপ্ট রান করার জন্য।