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

ডিপেনডেন্সি ইনজেকশন কি (জার্গন ছাড়া)
ডিপেনডেন্সি ইনজেকশন (DI) একটা সহজ ধারণা: কোড নিজের প্রয়োজনীয় জিনিসগুলো নিজে তৈরি করার পরিবর্তে বাইরে থেকে পায়।
এগুলোই হল তার "ডিপেনডেন্সি"—উদাহরণস্বরূপ, ডাটাবেস কানেকশন, পেমেন্ট সার্ভিস, ক্লক, লগার বা ই-মেইল সেন্ডার। যদি আপনার কোড নিজের হাতেই এসব তৈরি করে, তাহলে সেটা চুপচাপ নির্ধারণ করে ফেলছে কিভাবে সেই ডিপেনডেন্সিগুলো কাজ করবে।
বাস্তব জীবনের উপমা
এক অফিসের কফি মেশিন ভাবুন। এটা পানি, কফি বিন, এবং বিদ্যুতের ওপর নির্ভরশীল।
- যদি মেশিনটি কেবল একটি প্রোপাইটারি পানি কার্টিজের সাথে কাজ করে এবং নিজে সেটাই কেনে, তাহলে আপনি সেই সরবরাহকারীর সাথে আটকে পড়েছেন।
- যদি মেশিনটি যেকোনো স্ট্যান্ডার্ড পানি ইনপুট গ্রহণ করে, তাহলে কেউ অন্য কেউ উৎস বেছে নিতে পারে—ট্যাপ, ফিল্টারকৃত, বোতলজাত—মেশিন পরিবর্তন না করেই।
DI ঐ দ্বিতীয় পদ্ধতি: “কফি মেশিন” (আপনার ক্লাস/ফাংশন) তার কাজ করবে, আর “সরবরাহ” (ডিপেনডেন্সি) যারা সেট আপ করেন তারা দিয়েই দেয়।
DI কি নয়
DI কোনো নির্দিষ্ট ফ্রেমওয়ার্ক ব্যবহার করার শর্ত নয়, এবং এটা DI কন্টেইনারের সমার্থকও নয়। আপনি ম্যানুয়ালি প্যারামিটার বা কনস্ট্রাকটরের মাধ্যমে DI করতে পারেন।
DI কে “মকিং” বলাও ঠিক হবে না—মকিং হচ্ছে টেস্টে DI ব্যবহার করার একটা উপায়, কিন্তু DI নিজে শুধুই ডিজাইন সিদ্ধান্ত যে ডিপেনডেন্সি কোথায় তৈরি হবে।
কেন পরীক্ষাযোগ্যতা ও মডুলারিটি একসাথে বাড়ে
যখন ডিপেনডেন্সি বাইরের পক্ষ থেকে দেয়া হয়, আপনার কোড ভিন্ন প্রসঙ্গে চালানো সহজ হয়: প্রোডাকশন, ইউনিট টেস্ট, ডেমো, বা ভবিষ্যৎ ফিচার।
এই নমনীয়তা মডিউলগুলোকেও পরিষ্কার রাখে: অংশগুলো রিপ্লেস করা যায় পুরো সিস্টেমকে রিওয়্যার করার দরকার ছাড়া। ফলে টেস্টগুলো দ্রুত ও পরিষ্কার হয় (কারণ আপনি সহজ স্ট্যান্ড-ইন ব্যবহার করতে পারেন), এবং কোডবেস পরিবর্তন করা সহজ হয় (কারণ অংশগুলো কম জড়িত)।
মূল সমস্যা: টাইট কাপলিং পরিবর্তনকে কঠিন করে তোলে
টাইট কাপলিং তখনই ঘটে যখন কোডের একটি অংশ সরাসরি নির্ধারণ করে যে অন্য অংশগুলোকে কি ব্যবহার করতে হবে। সবচেয়ে সাধারণ রূপটি হলো: ব্যবসায়িক লজিকে new ব্যবহার করা।
সরাসরি ইনস্ট্যানশিয়েশন কিভাবে লুকানো কাপলিং তৈরি করে
ভাবুন একটি চেকআউট ফাংশন new StripeClient() এবং new SmtpEmailSender() নিজে তৈরি করছে। প্রথমে এটা সুবিধাজনক মনে হয়—প্রয়োজনীয় সবকিছু সেখানে রয়েছে। কিন্তু এটি চেকআউট ফ্লোকে সঠিক সেই ইমপ্লিমেন্টেশনের সাথে আটকে দেয়, কনফিগারেশন বিবরণ ও তাদের তৈরি-বিধি (API কী, টাইমআউট, নেটওয়ার্ক আচরণ) পর্যন্ত।
এই কাপলিং "লুকানো" কারণ এটা মেথড সিগনেচার থেকে স্পষ্ট হয় না। ফাংশনটি শুধু অর্ডার প্রসেস করে মনে হয়, কিন্তু গোপনে এটি পেমেন্ট গেটওয়ে, ইমেল প্রোভাইডার, এবং সম্ভবত ডাটাবেসের ওপর নির্ভরশীল।
বদলাতে কষ্ট হওয়া ডিপেনডেন্সি কেন ধীর পরিবর্তন ঘটায়
যখন ডিপেনডেন্সি হার্ড-কোডেড থাকে, ছোট পরিবর্তনও রিপল эффেক্ট ফেলে:
- প্রোভাইডার বদলালে (Stripe → Adyen) ব্যবসায়িক লজিক সম্পাদনা করতে হয়, না যে কেবল একটি কম্পোনেন্ট বদলাতে হবে।
- ক্যাশিং, রিট্রাই, বা লগিং যোগ করলে অনেক কল সাইটে ইস্যু ছড়াতে থাকে।
- লাইব্রেরি আপগ্রেড করা বিস্তৃত রিফ্যাক্টরের কারণ হতে পারে কারণ তৈরি স্বাধীনভাবে ছড়িয়ে আছে।
টাইট কাপলিং ধীর বা ফ্ল্যাকি টেস্ট হিসাবে প্রকাশ পায়
হার্ড-কোডেড ডিপেনডেন্সি ইউনিট টেস্টকে বাস্তব কাজ চালাতে বাধ্য করে: নেটওয়ার্ক কল, ফাইল I/O, ঘড়ি, র্যান্ডম আইডি, বা শেয়ার করা রিসোর্স। টেস্টগুলো আইসোলেটেড না থাকায় ধীরে চলে এবং ফ্ল্যাকি হয় কারণ ফলাফল টাইমিং, বাহ্যিক সার্ভিস, বা এক্সিকিউশনের অর্ডারের ওপর নির্ভর করে।
সতর্কতা সিগন্যাল যা নজর রাখতে হবে
যদি নিচের প্যাটার্নগুলো দেখতে পান, টাইট কাপলিং ইতিমধ্যে আপনার সময় খাওয়াচ্ছে:
- ইমপ্লিসিট ডিপেনডেন্সি হিসেবে গ্লোবাল স্টেট ব্যবহার
- টেস্টে রিসেট করা কষ্টসাধ্য সিঙ্গলটন
- কোর লজিকে ছড়িয়ে থাকা
new - কোড যা ডাটাবেস, ওয়েব সার্ভার, বা বাস্তব API কী ছাড়া টেস্ট করা যায় না
ডিপেনডেন্সি ইনজেকশন এই সমস্যাগুলো সমাধান করে—ডিপেনডেন্সিগুলোকে স্পষ্ট ও সহজে বদলযোগ্য করে দেয়, ব্যবসায়িক নিয়ম পুনর্লিখন ছাড়া।
ইনভার্সন অফ কন্ট্রোল: "কি" থেকে আলাদা করা "কিভাবে"
ইনভার্সন অফ কন্ট্রোল (IoC) হল দায়বদ্ধতার একটি সরল পরিবর্তন: একটি ক্লাসকে কি করতে হবে সে বিষয়ে মনোনিবেশ করা উচিত, না কিভাবে প্রয়োজনীয় জিনিসগুলো পাবে।
যখন একটি ক্লাস নিজের ডিপেনডেন্সি ক্রিয়েট করে (যেমন new EmailService() বা সরাসরি ডাটাবেস কানেকশন ওপেন করা), তখন এটি চুপচাপ দুইটা কাজ করছে: ব্যবসায়িক লজিক এবং সেটআপ। এতে ক্লাসটি বদলাতে, পুনঃব্যবহার করতে এবং টেস্ট করতে কঠিন হয়ে যায়।
কনক্রিট ক্লাসগুলোর ওপর নয়, অ্যাবস্ট্রাকশনের ওপর নির্ভর করা
IoC-তে আপনার কোড অ্যাবস্ট্রাকশনের ওপর নির্ভর করে—ইন্টারফেস বা ছোট "চুক্তি" টাইপের ওপর—কোনো নির্দিষ্ট ইমপ্লিমেন্টেশনের ওপর নয়।
উদাহরণস্বরূপ, একটি CheckoutService-এর দরকার নেই জানা যে পেমেন্ট প্রক্রিয়াকরণ Stripe, PayPal, না একটা টেস্ট প্রসেসর দিয়ে হবে—ওয়ের কেবল দরকার "কেউ যে কার্ড চার্জ করতে পারে"। যদি CheckoutService একটি IPaymentProcessor নেয়, তাহলে এটি যেকোনো ইমপ্লিমেন্টেশন দিয়ে কাজ করবে যা ঐ চুক্তি মেনে চলে।
এটা আপনার কোর লজিককে স্থিতিশীল রাখে এমনকি যখন আন্ডারলাইং টুলস বদলে যায়।
ক্লাসের বাইরের দিকে ক্রিয়েশন সরান
IoC-র ব্যবহারিক অংশ হলো ডিপেনডেন্সি ক্রিয়েশন ক্লাসের বাইরে নিয়ে আসা এবং সেগুলো পাস করা (অften কনস্ট্রাকটরের মাধ্যমে)। এটিই ডিপেনডেন্সি ইনজেকশন (DI)-এর কাজ: IoC অর্জনের একটি সাধারণ উপায়।
এর বদলে:
- ক্লাস নিজের সহযোগীদের বেছে নেয় এবং তৈরি করে
আপনি পান:
- ক্লাস বাইরের থেকে সহযোগীরা পায়
ফলাফল হলো নমনীয়তা: আচরণ বদলানো একটি কনফিগারেশন সিদ্ধান্ত হয়ে যায়, রিরাইট নয়।
"কম্পোজিশন রুট": যেখানে ওয়্যারিং হয়ে থাকে
যদি ক্লাসগুলো তাদের ডিপেনডেন্সি তৈরি না করে, তখন আরেকটি জিনিস করতে হবে—সেই জিনিসটিই হলো কম্পোজিশন রুট: যেখানে আপনার অ্যাপ অ্যাসেম্বল করা হয়—সাধারণত স্টার্টআপ কোড।
কম্পোজিশন রুটে আপনি নির্ধারণ করবেন, “প্রোডাকশনে RealPaymentProcessor; টেস্টে FakePaymentProcessor।” ওয়্যারিং এক জায়গায় রাখা বিস্ময় কমায় এবং বাকি কোডবেসকে আচরণে ফোকাস রাখতে সাহায্য করে।
টেস্ট ও রিফ্যাক্টরের জন্য কেন এটি গুরুত্বপূর্ণ
IoC ইউনিট টেস্টগুলো সহজ করে কারণ আপনি রিয়াল নেটওয়ার্ক বা ডাটাবেসের বদলে ছোট, দ্রুত টেস্ট ডাবল দিতে পারেন।
এছাড়া রিফ্যাক্টরিংও নিরাপদ হয়: যখন দায়িত্বগুলো পৃথক থাকে, একটি ইমপ্লিমেন্টেশন বদলালে সাধারণত যেগুলো ব্যবহার করে তাদের বদলাতে হয় না—যতক্ষণ না অ্যাবস্ট্রাকশন পরিবর্তিত হয়।
সাধারণ DI স্টাইল ও কখন কোনটি ব্যবহার করবেন
DI কোনো একক কৌশল নয়—এটি কিছু ছোট উপায়ের সেট যাতে আপনি একটি ক্লাসকে তার দরকারি জিনিসগুলো (যেমন লগার, ডাটাবেস ক্লায়েন্ট, বা পেমেন্ট গেটওয়ে) "খাওয়ান"। আপনি যে স্টাইল পছন্দ করবেন তা স্পষ্টতা, পরীক্ষাযোগ্যতা ও অপব্যবহারের সম্ভাব্যতা প্রভাবিত করে।
কনস্ট্রাকটর ইনজেকশন (ডিফল্ট)
কনস্ট্রাকটর ইনজেকশনে, ডিপেনডেন্সিগুলো অবজেক্ট তৈরি করার সময় আবশ্যক। বড় সুবিধা: আপনি ভুলবশত সেগুলো ভুলে যেতে পারবেন না।
এটা সবচেয়ে ভালো যখন একটি ডিপেনডেন্সি:
- অবজেক্টটি কাজ করার জন্য সবসময় প্রয়োজন
- একাধিক মেথড জুড়ে শেয়ার করা হয়
- আগেই ভ্যালিডেট করা গুরুত্বপূর্ণ (null/undefined অনুমোদনযোগ্য নয়)
কনস্ট্রাকটর ইনজেকশন পরিষ্কার কোড এবং সরাসরি ইউনিট টেস্ট দেয়—টেস্টে আপনি ফেক বা মক কনস্ট্রাকশনের সময়ই পাস করতে পারেন।
প্যারামিটার / মেথড ইনজেকশন (এক-সময়ের কাজের জন্য)
কখনও কখনও একটি ডিপেনডেন্সি কেবল একটা অপারেশনের জন্যই দরকার—উদাহরণ: একটি অস্থায়ী ফরম্যাটার, বিশেষ স্ট্র্যাটেজি, বা রিকোয়েস্ট-স্কোপড ভ্যালু।
এই ক্ষেত্রে, সেটি মেথড প্যারামিটার হিসাবে পাস করুন। এটি অবজেক্টকে ছোট রাখে এবং একবারের চাহিদাকে স্থায়ী ফিল্ড করে না।
প্রপার্টি / সেটার ইনজেকশন (সাৱধানে ব্যবহার করবেন)
সেটার ইনজেকশন সুবিধাজনক হতে পারে যখন আপনি কনস্ট্রাকশন সময় ডিপেনডেন্সি দিতে পারছেন না (কিছু ফ্রেমওয়ার্ক বা লেগেসি কোড পাথ)। বদলে—এটি প্রয়োজনীয়তা লুকিয়ে রাখে: ক্লাসটি ব্যবহারযোগ্য দেখায় এমনকি পুরো কনফিগার করা না থাকলেও।
এটা প্রায়শই রানটাইম-এর বিস্ময় ডেকে আনে ("কেন এটা undefined?"), এবং টেস্টগুলোকে দুর্বল করে কারণ সেটআপ ভুলে যাওয়া সহজ।
একটি সহজ নিয়ম
- যদি ক্লাস এটি ছাড়া কাজ করতে না পারে: কনস্ট্রাকটর ইনজেকশন।
- যদি এটা কেবল এক কল বা ভেরিয়েন্ট আচরণ জন্য: মেথড/প্যারামিটার ইনজেকশন।
- যদি দেরিতে ওয়্যারিং সত্যিই দরকার: সেটার ইনজেকশন, কিন্তু প্রমাণপত্র (ডক, ভ্যালিডেশন, বা ফেল-ফাস্ট চেক) যোগ করুন।
DI কিভাবে ইউনিট টেস্ট উন্নত করে (গতি, আইসোলেশন, স্পষ্টতা)
ইউনিট টেস্ট তখন সবচেয়ে কার্যকর যখন সেগুলো দ্রুত, পুনরাবৃত্তিযোগ্য এবং এক বিহেভিয়ারের ওপর কেন্দ্রীভূত। টেস্ট যদি বাস্তব ডাটাবেস, নেটওয়ার্ক কল, ফাইলসিস্টেম, বা ক্লক নির্ভর করে, তা ধীর হয়ে যায় এবং ফ্ল্যাকি হয়ে পড়ে। আরও খারাপ হলো ব্যর্থতা অস্পষ্ট—কোড নাকি পরিবেশ কি ভেঙেছে?
DI এটি প্রতিরোধ করে কারণ আপনার কোড বহিরাগত ডিপেনডেন্সি বাইরের থেকে গ্রহণ করে। টেস্টগুলোতে আপনি সেগুলো বদলে লাইটওয়েট সাবস্টিটিউট ইনজেক্ট করতে পারেন।
গতি: টেস্ট মেমরিতেই রাখুন
বাস্তব DB বা API কল সেটআপ টাইম ও লেটেন্সি যোগ করে। DI দিয়ে আপনি ইন-মেমরি রিপোজিটরি বা প্রস্তুত রেসপন্স দেয় এমন ফেক ক্লায়েন্ট ইনজেক্ট করতে পারেন। ফলে:
- একই সময়ে অনেক টেস্ট চলে
- আপনি প্রায়ই টেস্ট চালাবেন
- CI পাইপলাইন দ্রুত থাকে
আইসোলেশন: এক সময়ে এক জিনিস টেস্ট করুন
DI না থাকলে কোড প্রায়ই নিজের ডিপেনডেন্সি তৈরি করে, টেস্টকে পুরো স্ট্যাক এক্সারসাইজ করাতে বাধ্য করে। DI দিয়ে আপনি ইনজেক্ট করতে পারেন:
- মক ইন্টার্যাকশন যাচাই করার জন্য (যেমন, "একটি ইমেল পাঠানো হয়েছে")
- স্টাব নির্দিষ্ট ভ্যালু রিটার্ন করার জন্য (যেমন, "ইউজার আছে")
- ফেক সরল কাজ করা আচরণ দেওয়ার জন্য (যেমন, ইন-মেমরি স্টোর)
কোনও হ্যাক নয়, কোনও গ্লোবাল সুইচ নয়—শুধু ভিন্ন ইমপ্লিমেন্টেশন পাস করুন।
স্পষ্টতা: সহজ Arrange–Act–Assert
DI সেটআপকে স্পষ্ট করে। কনফিগারেশন, কানেকশন স্ট্রিং, বা টেস্ট-অনলি এনভায়রনমেন্ট ভ্যারিয়েবলগুলো খুঁটিয়ে খুঁজে বের করার বদলে, আপনি একটি টেস্ট পড়েই বুঝে ফেলতে পারবেন কি বাস্তব কি মক।
একটি সাধারণ DI-ফ্রেন্ডলি টেস্ট পড়ে এমন হয়:
- Arrange: সার্ভিস তৈরি করুন ফেক রিপোজিটরি ও স্টাব করা ক্লক দিয়ে
- Act: মেথড কল করুন
- Assert: রিটার্ন ভ্যালু চেক করুন এবং/অথবা মক ইন্টার্যাকশন যাচাই করুন
এই সরলতা শব্দবর্জিতিকে কমায় এবং ব্যর্থতাগুলো নির্ণয় সহজ করে—ঠিক যেটা আপনি ইউনিট টেস্ট থেকে চান।
টেস্ট সীম: আচরণ ইচ্ছাকৃতভাবে বদলানোর জায়গা তৈরি করা
একটি টেস্ট সীম হলো আপনার কোডে ইচ্ছাকৃতভাবে একটি "খোলা জায়গা" যেখানে আপনি একটি আচরণ বদলে দিতে পারেন। প্রোডাকশনে এখানে বাস্তব জিনিস লাগান; টেস্টে নিরাপদ, দ্রুত সাবস্টিটিউট লাগান। DI এই সীমগুলো তৈরি করার সহজ উপায়গুলোর একেকটি—বিনা হ্যাকের।
সীম সাধারণত কোথায় থাকে
সীমগুলো সবচেয়ে উপকারী এমন অংশগুলোর চারপাশে থাকে যা টেস্টে নিয়ন্ত্রণ করা কঠিন:
- টাইম (বর্তমান তারিখ/সময় পরিবর্তিত হয়)
- ফাইল সিস্টেম (ধীর, পারমিশন, ক্লিনআপ)
- ইমেল/SMS (সাইড-ইফেক্ট, বাহ্যিক সার্ভিস)
- পেমেন্ট গেটওয়ে (বাস্তব অর্থ, নেটওয়ার্ক ব্যর্থতা)
যদি আপনার ব্যবসায়িক লজিক সরাসরি এসব কল করে, টেস্ট ঝুঁকিপূর্ণ হয়: নেটওয়ার্ক হিকআপ, টাইমজোন ভিন্নতা, মিসিং ফাইল—এসব কারণেই ব্যর্থতা হতে পারে এবং এগুলো টেস্টকে ধীর করে।
ইন্টারফেস (বা চুক্তি) সীমগুলোকে সহজ পছন্দে পরিণত করে
একটি সীম প্রায়ই একটি ইন্টারফেস রূপ নেয়—বা ডাইনামিক ভাষায় একটি সরল চুক্তি যেমন "অবজেক্টটির একটি now() মেথড থাকতে হবে"। মূল ধারণা: আপনি কি লাগে তা নির্ভর করুন, কোথা থেকে আসে তা নয়।
উদাহরণ: একটি অর্ডার সার্ভিসে সরাসরি সিস্টেম ক্লক কল করার বদলে আপনি Clock ব্যবহার করতে পারেন:
- প্রোডাকশন:
SystemClock.now() - টেস্ট:
FakeClock.now()নির্দিষ্ট সময় রিটার্ন করে
ইয়েই প্যাটার্ন ফাইল রিড (FileStore), ইমেল পাঠানো (Mailer) কিংবা কার্ড চার্জিং (PaymentGateway)-এর জন্যও কাজ করে। কোর লজিক অপরিবর্তিত থাকে; কেবল প্লাগ-ইন ইমপ্লিমেন্টেশন বদলে যায়।
সীম কেন ভালো টেস্ট দেয়
যখন আপনি আচরণ ইচ্ছে করে বদলাতে পারেন:
- টেস্টগুলো কম ভঙ্গুর হয়: বাস্তব সময়, নেটওয়ার্ক, বা শেয়ার করা মেশিন স্টেটের ওপর নির্ভরশীলতা কমে।
- এজ কেস কভার করা সহজ: আপনি সহজে "পেমেন্ট প্রত্যাখ্যাত", "ইমেল প্রোভাইডার টাইমআউট" বা "মাসের শেষের তারিখ" সিমুলেট করতে পারেন।
- ব্যর্থতা স্পষ্ট হয়: টেস্ট ব্যর্থ হলে সাধারণত আপনার ব্যবসায়িক নিয়ম ত্রুটিপূর্ণ—পরিবেশ নয়।
ভালোভাবে স্থাপিত সীম হেভি মকিংয়ের প্রয়োজন কমিয়ে দেয়। বদলে, আপনি কয়েকটি পরিষ্কার সাবস্টিটিউশন পয়েন্ট পান যা ইউনিট টেস্টকে দ্রুত, ফোকাসড এবং পূর্বানুমেয় রাখে।
DI কিভাবে আরও মডিউলার কোড সক্ষম করে
মডিউলারিটি মানে সফটওয়্যার স্বতন্ত্র অংশ (মডিউলগুলি) থেকে গঠিত—প্রত্যেক মডিউলের সুস্পষ্ট দায়িত্ব ও বাউন্ডারি থাকে।
DI এই বাউন্ডারিগুলো স্পষ্ট করে দেয়। একটি মডিউল সবকিছু তৈরি বা খুঁজে না করে শুধুই তার ডিপেনডেন্সি পায় বাইরের থেকে। এই ছোট পরিবর্তন কমিয়ে দেয় একটি মডিউল আরেকটিকে কতটা জানে।
ডিজাইনে কম কাপলিং
যখন কোড ভিতরে থেকে ডিপেনডেন্সি তৈরি করে (উদাহরণ: সার্ভিসের ভিতরে ডাটাবেস ক্লায়েন্ট new করা), কলার ও ডিপেনডেন্সির মধ্যে শক্ত কাপলিং তৈরি হয়। DI আপনাকে ইন্টারফেস (বা সরল চুক্তি) নির্ভর করতে উৎসাহিত করে, কনক্রিট ইমপ্লিমেন্টেশনের ওপর নয়।
এতে একটি মডিউল সাধারণত জানে:
- কী দরকার (উদাহরণ:
PaymentGateway.charge()) - কিভাবে করা হচ্ছে না (Stripe vs PayPal vs sandbox)
ফলস্বরূপ, মডিউলগুলো একসাথে কম বদলায়, কারণ অভ্যন্তরীণ বিবরণ বাউন্ডারি ছাড়িয়ে লিক করে না।
অংশ পরিবর্তন করা, কলার অপরিবর্তিত রাখা
একটি মডিউলার কোডবেসে আপনি একটি কম্পোনেন্ট বদলাতে পারেন কলারদের পুনরায় লেখা ছাড়া। DI এটা বাস্তবে পরিণত করে:
- বাস্তব ইমেল সেন্ডারকে কিউড সেন্ডারে বদলান
- ফাইল-ভিত্তিক রিপোজিটরিকে ডাটাবেস-ব্যাকড রিপোজিটরিতে বদলান
- বিদ্যমান সার্ভিসের চারপাশে ক্যাশিং ডেকোরেটর যোগ করুন
প্রতিটি ক্ষেত্রে কলার একই চুক্তি ব্যবহার করে। ওয়্যারিং এক জায়গায় (কম্পোজিশন রুট) বদলে যায়, না যে পুরো কোডবেসে ছড়িয়ে পরিবর্তন করতে হবে।
দলের মধ্যে প্যারালাল কাজ সহজ হয়
স্পষ্ট ডিপেনডেন্সি বাউন্ডারিগুলো টিমগুলোকে প্যারালালভাবে কাজ করতে সাহায্য করে। একটি দল একটি চুক্তির পেছনে নতুন ইমপ্লিমেন্টেশন তৈরি করতে পারে অন্য দল যখন ঐ ইন্টারফেস ব্যবহার করে ফিচার উন্নয়ন চালিয়ে যায়।
DI ইনক্রিমেন্টাল রিফ্যাক্টরিংও সহজ করে: আপনি একটি মডিউল বের করে ইনজেক্ট করতে পারেন এবং ধাপে ধাপে রিপ্লেস করতে পারেন—বিগ-ব্যাং রিরাইট ছাড়া।
একটি সরল বেফোর-এন্ড-আফটার উদাহরণ
কোডে DI দেখলে ধারণা দ্রুত ক্লিক করে। এখানে ছোট একটি নোটিফিকেশন ফিচারের "পূর্ব" ও "পর" উদাহরণ।
পূর্ব: ক্লাস নিজের ডিপেনডেন্সি তৈরি করে
যখন ক্লাস ভিতরে new কল করে, তখন এটি সিদ্ধান্ত নেয় কোন ইমপ্লিমেন্টেশন ব্যবহার হবে এবং কিভাবে সেটি তৈরি হবে।
class EmailService {
send(to, message) {
// talks to real SMTP provider
}
}
class WelcomeNotifier {
notify(user) {
const email = new EmailService();
email.send(user.email, "Welcome!");
}
}
টেস্টিং সমস্যা: একটি ইউনিট টেস্ট বাস্তবে ইমেল ইউজ করতে পারে (অথবা গ্লোবাল স্টাবিং ছাড়া কঠিন)।
test("sends welcome email", () => {
const notifier = new WelcomeNotifier();
notifier.notify({ email: "[email protected]" });
// Hard to assert without patching EmailService globally
});
পর: ডিপেনডেন্সি ইনজেক্ট করুন
এখন WelcomeNotifier যেকোনো অবজেক্ট গ্রহণ করে যা প্রয়োজনীয় আচরণ মেনে চলে।
class WelcomeNotifier {
constructor(emailService) {
this.emailService = emailService;
}
notify(user) {
this.emailService.send(user.email, "Welcome!");
}
}
টেস্ট ছোট, দ্রুত, এবং স্পষ্ট হয়ে ওঠে।
test("sends welcome email", () => {
const fakeEmail = { send: vi.fn() };
const notifier = new WelcomeNotifier(fakeEmail);
notifier.notify({ email: "[email protected]" });
expect(fakeEmail.send).toHaveBeenCalledWith("[email protected]", "Welcome!");
});
নতুন ইমপ্লিমেন্টেশন যোগ করা সহজ
পরবর্তীতে SMS চান? WelcomeNotifier-এ যাওয়ার দরকার নেই। আপনি কেবল ভিন্ন ইমপ্লিমেন্টেশন পাস করবেন:
const smsService = { send: (to, msg) => {/* SMS provider */} };
const notifier = new WelcomeNotifier(smsService);
প্রায়োগিক ফলাফল: টেস্টগুলো কনস্ট্রাকশন বিস্তারিত নিয়ে লড়াই বন্ধ করে, এবং নতুন আচরণ যোগ করা হয় ডিপেনডেন্সি বদলিয়ে, না যে বিদ্যমান কোড রিরাইট করে।
ম্যানুয়াল DI বনাম DI কন্টেইনার: সঠিক স্তর বাছাই
DI হতে পারে সহজতর: "আপনি যা দরকার তা ব্যবহারকারীকে পাস করুন।" এটিই ম্যানুয়াল DI। DI কন্টেইনার সেই ওয়্যারিং অটোমেট করে। উভয়ই উপযুক্ত—কিন্তু উপযুক্ত স্তর বাছাই করাটাই মূল।
ম্যানুয়াল ওয়্যারিং: স্পষ্ট ও বোঝা সহজ
ম্যানুয়াল DI-তে আপনি নিজে অবজেক্ট তৈরি করে কনস্ট্রাকটরে ডিপেনডেন্সি পাস করেন। এর সুবিধা:
- কি তৈরি হচ্ছে এবং কোথায় স্পষ্ট দেখা যায়
- ভেঙে গেলে কোনো গোপন মেজাজ নেই
- ছোট অ্যাপ, স্ক্রিপ্ট, বা শুরুতে রিফ্যাক্টরের জন্য দারুণ
ম্যানুয়াল ওয়্যারিং ভালো ডিজাইন হাবিটও জোর দেয়। যদি কোনো অবজেক্ট সাতটি ডিপেনডেন্সি চায়, সেটি তাড়াতাড়ি অসুবিধাজনক মনে হবে—এটি প্রায়ই ক্লাস ভাগ করার সঙ্কেত।
DI কন্টেইনার: কম বয়লারপ্লেট, উন্নত লাইফসাইকেল ম্যানেজমেন্ট
কম্পোনেন্ট বাড়লে ম্যানুয়াল ওয়্যারিং পুনরাবৃত্তির ঝামেলায় পরতে পারে। DI কন্টেইনার সহায়তা করে:
- অবজেক্ট গ্রাফ অটোমেটিক বিল্ড করা
- লাইফটাইম ম্যানেজ করা (সিঙ্গেলটন বনাম প্রতি-রিকুয়েস্ট বনাম ট্রান্সিয়েন্ট)
- নিবন্ধন কেন্দ্রিয়করণ (পরিবেশ অনুযায়ী রিয়েল সার্ভিস বদলানো সহজ)
কন্টেইনার সেইসব অ্যাপ্লিকেশনে ভাল যেখানে পরিষ্কার বাউন্ডারি ও লাইফসাইকেল আছে—ওয়েব অ্যাপ, লং-রানিং সার্ভিস, বা যেখানে অনেক ফিচার শেয়ার করা ইনফ্রাস্ট্রাকচারের ওপর নির্ভরশীল।
কন্টেইনারকে ডিজাইন সমস্যা লুকাতে দেবেন না
কন্টেইনার একটা ভারসাম্যহীন ডিজাইনকে গোছা মনে করিয়ে দিতে পারে কারণ ওয়্যারিং দেখা যায় না। কিন্তু মুল ইস্যুগুলো রয়ে যায়:
- প্রতি ক্লাসে অতিরিক্ত ডিপেনডেন্সি
- অস্পষ্ট মালিকানা (কে রিসোর্স তৈরি/ডিসপোজ করে?)
- “সার্ভিস লোকেটর” প্যাটার্ন যা ডিপেনডেন্সি অদৃশ্য করে এবং টেস্ট কঠিন করে
যদি একটি কন্টেইনার কোডকে কম পাঠযোগ্য করে দেয়, বা ডেভেলপাররা কি নির্ভর করে কি জানানো বন্ধ করে দেয়—তাহলে আপনি সম্ভবত অতিরিক্ত করছেন।
স্কেল করে এমন একটি ব্যালান্সড অ্যাপ্রোচ
শুরু করুন ম্যানুয়াল DI দিয়ে যাতে জিনিসগুলো স্পষ্ট থাকে যখন আপনি আপনার মডিউলগুলো গঠন করছেন। কন্টেইনার যোগ করুন যখন ওয়্যারিং পুনরাবৃত্তিমূলক হয়ে ওঠে বা লাইফসাইকেল ম্যানেজমেন্ট জটিল হয়।
একটি ব্যবহারিক নিয়ম: কোর/বিজনেস কোডের ভিতরে ম্যানুয়াল DI ব্যবহার করুন, এবং (ঐচ্ছিকভাবে) অ্যাপ বাউন্ডারিতে একটি কন্টেইনার রাখুন যাতে সবকিছু অ্যাসেম্বল করা যায়। এভাবে ডিজাইন স্পষ্ট থাকে এবং প্রোজেক্ট বাড়ার সঙ্গে বয়লারপ্লেট কমে।
সাধারণ পিটফল (এবং কীভাবে এড়াব)
DI কোডকে টেস্ট এবং পরিবর্তন করা সহজ করতে পারে—কিন্তু শৃঙ্খলা না থাকলে তা ব্যর্থও হতে পারে। নিচে সবচেয়ে সাধারণ ভুলগুলো ও সেগুলো এড়ানোর অভ্যাস।
অতিরিক্ত ইনজেকশন ("12 প্যারামিটার কনস্ট্রাকটর" সমস্যা)
যদি কোনো ক্লাস অনেক ডিপেনডেন্সি চায়, সম্ভবত সেটা অনেক বেশি কাজ করছে। এটা DI-এর ব্যর্থতা নয়—DI ডিজাইনের গন্ধ উদঘাটন করছে।
প্রায়োগিক নিয়ম: যদি আপনি ক্লাসের কাজ এক বাক্যে বর্ণনা করতে না পারেন, বা কনস্ট্রাকটর বাড়তে থাকে, ক্লাস ভাগ করুন, ছোট সহযোগী বের করুন, বা অনুরূপ অপারেশনগুলোকে এক ইন্টারফেসের পেছনে গ্রুপ করুন (সাবধানে—"গড সার্ভিস" তৈরি করবেন না)।
সার্ভিস লোকেটর: ডিপেনডেন্সি লুকিয়ে ফেলা
সার্ভিস লোকেটর প্যাটার্ন সাধারণত ব্যবসায়িক কোডের ভিতরে container.get(Foo) দেখতে পাওয়া যায়। এটি সুবিধাজনক লাগে, কিন্তু এটি ডিপেনডেন্সি অদৃশ্য করে: কনস্ট্রাকটর পড়ে বোঝা যায় না ক্লাসের কী দরকার।
টেস্ট করা কঠিন হয় কারণ গ্লোবাল স্টেট (লোকেটর) সেটআপ করতে হয়; স্পষ্ট কনস্ট্রাকটর প্যারামিটারগুলো দিয়ে টেস্টের অভিপ্রায় বোঝা যায়।
লুকানো রানটাইম ব্যর্থতা: মিসিং রেজিস্ট্রেশন ও সার্কুলার ডিপেনডেন্সি
DI কন্টেইনারগুলো রানটাইমে ব্যর্থ হতে পারে যখন:
- কোনো ডিপেনডেন্সি রেজিস্টার করা হয়নি
- একটি রেজিস্ট্রেশন বর্তমান পরিবেশের জন্য ভুল ইমপ্লিমেন্টেশন বেছে নিচ্ছে
- দুইটি সার্ভিস পরস্পরের ওপর নির্ভর করে, সার্কেল তৈরি করছে
এই সমস্যা অপ্রস্তুতিতে বিরক্তিকর কারণ সেগুলো কেবল যখন ওয়্যারিং এক্সিকিউট হয় তখনই দেখা দেয়।
ব্যবহারিক প্রতিকার
কনস্ট্রাকটরগুলো ছোট ও ফোকাসড রাখুন। যদি ডিপেনডেন্সি তালিকা বাড়ে, তা রিফ্যাক্টরের নির্দেশ মনে করুন।
ওয়্যারিংয়ের জন্য ইন্টিগ্রেশন টেস্ট রাখুন। একটি হালকা "কম্পোজিশন রুট" টেস্ট যে আপনার কন্টেইনার (বা ম্যানুয়াল ওয়্যারিং) বিল্ড করে তা মিসিং রেজিস্ট্রেশন এবং সার্কেল দ্রুত ধরবে—প্রোডাকশনের আগে।
শেষে, অবজেক্ট তৈরি এক জায়গায় (অften অ্যাপ স্টার্টআপ/কম্পোজিশন রুট) রাখুন এবং DI কন্টেইনার কলগুলো ব্যবসায়িক লজিক থেকে দূরে রাখুন। এই পৃথকরণ DI-র মূল সুবিধা রক্ষা করে: কি কী-র ওপর নির্ভর করে তা স্পষ্ট রাখা।
বিদ্যমান কোডবেসে DI পরিচয় করানোর প্র্যাকটিক্যাল ধাপ
DI গ্রহণ করা সহজ যখন আপনি এটিকে ছোট, কম-ঝুঁকিপূর্ণ রিফ্যাক্টরগুলোর সিরিজ হিসেবে দেখেন। সেখানে শুরু করুন যেখানে টেস্ট ধীর বা ফ্ল্যাকি, এবং যেখানে পরিবর্তন নিয়মিতভাবে অপ্রাসঙ্গিক কোডে ছড়িয়ে পড়ে।
দ্রুত চেকলিস্ট: কোথায় DI আগে লাভ দেয়
তালিকা খুঁজুন যেগুলো টেস্ট করা কঠিন বা বোঝা কঠিন:
- I/O: ফাইল সিস্টেম, ডাটাবেস কল, নেটওয়ার্ক অনুরোধ
- টাইম: "এখুনি", টাইম জোন, ডিলে, শিডিউলার
- র্যান্ডমনেস: UUID, র্যান্ডম নম্বর, শাফল
- বাহ্যিক API/SDK: পেমেন্ট, ইমেল, অ্যানালিটিক্স, ফিচার ফ্ল্যাগ
যদি কোনো ফাংশন প্রসেস ছাড়া চালাতে না পারে, সেটা DI-র ভালো প্রার্থী।
ধাপে ধাপে রিফ্যাক্টর (পুনরাবৃত্তিযোগ্য প্যাটার্ন)
- একটা সীম বেছে নিন: একটি একক বাহ্যিক ডিপেনডেন্সি বাছুন যা এখনই
newকরা হচ্ছে বা সরাসরি কল হচ্ছে। - একটি ইন্টারফেস/চুক্তি বের করুন: আপনি আসলে কী_behavior_ চান তা নির্দিষ্ট করুন (অften 1–3 মেথড). ছোট রাখুন।
- একটি রিয়েল ইমপ্লিমেন্টেশন তৈরি করুন: বিদ্যমান কনক্রিট ডিপেনডেন্সি কোভার করার জন্য।
- ইনজেক্ট করুন: কনস্ট্রাকটর/প্যারামিটার দিয়ে পাস করুন—সবচেয়ে সরল অপশন বেছে নিন।
- প্রোডাকশন ওয়্যারিং আপডেট করুন: আপনার অ্যাপ এন্ট্রিপয়েন্টে রিয়েল ইমপ্লিমেন্টেশন তৈরি করে পাস করুন।
- টেস্ট আপডেট করুন: রিয়েল ইমপ্লিমেন্টেশনের বদলে ফেক/স্টাব/মক ব্যবহার করুন।
এই পদ্ধতি প্রতিটি পরিবর্তন রিভিউযোগ্য রাখে এবং যেকোনো ধাপে থেমে থাকা যায় ছাড়া সিস্টেম ভাঙা ছাড়া।
ইনজেকশন করলেও মডিউল কোহেসিভ রাখার টিপস
DI ভুলভাবে ব্যবহৃত হলে কোড "সবকিছুই সবকিছুর ওপর নির্ভরশীল" হয়ে যেতে পারে যদি আপনি অত্যধিক ইনজেক্ট করেন।
ভালো নিয়ম: ক্যাপাবিলিটি ইনজেক্ট করুন, বিস্তারিত নয়। উদাহরণ: Clock ইনজেক্ট করুন, না যে "SystemTime + TimeZoneResolver + NtpClient"। যদি একটি ক্লাস পাঁচটি অপ্রাসঙ্গিক সার্ভিস চায়, এটি সম্ভবত অনেক কাজ করছে—বিভাজন বিবেচনা করুন।
আরও, অনেক লেয়ারে প্যাস-থ্রু করে ডিপেনডেন্সি না পাঠান “শুধু কেসে”; যেখানে ব্যবহার হচ্ছে সেখানে ইনজেক্ট করুন; ওয়্যারিং এক জায়গায় কেন্দ্রীভূত রাখুন।
জেনারেটেড বা স্ক্যাফোল্ড করা অ্যাপে DI সম্পর্কে একটি নোট
আপনি যদি কোড জেনারেটর ব্যবহার করেন বা দ্রুত ফিচার বানাতে স্ক্যাফোল্ড করেন, DI আরও মূল্যবান হয়ে ওঠে কারণ এটি প্রকল্প বড় হলে কাঠামো রক্ষা করে। উদাহরণস্বরূপ, যখন টিমগুলি Koder.ai ব্যবহার করে React ফ্রন্টএন্ড, Go সার্ভিস, এবং PostgreSQL-ব্যাকড ব্যাকএন্ড জেনারেট করে ছোট স্পেক থেকে, একটি স্পষ্ট কম্পোজিশন রুট ও DI-ফ্রেন্ডলি ইন্টারফেস রাখলে জেনারেটেড কোড টেস্ট, রিফ্যাক্টর এবং ইন্টিগ্রেশন বদলানো সহজ থাকে।
নিয়ম একই: অবজেক্ট তৈরি ও পরিবেশ-নির্দিষ্ট ওয়্যারিং বর্ডারে রাখুন, আর ব্যবসায়িক কোড আচরণে ফোকাস রাখুক।
পরিবর্তনের পর কী পরিমাপ করবেন
আপনি স্পষ্ট উন্নতি নির্দেশ করতে সক্ষম হওয়া উচিত:
- দ্রুততর ইউনিট টেস্ট (কম DB/নেটওয়ার্ক/টাইম অপেক্ষা)
- আরও আইসোলেটেড টেস্ট (কম গ্লোবাল সেটআপ ও শেয়ারড স্টেট)
- পরিষ্কার বাউন্ডারি (মডিউলের মাঝে স্পষ্ট চুক্তি)
- সহজ পরিবর্তন (একটি API ক্লায়েন্ট বা স্টোরেজ স্ট্র্যাটেজি বদলাতে কম এডিট)
পরবর্তী ধাপ হলে, আপনার কম্পোজিশন রুট ডকুমেন্ট করুন এবং সেটিকে "নির্বিঘ্ন" রাখুন: একটি ফাইল যা ডিপেনডেন্সি ওয়্যার করে, বাকি কোড আচরণে ফোকাস রাখে।
সাধারণ প্রশ্ন
সরল ভাষায় ডিপেনডেন্সি ইনজেকশন কী?
ডিপেনডেন্সি ইনজেকশন (DI) মানে আপনার কোড বাইরের পক্ষ থেকে যে জিনিসগুলো প্রয়োজন সেইগুলো প্রদান করা হয়, এর বদলে কোড নিজে সেগুলো তৈরি করে না (ডাটাবেস, লগার, ঘড়ি, পেমেন্ট ক্লায়েন্ট ইত্যাদি)।
প্রায়ই এটা কনস্ট্রাকটর বা ফাংশন প্যারামিটারের মাধ্যমে ডিপেনডেন্সি পাস করা হিসেবে দেখা যায়, যাতে সেগুলো স্পষ্ট এবং বদলানো যায়।
DI কিভাবে Inversion of Control (IoC) থেকে আলাদা?
ইনভার্সন অফ কন্ট্রোল (IoC) বড় ধারণাটি: একটি ক্লাসকে তার কাজ নিয়ে মনোনিবেশ করতে হবে, না কি সেটা কীভাবে তার সহযোগীরা পায়।
DI হলো সেই IoC অর্জনের একটি সাধারণ কৌশল—ডিপেনডেন্সি তৈরি করা বাইরের দিকে সরিয়ে নিয়ে সেগুলো ইনজেক্ট করা।
ব্যবসায়িক লজিকে `new` কল করলে কিভাবে টাইট কাপলিং হয়?
যখন ব্যবসায়িক লজিকে new দিয়ে ডিপেনডেন্সি তৈরি করা হয়, তখন সেটাকে বদলানো কঠিন হয়ে পড়ে।
ফলাফলগুলো:
- প্রোভাইডারে লক-ইন (যেমন চেকআউটে Stripe স্থির হয়ে থাকা)
- কনফিগারেশন ও তৈরি-বিধি ছড়িয়ে থাকার কারণে জটিলতা
- বাস্তব I/O (নেটওয়ার্ক/ডিবি/ফাইল/টাইম) ব্যবহার করে টেস্ট ধীর বা ফ্ল্যাকি হয়ে উঠা
DI কিভাবে ইউনিট টেস্টকে দ্রুত ও কম ফ্ল্যাকি করে?
DI টেস্টগুলোকে দ্রুত এবং ডিটারমিনিস্টিক রাখে কারণ আপনি প্রকৃত বহিরাগত সিস্টেমগুলোর বদলে টেস্ট ডাবল ইনজেক্ট করতে পারেন।
সাধারণ বদলগুলো:
- বাস্তব DB-এর বদলে ইন-মেমরি রিপোজিটরি
- সিস্টেম টাইমের বদলে স্টাব করা ঘড়ি
- বাস্তব ইমেল পাঠানোর বদলে মকড মেইলার
DI ব্যবহার করতে কি আমাকে DI কন্টেইনার নেয়ার হবে?
না—DI ব্যবহার করার জন্য DI কন্টেইনার আবশ্যক নয়। ছোট বা মাঝারি অ্যাপে/manual DI দিয়ে শুরু করুন (স্পষ্টভাবে ডিপেনডেন্সি পাস করা) যেখানে:
- অ্যাপ ছোট/মাঝারি
- অবজেক্ট গ্রাফ হাতে বোনা সহজ
- সর্বোচ্চ স্বচ্ছতা চান
কন্টেইনার তখন বিবেচনা করবেন যখন ওয়্যারিং পুনরাবৃত্তিমূলক বা লাইফসাইকেল ম্যানেজমেন্ট (সিঙ্গেলটন/প্রতি-রিকুয়েস্ট ইত্যাদি) দরকার হয়।
কখন কনস্ট্রাকটর বনাম মেথড বনাম সেটার ইনজেকশন ব্যবহার করা উচিত?
কনস্ট্রাকটর ইনজেকশন ব্যবহার করুন যখন ডিপেনডেন্সি অবজেক্টের কাজ করতে অপরিহার্য এবং অনেক মেথডে ব্যবহৃত হয়।
মেথড/প্যারামিটার ইনজেকশন ব্যবহার করুন যখন সেটা কেবল একবারের কাজের জন্য লাগে (উদাহরণ: রিকোয়েস্ট-স্কোপড ভ্যালু)।
সেটার/প্রপার্টি ইনজেকশন এড়িয়ে চলুন যতটা সম্ভব; যদি দরকার হয়, তাড়াতাড়ি ব্যর্থ হবে এমন ভ্যালিডেশন রাখুন।
কম্পোজিশন রুট কী এবং এটা কোথায় থাকা উচিত?
কম্পোজিশন রুট হলো যেখানে আপনি অ্যাপ অ্যাসেম্বল করেন: বাস্তব ইমপ্লিমেন্টেশনগুলো তৈরি করে সেগুলোকে সার্ভিসে পাস করেন।
এটি সাধারণত অ্যাপ স্টার্টআপ (এন্ট্রি পয়েন্ট)-এর কাছে রাখুন, যাতে বাকি কোডবেস আচরণ নিয়ে ফোকাসেড থাকে, না কি ওয়্যারিং নিয়ে।
টেস্ট সীম কী, এবং কোথায় তৈরি করা উচিত?
টেস্ট সীম (test seam) হবে এমন একটি জায়গা যেখানে আচরণ বদলানো যায়।
ভালো জায়গাগুলো সাধারণত কঠিন-পরীক্ষাযোগ্য বিষয়গুলোর চারপাশে:
- টাইম (
Clock.now()) - I/O (ফাইল স্টোর, HTTP ক্লায়েন্ট)
- বাহ্যিক সার্ভিস (পেমেন্ট, ইমেল)
DI টেস্টে এই জায়গায় বিকল্প ইমপ্লিমেন্টেশন ইনজেক্ট করে সিমুলেশন দেয়।
সাধারণ DI-র ভুলগুলো কী এবং কীভাবে এড়াব?
সাধারণ পিটফলগুলো:
- ওভার-ইনজেকশন: অনেক ডিপেনডেন্সি দেখালে ক্লাস বেশি কাজ করছে—বিভক্ত করুন।
- সার্ভিস লোকেটর:
container.get()ব্যবসায়িক কোডে ব্যবহার করলে ডিপেনডেন্সি অদৃশ্য হয়ে যায়—বাইকটন স্পষ্টভাবে পাস করুন। - রানটাইম ওয়্যারিং ত্রুটি: মিসিং রেজিস্ট্রেশন বা সার্কুলার নির্ভরতা—কম্পোজিশন রুটের ইন্টিগ্রেশন টেস্ট রাখুন।
কিভাবে বিদ্যমান কোডবেসে DI নিরাপদভাবে পরিচয় করাবো?
নিরাপদভাবে DI চালু করার ধাপগুলি:
- একটি কঠিন ডিপেনডেন্সি বাছুন (ডিবি, ঘড়ি, HTTP ক্লায়েন্ট)।
- একটি ছোট ইন্টারফেস/চুক্তি নির্ধারণ করুন।
- বিদ্যমান কনক্রিট ইমপ্লিমেন্টেশানকে তার পেছনে মোড়ান।
- কনস্ট্রাকটর/প্যারামিটার দিয়ে ইনজেক্ট করুন।
- স্টার্টআপে বাস্তব ইমপ্লিমেন্টেশন তৈরি করে পাস করুন (কম্পোজিশন রুট)।
- টেস্টগুলো আপডেট করে ফেক/স্টাব/মক ব্যবহার করুন।
প্রতিটি স্টেপ ছোট রাখুন—আপনি কোনো ধাপে থেমে থাকতে পারবেন, বড় রিরাইট ছাড়া।