জাভাস্ক্রিপ্টে টেস্ট-ড্রিভেন ডেভেলপমেন্ট (TDD) আয়ত্ত করুন। এই সম্পূর্ণ নির্দেশিকাটি রেড-গ্রিন-রিফ্যাক্টর চক্র, Jest-এর সাথে বাস্তবায়ন, এবং আধুনিক ডেভেলপমেন্টের সেরা অনুশীলনগুলি তুলে ধরে।
জাভাস্ক্রিপ্টে টেস্ট-ড্রিভেন ডেভেলপমেন্ট: বিশ্বব্যাপী ডেভেলপারদের জন্য একটি সম্পূর্ণ নির্দেশিকা
এই দৃশ্যটি কল্পনা করুন: আপনাকে একটি বিশাল, পুরনো সিস্টেমের একটি গুরুত্বপূর্ণ কোড পরিবর্তন করার দায়িত্ব দেওয়া হয়েছে। আপনি এক ধরনের আতঙ্কে ভুগছেন। আপনার পরিবর্তন কি অন্য কিছু ভেঙে দেবে? সিস্টেমটি এখনও উদ্দেশ্য অনুযায়ী কাজ করছে কিনা তা আপনি কীভাবে নিশ্চিত হবেন? পরিবর্তনের এই ভয় সফটওয়্যার ডেভেলপমেন্টের একটি সাধারণ সমস্যা, যা প্রায়শই ধীর অগ্রগতি এবং ভঙ্গুর অ্যাপ্লিকেশনের দিকে পরিচালিত করে। কিন্তু যদি এমন কোনো উপায় থাকতো যার মাধ্যমে আত্মবিশ্বাসের সাথে সফটওয়্যার তৈরি করা যায়, একটি সুরক্ষা বলয় তৈরি করা যায় যা প্রোডাকশনে পৌঁছানোর আগেই ত্রুটিগুলি ধরে ফেলে? এটাই হলো টেস্ট-ড্রিভেন ডেভেলপমেন্ট (TDD)-এর প্রতিশ্রুতি।
TDD শুধুমাত্র একটি টেস্টিং কৌশল নয়; এটি সফটওয়্যার ডিজাইন এবং ডেভেলপমেন্টের একটি শৃঙ্খলাবদ্ধ পদ্ধতি। এটি প্রচলিত "আগে কোড লিখুন, তারপর পরীক্ষা করুন" মডেলটিকে উল্টে দেয়। TDD-এর মাধ্যমে, প্রোডাকশন কোড লেখার আগে আপনি একটি টেস্ট লেখেন যা ব্যর্থ হয়। এই সাধারণ পরিবর্তনটি কোডের গুণমান, ডিজাইন এবং রক্ষণাবেক্ষণের উপর গভীর প্রভাব ফেলে। এই নির্দেশিকাটি জাভাস্ক্রিপ্টে TDD বাস্তবায়নের একটি ব্যাপক, ব্যবহারিক দিক তুলে ধরবে, যা পেশাদার ডেভেলপারদের বিশ্বব্যাপী দর্শকদের জন্য ডিজাইন করা হয়েছে।
টেস্ট-ড্রিভেন ডেভেলপমেন্ট (TDD) কী?
এর মূল ভিত্তি হলো, টেস্ট-ড্রিভেন ডেভেলপমেন্ট একটি ডেভেলপমেন্ট প্রক্রিয়া যা খুব ছোট একটি ডেভেলপমেন্ট চক্রের পুনরাবৃত্তির উপর নির্ভর করে। ফিচার লিখে তারপর পরীক্ষা করার পরিবর্তে, TDD জোর দেয় যে টেস্টটি প্রথমে লেখা হবে। এই টেস্টটি অনিবার্যভাবে ব্যর্থ হবে কারণ ফিচারটির কোনো অস্তিত্বই নেই। এরপর ডেভেলপারের কাজ হলো সেই নির্দিষ্ট টেস্টটি পাস করানোর জন্য সবচেয়ে সহজ কোড লেখা। একবার এটি পাস হয়ে গেলে, কোডটি পরিষ্কার এবং উন্নত করা হয়। এই মৌলিক লুপটি 'রেড-গ্রিন-রিফ্যাক্টর' চক্র হিসাবে পরিচিত।
TDD-এর ছন্দ: রেড-গ্রিন-রিফ্যাক্টর
এই তিন-ধাপের চক্রটি হলো TDD-এর হৃদস্পন্দন। এই ছন্দ বোঝা এবং অনুশীলন করা এই কৌশলটি আয়ত্ত করার জন্য মৌলিক।
- 🔴 রেড — একটি ব্যর্থ টেস্ট লিখুন: আপনি একটি নতুন কার্যকারিতার জন্য একটি স্বয়ংক্রিয় টেস্ট লেখার মাধ্যমে শুরু করেন। এই টেস্টটি সংজ্ঞায়িত করবে যে আপনি কোডটি দিয়ে কী করাতে চান। যেহেতু আপনি এখনও কোনো ইমপ্লিমেন্টেশন কোড লেখেননি, তাই এই টেস্টটি ব্যর্থ হতে বাধ্য। একটি ব্যর্থ টেস্ট কোনো সমস্যা নয়; এটি অগ্রগতি। এটি প্রমাণ করে যে টেস্টটি সঠিকভাবে কাজ করছে (এটি ব্যর্থ হতে পারে) এবং পরবর্তী পদক্ষেপের জন্য একটি স্পষ্ট, সুনির্দিষ্ট লক্ষ্য নির্ধারণ করে।
- 🟢 গ্রিন — পাস করার জন্য সবচেয়ে সহজ কোড লিখুন: আপনার লক্ষ্য এখন একটাই: টেস্টটি পাস করানো। টেস্টটিকে রেড থেকে গ্রিন করতে আপনার একেবারে ন্যূনতম প্রোডাকশন কোড লিখতে হবে। এটি অদ্ভুত মনে হতে পারে; কোডটি হয়তো সুন্দর বা কার্যকর নাও হতে পারে। তাতে কিছু আসে যায় না। এখানে একমাত্র ফোকাস হলো টেস্ট দ্বারা সংজ্ঞায়িত প্রয়োজনীয়তা পূরণ করা।
- 🔵 রিফ্যাক্টর — কোড উন্নত করুন: এখন যেহেতু আপনার কাছে একটি পাস করা টেস্ট আছে, আপনার একটি সুরক্ষা বলয় রয়েছে। আপনি কার্যকারিতা ভাঙার ভয় ছাড়াই আত্মবিশ্বাসের সাথে আপনার কোড পরিষ্কার এবং উন্নত করতে পারেন। এখানেই আপনি কোড স্মেল (code smells), ডুপ্লিকেশন দূর করা, স্পষ্টতা বৃদ্ধি এবং পারফরম্যান্স অপ্টিমাইজ করার কাজ করেন। আপনি রিফ্যাক্টরিংয়ের সময় যেকোনো মুহূর্তে আপনার টেস্ট স্যুট চালাতে পারেন যাতে নিশ্চিত হওয়া যায় যে আপনি কোনো রিগ্রেশন ঘটাননি। রিফ্যাক্টরিংয়ের পরে, সমস্ত টেস্ট এখনও গ্রিন থাকা উচিত।
একবার একটি ছোট কার্যকারিতার জন্য চক্রটি সম্পূর্ণ হলে, আপনি পরবর্তী অংশের জন্য একটি নতুন ব্যর্থ টেস্ট দিয়ে আবার শুরু করেন।
TDD-এর তিনটি নিয়ম
রবার্ট সি. মার্টিন (যিনি "আঙ্কেল বব" নামে পরিচিত), অ্যাজাইল সফটওয়্যার আন্দোলনের একজন গুরুত্বপূর্ণ ব্যক্তিত্ব, তিনটি সহজ নিয়ম সংজ্ঞায়িত করেছেন যা TDD শৃঙ্খলাকে বিধিবদ্ধ করে:
- একটি ব্যর্থ ইউনিট টেস্ট পাস করানোর প্রয়োজন না হলে আপনি কোনো প্রোডাকশন কোড লিখবেন না।
- একটি ইউনিট টেস্ট ব্যর্থ করার জন্য যতটুকু প্রয়োজন, তার চেয়ে বেশি লিখবেন না; এবং কম্পাইলেশন ব্যর্থতাও একটি ব্যর্থতা।
- একটি ব্যর্থ ইউনিট টেস্ট পাস করার জন্য যতটুকু প্রয়োজন, তার চেয়ে বেশি প্রোডাকশন কোড লিখবেন না।
এই নিয়মগুলি অনুসরণ করা আপনাকে রেড-গ্রিন-রিফ্যাক্টর চক্রে বাধ্য করে এবং নিশ্চিত করে যে আপনার ১০০% প্রোডাকশন কোড একটি নির্দিষ্ট, পরীক্ষিত প্রয়োজনীয়তা পূরণের জন্য লেখা হয়েছে।
আপনার কেন TDD গ্রহণ করা উচিত? বিশ্বব্যাপী ব্যবসায়িক প্রেক্ষাপট
যদিও TDD স্বতন্ত্র ডেভেলপারদের জন্য বিশাল উপকারিতা প্রদান করে, এর আসল শক্তি দল এবং ব্যবসায়িক স্তরে উপলব্ধি করা যায়, বিশেষ করে বিশ্বব্যাপী বিস্তৃত পরিবেশে।
- আত্মবিশ্বাস এবং গতি বৃদ্ধি: একটি সম্পূর্ণ টেস্ট স্যুট একটি সুরক্ষা বলয় হিসাবে কাজ করে। এটি দলগুলিকে আত্মবিশ্বাসের সাথে নতুন ফিচার যোগ করতে বা বিদ্যমান ফিচার রিফ্যাক্টর করতে দেয়, যা একটি উচ্চতর টেকসই ডেভেলপমেন্ট গতির দিকে পরিচালিত করে। আপনি ম্যানুয়াল রিগ্রেশন টেস্টিং এবং ডিবাগিংয়ে কম সময় ব্যয় করেন এবং ভ্যালু ডেলিভারি করতে বেশি সময় পান।
- উন্নত কোড ডিজাইন: প্রথমে টেস্ট লেখা আপনাকে ভাবতে বাধ্য করে যে আপনার কোড কীভাবে ব্যবহৃত হবে। আপনি আপনার নিজের API-এর প্রথম ব্যবহারকারী। এটি স্বাভাবিকভাবেই ছোট, আরও ফোকাসড মডিউল এবং উদ্বেগের স্পষ্ট বিভাজন সহ আরও ভাল-ডিজাইন করা সফটওয়্যারের দিকে পরিচালিত করে।
- জীবন্ত ডকুমেন্টেশন: বিভিন্ন সময় অঞ্চল এবং সংস্কৃতিতে কাজ করা একটি বিশ্বব্যাপী দলের জন্য, স্পষ্ট ডকুমেন্টেশন অত্যন্ত গুরুত্বপূর্ণ। একটি ভালভাবে লেখা টেস্ট স্যুট হলো জীবন্ত, এক্সিকিউটেবল ডকুমেন্টেশনের একটি রূপ। একজন নতুন ডেভেলপার টেস্টগুলো পড়ে বুঝতে পারে যে একটি কোডের ঠিক কী করার কথা এবং বিভিন্ন পরিস্থিতিতে এটি কীভাবে আচরণ করে। প্রচলিত ডকুমেন্টেশনের মতো, এটি কখনও পুরানো হতে পারে না।
- মালিকানার মোট ব্যয় (TCO) হ্রাস: ডেভেলপমেন্ট চক্রের প্রথম দিকে ধরা পড়া বাগগুলি প্রোডাকশনে পাওয়া বাগগুলির চেয়ে বহুগুণে সস্তায় ঠিক করা যায়। TDD একটি শক্তিশালী সিস্টেম তৈরি করে যা সময়ের সাথে রক্ষণাবেক্ষণ এবং প্রসারিত করা সহজ, যা সফটওয়্যারের দীর্ঘমেয়াদী TCO হ্রাস করে।
আপনার জাভাস্ক্রিপ্ট TDD এনভায়রনমেন্ট সেট আপ করা
জাভাস্ক্রিপ্টে TDD শুরু করার জন্য আপনার কয়েকটি টুলের প্রয়োজন। আধুনিক জাভাস্ক্রিপ্ট ইকোসিস্টেম চমৎকার বিকল্প সরবরাহ করে।
একটি টেস্টিং স্ট্যাকের মূল উপাদান
- টেস্ট রানার: একটি প্রোগ্রাম যা আপনার টেস্টগুলি খুঁজে বের করে এবং চালায়। এটি কাঠামো প্রদান করে (যেমন `describe` এবং `it` ব্লক) এবং ফলাফল রিপোর্ট করে। Jest এবং Mocha দুটি সবচেয়ে জনপ্রিয় বিকল্প।
- অ্যাসারশন লাইব্রেরি: একটি টুল যা আপনার কোড প্রত্যাশা অনুযায়ী আচরণ করছে কিনা তা যাচাই করার জন্য ফাংশন সরবরাহ করে। এটি আপনাকে `expect(result).toBe(true)` এর মতো স্টেটমেন্ট লিখতে দেয়। Chai একটি জনপ্রিয় স্বতন্ত্র লাইব্রেরি, যেখানে Jest-এর নিজস্ব শক্তিশালী অ্যাসারশন লাইব্রেরি অন্তর্ভুক্ত রয়েছে।
- মকিং লাইব্রেরি: API কল বা ডাটাবেস সংযোগের মতো নির্ভরতাগুলির "নকল" (fakes) তৈরি করার একটি টুল। এটি আপনাকে আপনার কোডকে বিচ্ছিন্নভাবে পরীক্ষা করতে দেয়। Jest-এর চমৎকার বিল্ট-ইন মকিং ক্ষমতা রয়েছে।
এর সরলতা এবং অল-ইন-ওয়ান প্রকৃতির জন্য, আমরা আমাদের উদাহরণগুলির জন্য Jest ব্যবহার করব। এটি এমন দলগুলির জন্য একটি চমৎকার পছন্দ যারা একটি "জিরো-কনফিগারেশন" অভিজ্ঞতা খুঁজছেন।
Jest দিয়ে ধাপে ধাপে সেটআপ
চলুন TDD-এর জন্য একটি নতুন প্রজেক্ট সেট আপ করি।
১. আপনার প্রজেক্ট শুরু করুন: আপনার টার্মিনাল খুলুন এবং একটি নতুন প্রজেক্ট ডিরেক্টরি তৈরি করুন।
mkdir js-tdd-project
cd js-tdd-project
npm init -y
২. Jest ইনস্টল করুন: আপনার প্রজেক্টে Jest-কে একটি ডেভেলপমেন্ট ডিপেন্ডেন্সি হিসাবে যোগ করুন।
npm install --save-dev jest
৩. টেস্ট স্ক্রিপ্ট কনফিগার করুন: আপনার `package.json` ফাইলটি খুলুন। `"scripts"` বিভাগটি খুঁজুন এবং `"test"` স্ক্রিপ্টটি পরিবর্তন করুন। একটি `"test:watch"` স্ক্রিপ্ট যোগ করারও খুব সুপারিশ করা হয়, যা TDD ওয়ার্কফ্লোর জন্য অমূল্য।
"scripts": {
"test": "jest",
"test:watch": "jest --watchAll"
}
`--watchAll` ফ্ল্যাগটি Jest-কে বলে যে কোনো ফাইল সেভ হলেই স্বয়ংক্রিয়ভাবে টেস্ট পুনরায় চালাতে। এটি তাৎক্ষণিক ফিডব্যাক প্রদান করে, যা রেড-গ্রিন-রিফ্যাক্টর চক্রের জন্য উপযুক্ত।
এটাই! আপনার এনভায়রনমেন্ট প্রস্তুত। Jest স্বয়ংক্রিয়ভাবে `*.test.js`, `*.spec.js` নামের বা `__tests__` ডিরেক্টরিতে অবস্থিত টেস্ট ফাইলগুলি খুঁজে নেবে।
অনুশীলনে TDD: একটি `CurrencyConverter` মডিউল তৈরি করা
আসুন TDD চক্রটি একটি ব্যবহারিক, বিশ্বব্যাপী বোধগম্য সমস্যায় প্রয়োগ করি: মুদ্রাগুলির মধ্যে অর্থ রূপান্তর। আমরা ধাপে ধাপে একটি `CurrencyConverter` মডিউল তৈরি করব।
প্রথম পুনরাবৃত্তি: সহজ, নির্দিষ্ট হারের রূপান্তর
🔴 রেড: প্রথম ব্যর্থ টেস্টটি লিখুন
আমাদের প্রথম প্রয়োজন হলো একটি নির্দিষ্ট পরিমাণ অর্থকে একটি নির্দিষ্ট হারে এক মুদ্রা থেকে অন্য মুদ্রায় রূপান্তর করা। `CurrencyConverter.test.js` নামে একটি নতুন ফাইল তৈরি করুন।
// CurrencyConverter.test.js
const CurrencyConverter = require('./CurrencyConverter');
describe('CurrencyConverter', () => {
it('should convert an amount from USD to EUR correctly', () => {
// Arrange
const amount = 10; // 10 USD
const expected = 9.2; // ধরা যাক, নির্দিষ্ট হার 1 USD = 0.92 EUR
// Act
const result = CurrencyConverter.convert(amount, 'USD', 'EUR');
// Assert
expect(result).toBe(expected);
});
});
এখন, আপনার টার্মিনাল থেকে টেস্ট ওয়াচারটি চালান:
npm run test:watch
টেস্টটি দর্শনীয়ভাবে ব্যর্থ হবে। Jest `TypeError: Cannot read properties of undefined (reading 'convert')` এর মতো কিছু রিপোর্ট করবে। এটি আমাদের রেড অবস্থা। টেস্টটি ব্যর্থ হয়েছে কারণ `CurrencyConverter`-এর অস্তিত্ব নেই।
🟢 গ্রিন: পাস করার জন্য সবচেয়ে সহজ কোড লিখুন
এখন, চলুন টেস্টটি পাস করাই। `CurrencyConverter.js` তৈরি করুন।
// CurrencyConverter.js
const rates = {
USD: {
EUR: 0.92
}
};
const CurrencyConverter = {
convert(amount, from, to) {
return amount * rates[from][to];
}
};
module.exports = CurrencyConverter;
আপনি এই ফাইলটি সেভ করার সাথে সাথেই, Jest টেস্টটি পুনরায় চালাবে এবং এটি গ্রিন হয়ে যাবে। আমরা টেস্টের প্রয়োজনীয়তা পূরণের জন্য একেবারে ন্যূনতম কোড লিখেছি।
🔵 রিফ্যাক্টর: কোড উন্নত করুন
কোডটি সহজ, কিন্তু আমরা এখনই উন্নতির কথা ভাবতে পারি। নেস্টেড `rates` অবজেক্টটি কিছুটা অনমনীয়। আপাতত, এটি যথেষ্ট পরিষ্কার। সবচেয়ে গুরুত্বপূর্ণ বিষয় হলো আমাদের কাছে একটি কার্যকরী ফিচার রয়েছে যা একটি টেস্ট দ্বারা সুরক্ষিত। চলুন পরবর্তী প্রয়োজনীয়তার দিকে এগিয়ে যাই।
দ্বিতীয় পুনরাবৃত্তি: অজানা মুদ্রা পরিচালনা
🔴 রেড: একটি অবৈধ মুদ্রার জন্য একটি টেস্ট লিখুন
যদি আমরা এমন কোনো মুদ্রায় রূপান্তর করার চেষ্টা করি যা আমরা জানি না, তাহলে কী হওয়া উচিত? সম্ভবত এটি একটি এরর (error) থ্রো করবে। চলুন `CurrencyConverter.test.js`-এ একটি নতুন টেস্টে এই আচরণটি সংজ্ঞায়িত করি।
// CurrencyConverter.test.js-এ, describe ব্লকের ভিতরে
it('should throw an error for unknown currencies', () => {
// Arrange
const amount = 10;
// Act & Assert
// Jest-এর toThrow কাজ করার জন্য আমরা ফাংশন কলটিকে একটি অ্যারো ফাংশনে র্যাপ করি।
expect(() => {
CurrencyConverter.convert(amount, 'USD', 'XYZ');
}).toThrow('Unknown currency: XYZ');
});
ফাইলটি সেভ করুন। টেস্ট রানার অবিলম্বে একটি নতুন ব্যর্থতা দেখাবে। এটি রেড কারণ আমাদের কোড কোনো এরর থ্রো করে না; এটি `rates['USD']['XYZ']` অ্যাক্সেস করার চেষ্টা করে, যার ফলে একটি `TypeError` হয়। আমাদের নতুন টেস্টটি এই ত্রুটিটি সঠিকভাবে শনাক্ত করেছে।
🟢 গ্রিন: নতুন টেস্টটি পাস করান
আসুন ভ্যালিডেশন যোগ করার জন্য `CurrencyConverter.js` পরিবর্তন করি।
// CurrencyConverter.js
const rates = {
USD: {
EUR: 0.92,
GBP: 0.80
},
EUR: {
USD: 1.08
}
};
const CurrencyConverter = {
convert(amount, from, to) {
if (!rates[from] || !rates[from][to]) {
// একটি ভালো এরর মেসেজের জন্য কোন মুদ্রাটি অজানা তা নির্ধারণ করুন
const unknownCurrency = !rates[from] ? from : to;
throw new Error(`Unknown currency: ${unknownCurrency}`);
}
return amount * rates[from][to];
}
};
module.exports = CurrencyConverter;
ফাইলটি সেভ করুন। উভয় টেস্টই এখন পাস করছে। আমরা আবার গ্রিন অবস্থায় ফিরে এসেছি।
🔵 রিফ্যাক্টর: এটি পরিষ্কার করুন
আমাদের `convert` ফাংশনটি বড় হচ্ছে। ভ্যালিডেশন লজিকটি গণনার সাথে মিশে আছে। পঠনযোগ্যতা উন্নত করার জন্য আমরা ভ্যালিডেশনটিকে একটি পৃথক প্রাইভেট ফাংশনে বের করে আনতে পারতাম, কিন্তু আপাতত এটি এখনও পরিচালনাযোগ্য। মূল বিষয় হলো আমাদের এই পরিবর্তনগুলি করার স্বাধীনতা আছে কারণ আমাদের টেস্টগুলি আমাদের বলে দেবে যদি আমরা কিছু ভেঙে ফেলি।
তৃতীয় পুনরাবৃত্তি: অ্যাসিঙ্ক্রোনাস রেট ফেচিং
রেট হার্ডকোড করা বাস্তবসম্মত নয়। আসুন আমাদের মডিউলটিকে একটি (মক করা) এক্সটার্নাল API থেকে রেট আনার জন্য রিফ্যাক্টর করি।
🔴 রেড: একটি অ্যাসিঙ্ক টেস্ট লিখুন যা একটি API কল মক করে
প্রথমত, আমাদের কনভার্টারটিকে পুনর্গঠন করতে হবে। এটি এখন একটি ক্লাস হবে যা আমরা সম্ভবত একটি API ক্লায়েন্ট দিয়ে ইনস্ট্যানশিয়েট করতে পারব। আমাদের `fetch` API-কেও মক করতে হবে। Jest এটি সহজ করে তোলে।
আসুন এই নতুন, অ্যাসিঙ্ক্রোনাস বাস্তবতার সাথে খাপ খাইয়ে নিতে আমাদের টেস্ট ফাইলটি পুনরায় লিখি। আমরা আবার হ্যাপি পাথ পরীক্ষা করে শুরু করব।
// CurrencyConverter.test.js
const CurrencyConverter = require('./CurrencyConverter');
// এক্সটার্নাল ডিপেন্ডেন্সি মক করুন
global.fetch = jest.fn();
beforeEach(() => {
// প্রতিটি টেস্টের আগে মকের ইতিহাস পরিষ্কার করুন
fetch.mockClear();
});
describe('CurrencyConverter', () => {
it('should fetch rates and convert correctly', async () => {
// Arrange
// সফল API রেসপন্স মক করুন
fetch.mockResolvedValueOnce({
json: () => Promise.resolve({ rates: { EUR: 0.92 } })
});
const converter = new CurrencyConverter('https://api.exchangerates.com');
const amount = 10; // 10 USD
// Act
const result = await converter.convert(amount, 'USD', 'EUR');
// Assert
expect(result).toBe(9.2);
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('https://api.exchangerates.com/latest?base=USD');
});
// আমরা API ব্যর্থতা ইত্যাদির জন্যেও টেস্ট যোগ করব।
});
এটি চালালে রেড এর বন্যা বয়ে যাবে। আমাদের পুরনো `CurrencyConverter` একটি ক্লাস নয়, এর কোনো `async` মেথড নেই, এবং এটি `fetch` ব্যবহার করে না।
🟢 গ্রিন: অ্যাসিঙ্ক লজিক প্রয়োগ করুন
এখন, আসুন টেস্টের প্রয়োজনীয়তা মেটাতে `CurrencyConverter.js` পুনরায় লিখি।
// CurrencyConverter.js
class CurrencyConverter {
constructor(apiUrl) {
this.apiUrl = apiUrl;
}
async convert(amount, from, to) {
const response = await fetch(`${this.apiUrl}/latest?base=${from}`);
if (!response.ok) {
throw new Error('Failed to fetch exchange rates.');
}
const data = await response.json();
const rate = data.rates[to];
if (!rate) {
throw new Error(`Unknown currency: ${to}`);
}
// টেস্টে ফ্লোটিং পয়েন্ট সমস্যা এড়াতে সহজ রাউন্ডিং
const convertedAmount = amount * rate;
return parseFloat(convertedAmount.toFixed(2));
}
}
module.exports = CurrencyConverter;
আপনি যখন সেভ করবেন, টেস্টটি গ্রিন হয়ে যাওয়া উচিত। লক্ষ্য করুন যে আমরা ফ্লোটিং-পয়েন্ট ত্রুটিগুলি পরিচালনা করার জন্য রাউন্ডিং লজিকও যোগ করেছি, যা আর্থিক গণনার একটি সাধারণ সমস্যা।
🔵 রিফ্যাক্টর: অ্যাসিঙ্ক কোড উন্নত করুন
`convert` মেথডটি অনেক কিছু করছে: ফেচিং, এরর হ্যান্ডলিং, পার্সিং এবং গণনা। আমরা শুধুমাত্র API কমিউনিকেশনের জন্য দায়ী একটি পৃথক `RateFetcher` ক্লাস তৈরি করে এটিকে রিফ্যাক্টর করতে পারি। আমাদের `CurrencyConverter` তখন এই ফেচারটি ব্যবহার করবে। এটি সিঙ্গেল রেসপন্সিবিলিটি প্রিন্সিপল (Single Responsibility Principle) অনুসরণ করে এবং উভয় ক্লাসকে পরীক্ষা ও রক্ষণাবেক্ষণ করা সহজ করে তোলে। TDD আমাদের এই পরিচ্ছন্ন ডিজাইনের দিকে পরিচালিত করে।
সাধারণ TDD প্যাটার্ন এবং অ্যান্টি-প্যাটার্ন
আপনি TDD অনুশীলন করার সাথে সাথে, আপনি এমন প্যাটার্ন আবিষ্কার করবেন যা ভাল কাজ করে এবং অ্যান্টি-প্যাটার্ন যা ঘর্ষণ সৃষ্টি করে।
অনুসরণ করার জন্য ভাল প্যাটার্ন
- Arrange, Act, Assert (AAA): আপনার টেস্টগুলিকে তিনটি স্পষ্ট অংশে গঠন করুন। আপনার সেটআপ Arrange করুন, পরীক্ষার অধীনে কোডটি সম্পাদন করে Act করুন, এবং ফলাফল সঠিক কিনা তা Assert করুন। এটি টেস্টগুলিকে পড়া এবং বোঝা সহজ করে তোলে।
- একবারে একটি আচরণ পরীক্ষা করুন: প্রতিটি টেস্ট কেস একটি একক, নির্দিষ্ট আচরণ যাচাই করবে। এটি একটি টেস্ট ব্যর্থ হলে কী ভেঙেছে তা স্পষ্ট করে তোলে।
- বর্ণনামূলক টেস্টের নাম ব্যবহার করুন: একটি টেস্টের নাম যেমন `it('should throw an error if the amount is negative')` `it('test 1')` এর চেয়ে অনেক বেশি মূল্যবান।
এড়িয়ে চলার জন্য অ্যান্টি-প্যাটার্ন
- ইমপ্লিমেন্টেশন ডিটেইলস পরীক্ষা করা: টেস্টগুলির পাবলিক API ("কী") এর উপর ফোকাস করা উচিত, প্রাইভেট ইমপ্লিমেন্টেশন ("কীভাবে") এর উপর নয়। প্রাইভেট মেথড পরীক্ষা করা আপনার টেস্টগুলিকে ভঙ্গুর করে তোলে এবং রিফ্যাক্টরিং কঠিন করে তোলে।
- রিফ্যাক্টর ধাপটি উপেক্ষা করা: এটি সবচেয়ে সাধারণ ভুল। রিফ্যাক্টরিং এড়িয়ে যাওয়া আপনার প্রোডাকশন কোড এবং আপনার টেস্ট স্যুট উভয় ক্ষেত্রেই টেকনিক্যাল ডেট (technical debt) তৈরি করে।
- বড়, ধীরগতির টেস্ট লেখা: ইউনিট টেস্টগুলি দ্রুত হওয়া উচিত। যদি তারা আসল ডাটাবেস, নেটওয়ার্ক কল বা ফাইলসিস্টেমের উপর নির্ভর করে, তবে তারা ধীর এবং অবিশ্বস্ত হয়ে যায়। আপনার ইউনিটগুলিকে বিচ্ছিন্ন করতে মক এবং স্টাব ব্যবহার করুন।
বৃহত্তর ডেভেলপমেন্ট জীবনচক্রে TDD
TDD শূন্যস্থানে বিদ্যমান নয়। এটি আধুনিক অ্যাজাইল এবং ডেভঅপ্স অনুশীলনের সাথে সুন্দরভাবে সংহত হয়, বিশেষ করে বিশ্বব্যাপী দলগুলির জন্য।
- TDD এবং Agile: আপনার প্রজেক্ট ম্যানেজমেন্ট টুল থেকে একটি ইউজার স্টোরি বা একটি অ্যাক্সেপটেন্স ক্রাইটেরিয়ন সরাসরি একাধিক ব্যর্থ টেস্টে রূপান্তরিত হতে পারে। এটি নিশ্চিত করে যে আপনি ঠিক তাই তৈরি করছেন যা ব্যবসার প্রয়োজন।
- TDD এবং কন্টিনিউয়াস ইন্টিগ্রেশন/কন্টিনিউয়াস ডিপ্লয়মেন্ট (CI/CD): TDD একটি নির্ভরযোগ্য CI/CD পাইপলাইনের ভিত্তি। প্রতিবার যখন একজন ডেভেলপার কোড পুশ করে, একটি স্বয়ংক্রিয় সিস্টেম (যেমন GitHub Actions, GitLab CI, বা Jenkins) পুরো টেস্ট স্যুট চালাতে পারে। যদি কোনো টেস্ট ব্যর্থ হয়, বিল্ডটি বন্ধ হয়ে যায়, যা বাগগুলিকে প্রোডাকশনে পৌঁছাতে বাধা দেয়। এটি সময় অঞ্চল নির্বিশেষে পুরো দলের জন্য দ্রুত, স্বয়ংক্রিয় প্রতিক্রিয়া প্রদান করে।
- TDD বনাম BDD (বিহেভিয়ার-ড্রিভেন ডেভেলপমেন্ট): BDD হলো TDD-এর একটি সম্প্রসারণ যা ডেভেলপার, QA এবং ব্যবসায়িক স্টেকহোল্ডারদের মধ্যে সহযোগিতার উপর দৃষ্টি নিবদ্ধ করে। এটি আচরণ বর্ণনা করার জন্য একটি প্রাকৃতিক ভাষার বিন্যাস (Given-When-Then) ব্যবহার করে। প্রায়শই, একটি BDD ফিচার ফাইল একাধিক TDD-স্টাইলের ইউনিট টেস্ট তৈরিতে চালিকাশক্তি হিসেবে কাজ করে।
উপসংহার: TDD-এর সাথে আপনার যাত্রা
টেস্ট-ড্রিভেন ডেভেলপমেন্ট একটি টেস্টিং কৌশলের চেয়েও বেশি কিছু—এটি সফটওয়্যার ডেভেলপমেন্টে আমাদের দৃষ্টিভঙ্গির একটি দৃষ্টান্তমূলক পরিবর্তন। এটি গুণমান, আত্মবিশ্বাস এবং সহযোগিতার একটি সংস্কৃতি গড়ে তোলে। রেড-গ্রিন-রিফ্যাক্টর চক্র একটি স্থির ছন্দ প্রদান করে যা আপনাকে পরিষ্কার, শক্তিশালী এবং রক্ষণাবেক্ষণযোগ্য কোডের দিকে পরিচালিত করে। ফলস্বরূপ টেস্ট স্যুটটি একটি সুরক্ষা বলয় হয়ে ওঠে যা আপনার দলকে রিগ্রেশন থেকে রক্ষা করে এবং একটি জীবন্ত ডকুমেন্টেশন যা নতুন সদস্যদের অনবোর্ড করে।
শেখার পথটি খাড়া মনে হতে পারে, এবং প্রাথমিক গতি ধীর মনে হতে পারে। কিন্তু ডিবাগিং সময় হ্রাস, উন্নত সফটওয়্যার ডিজাইন এবং বর্ধিত ডেভেলপার আত্মবিশ্বাসের দীর্ঘমেয়াদী সুফল অপরিমেয়। TDD আয়ত্ত করার যাত্রাটি শৃঙ্খলা এবং অনুশীলনের একটি যাত্রা।
আজই শুরু করুন। আপনার পরবর্তী প্রজেক্টে একটি ছোট, গুরুত্বহীন ফিচার বেছে নিন এবং প্রক্রিয়াটির প্রতি প্রতিশ্রুতিবদ্ধ হন। প্রথমে টেস্ট লিখুন। এটিকে ব্যর্থ হতে দেখুন। এটিকে পাস করান। এবং তারপর, সবচেয়ে গুরুত্বপূর্ণভাবে, রিফ্যাক্টর করুন। একটি গ্রিন টেস্ট স্যুট থেকে আসা আত্মবিশ্বাস অনুভব করুন, এবং আপনি শীঘ্রই অবাক হবেন যে আপনি অন্য কোনো উপায়ে কীভাবে সফটওয়্যার তৈরি করতেন।