আমরা আমাদের ক্লিন আর্কিটেকচার সিরিজের একদম শেষ পর্যায়ে চলে এসেছি। ৬ষ্ঠ পর্বে আমরা শিখেছি কীভাবে লেয়ারগুলোর মধ্যে ডেটা অনুবাদ (Mapping) করতে হয়। এখন প্রশ্ন হলো—এই যে এতগুলো লেয়ার (Entity, Use Case, Repository, Data Source, Mapper), এদেরকে একে অপরের সাথে জোড়া লাগাবে কে?
পরবর্তী এবং অত্যন্ত গুরুত্বপূর্ণ ধাপ হলো আর্টিকেল ৭: ডিপেন্ডেন্সি ইনজেকশন (Dependency Injection – DI)।
কেন এটি পরবর্তী ধাপ?
এখন পর্যন্ত আমরা প্রতিটি লেয়ার আলাদাভাবে লিখেছি। কিন্তু একটি রিয়েল-লাইফ অ্যাপে যখন আপনি একটি স্ক্রিন ওপেন করবেন, তখন সেই স্ক্রিনের জন্য একটি UseCase লাগবে, সেই ইউজ কেসের জন্য একটি Repository লাগবে, আবার রিপোজিটরির জন্য DataSource লাগবে।
আপনি যদি ম্যানুয়ালি প্রতিটি ক্লাসের ভেতরে অন্য ক্লাসের অবজেক্ট তৈরি করেন (যেমন: final repo = UserRepositoryImpl()), তবে আপনার লেয়ারগুলো আবার একে অপরের ওপর শক্তভাবে আটকে যাবে (Tight Coupling)। এই সমস্যা সমাধান করার জন্যই আমাদের Dependency Injection প্রয়োজন।
Dependency Injection: সব লেয়ারকে সুতোয় বাঁধার কারিগর
ক্লিন আর্কিটেকচার সিরিজের আগের পর্বে আমরা ম্যাপার নিয়ে কথা বলেছি। আজ আমরা শিখবো এই সবগুলোকে একসাথে জোড়া দেওয়ার টেকনিক—Clean Architecture Dependency Injection বা সংক্ষেপে DI।
ডিপেন্ডেন্সি ইনজেকশন আসলে কী?
সহজ কথায়, একটি ক্লাসের ভেতর অন্য একটি ক্লাসের অবজেক্ট সরাসরি তৈরি না করে, বাইরে থেকে সেই অবজেক্টটিকে “সরবরাহ” বা ইনজেক্ট করাই হলো ডিপেন্ডেন্সি ইনজেকশন।
মনে করুন, আপনার GetUserUseCase-এর কাজ করার জন্য UserRepository প্রয়োজন। আপনি যদি ইউজ কেসের ভেতরেই রিপোজিটরি তৈরি করেন, তবে সেই ইউজ কেসটি নির্দিষ্ট একটি রিপোজিটরির সাথে আটকে গেল। কিন্তু আপনি যদি বাইরে থেকে রিপোজিটরি পাঠাতে পারেন, তবে আপনি চাইলেই টেস্ট করার সময় একটি ‘ফেক রিপোজিটরি’ পাঠাতে পারবেন।
কেন Clean Architecture Dependency Injection জরুরি?
১. লুজলি কাপলড কোড: আপনার ক্লাসগুলো জানে না তাদের ডিপেন্ডেন্সিগুলো আসলে কীভাবে তৈরি হয়েছে। তারা শুধু জানে তাদের কিছু একটা প্রয়োজন। ২. সহজ টেস্টিং: টেস্ট করার সময় আপনি আসল ডাটাবেস বা এপিআই-এর বদলে মক (Mock) অবজেক্ট ইনজেক্ট করতে পারেন। ৩. কোড মেইনটেন্যান্স: প্রজেক্ট যত বড় হবে, প্রতিটি লেয়ার ম্যানুয়ালি হ্যান্ডেল করা তত কঠিন হবে। DI আপনার জন্য এই কাজটি অটোমেটিক করে দেয়।
প্র্যাকটিক্যাল কোড ইমপ্লিমেন্টেশন (GetIt ব্যবহার করে)
ফ্লাটারে ডিপেন্ডেন্সি ইনজেকশনের জন্য সবচাইতে জনপ্রিয় প্যাকেজ হলো GetIt। চলুন দেখি এটি দিয়ে কীভাবে আমাদের লেয়ারগুলোকে কানেক্ট করবো।
ধাপ ১: সার্ভিস লোকেটার সেটআপ
final sl = GetIt.instance; // sl মানে Service Locator
Future<void> init() async {
// Use Cases
sl.registerLazySingleton(() => GetUserUseCase(sl()));
// Repositories
sl.registerLazySingleton<UserRepository>(
() => UserRepositoryImpl(remoteDataSource: sl()),
);
// Data Sources
sl.registerLazySingleton<UserRemoteDataSource>(
() => UserRemoteDataSourceImpl(client: sl()),
);
// External Libraries (যেমন: HttpClient)
sl.registerLazySingleton(() => http.Client());
}
ম্যাজিকটা কোথায়?
খেয়াল করুন, GetUserUseCase(sl())-এ আমি কোনো নির্দিষ্ট রিপোজিটরি দিইনি। শুধু sl() লিখেছি। GetIt অটোমেটিক খুঁজে বের করবে যে এই ইউজ কেসের জন্য কোন রিপোজিটরি রেজিস্টার করা আছে এবং সেটি সেখানে ইনজেক্ট করে দেবে।
সারকথা
Clean Architecture Dependency Injection হলো আপনার অ্যাপের সেই কাঠামো যা সব লেয়ারকে স্বাধীন রেখেও এক সুতোয় বেঁধে রাখে। এটি ছাড়া আপনার অ্যাপ কখনোই স্কেলেবল হবে না।
পরবর্তী এবং আমাদের সিরিজের শেষ পর্বে আমরা আলোচনা করবো Complete Project Structure নিয়ে—যেখানে আমরা দেখবো এই সব লেয়ারগুলো ফ্লাটার প্রজেক্টের ফোল্ডারে কীভাবে সাজাতে হয়।
গেট-ইট সম্পর্কে আরও জানতে GetIt Package on pub.dev দেখতে পারেন।