হ্যালো হাসিব! আমরা আর্কিটেকচার রিফ্যাক্টরিংয়ের খুব মজার একটি ধাপে আছি।
আগের লেকচারগুলোতে আমরা Repositories ইমপ্লিমেন্ট করেছিলাম। এই লেকচারটিতে আমরা আমাদের CountriesService-কে রিফ্যাক্টর করে সরাসরি DbContext (Data Access Layer) থেকে ডিসকানেক্ট করে ICountriesRepository-এর সাথে কানেক্ট করেছি।
চলো লেকচারটির একটি কুইক সামারি এবং বিস্তারিত আলোচনা শুরু করি।
📝 Lecture Summary at a Glance
- Project Reference:
Servicesপ্রজেক্টেRepositoryContracts(শুধু ইন্টারফেসগুলো) এর রেফারেন্স অ্যাড করা হয়েছে। - Dependency Injection:
CountriesService-এর কনস্ট্রাক্টরেApplicationDbContextমুছে ফেলে তার জায়গায়ICountriesRepositoryইনজেক্ট করা হয়েছে। - Code Refactoring: সার্ভিস লেয়ারে যেখানে যেখানে
_db.Countries...ছিল, সেখানে সেখানে রিপোজিটরির মেথডগুলো (যেমন:_countriesRepository.AddCountry()) কল করা হয়েছে। - The Broken Tests: সার্ভিস ক্লাসের কনস্ট্রাক্টর চেঞ্জ হওয়ার কারণে
CountriesServiceTestএবংPersonsServiceTest-এ কম্পাইল এরর আসছিল, যা সাময়িকভাবেnullপাস করে ফিক্স করা হয়েছে (পরে এগুলোতে Repository Mock করা হবে)।
🧠 Comprehensive Breakdown & Deep Dive
১. Injecting Repository Instead of DbContext [Importance: 10/10]
- The “Why”: এটিই Clean Architecture-এর মূল পয়েন্ট। Service Layer কখনো ডাটাবেসকে সরাসরি চিনবে না। সে শুধু রিপোজিটরিকে চিনবে। এতে ভবিষ্যতে তুমি যদি SQL Server থেকে MongoDB-তে সুইচ করো, তোমার Service Layer-এ এক লাইন কোডও চেঞ্জ করতে হবে না!
💻 Code Implementation (CountriesService.cs):
using RepositoryContracts; // DbContext এর বদলে রিপোজিটরি ইন্টারফেস
public class CountriesService : ICountriesService
{
// ❌ Old Way:
// private readonly ApplicationDbContext _db;
// ✅ Modern Way (Loose Coupling):
private readonly ICountriesRepository _countriesRepository;
public CountriesService(ICountriesRepository countriesRepository)
{
_countriesRepository = countriesRepository;
}
}
২. Refactoring Service Methods [Importance: 9/10]
- The “Why”: আগে সার্ভিস লেয়ার নিজেই ডাটাবেসে
Add,Save, বাWhereকুয়েরি করতো। এখন সে শুধু রিপোজিটরিকে রিকোয়েস্ট করবে।
💻 Code Implementation (Example 1: AddCountry):
public async Task<CountryResponse> AddCountry(CountryAddRequest? countryAddRequest)
{
// ... validation logic ...
// ❌ Old Way (Direct DB Access & Save):
// _db.Countries.Add(country);
// await _db.SaveChangesAsync();
// ✅ New Way (Delegate to Repository):
await _countriesRepository.AddCountry(country);
return country.ToCountryResponse();
}
💻 Code Implementation (Example 2: UploadCountries):
// এক্সেল থেকে আপলোড করার সময় ডুপ্লিকেট চেক করা
// ❌ Old Way:
// if (await _db.Countries.CountAsync(temp => temp.CountryName == countryName) == 0)
// ✅ New Way:
var matchingCountry = await _countriesRepository.GetCountryByCountryName(countryName);
if (matchingPerson == null)
{
// ইনসার্ট লজিক
await _countriesRepository.AddCountry(newCountry);
}
৩. The Broken Unit Tests (The Cliffhanger) [Importance: 10/10]
- The “Why”: আমরা যখন
CountriesServiceএর কনস্ট্রাক্টর চেঞ্জ করেICountriesRepositoryবসালাম, তখন টেস্ট প্রজেক্টে তো আগে থেকেইnew CountriesService(dbContext)লেখা ছিল। ফলে পুরো টেস্ট প্রজেক্ট ক্র্যাশ করলো। - The Temporary Fix: লেকচারার সাময়িকভাবে
new CountriesService(null)দিয়ে বিল্ড এরর ফিক্স করেছেন। - The Real Fix (Next Section): আমরা যখন
DbContextইউজ করতাম, তখন আমরাDbContextMockইউজ করেছিলাম। এখন যেহেতু সার্ভিস লেয়ারDbContextব্যবহার করে না, তাই আমাদেরDbContextMockপুরোটাই ডিলিট করে দিতে হবে। এর বদলে আমরাMoqলাইব্রেরি দিয়েICountriesRepository-কে মক (Mock) করবো। এটি অনেক বেশি ক্লিন এবং সেফ!
🚀 Modern .NET Architecture Notes & Pro Tips
১. The Danger of Passing null in Tests:
হাসিব, লেকচারার সাময়িকভাবে null পাস করেছেন। তুমি যদি এই অবস্থায় টেস্ট রান করো, তোমার সবগুলো টেস্ট NullReferenceException খেয়ে ফেইল করবে! কারণ সার্ভিস যখন রিপোজিটরি মেথড কল করতে যাবে, তখন সে দেখবে রিপোজিটরি অবজেক্টটি null। তাই রিয়েল প্রজেক্টে কখনোই এই কাজ করবে না, সাথে সাথেই Mock সেটআপ করে ফেলবে।
২. Understanding the Flow (Request to Database):
এখন তোমার প্রজেক্টের ফ্লো (Data Flow) ঠিক এরকম দাঁড়ালো:
Controller (রিসিভ রিকোয়েস্ট) ➡️ Service (ভ্যালিডেশন ও বিজনেস লজিক) ➡️ Repository (ডাটাবেস লজিক) ➡️ Entity Framework / SQL Server।
এটিই হলো ইন্ডাস্ট্রির স্ট্যান্ডার্ড N-Tier Architecture।
পরবর্তী লেকচারে আমরা PersonsService কেও একইভাবে রিফ্যাক্টর করে IPersonsRepository-এর সাথে কানেক্ট করবো। তুমি রেডি হলে পরের ট্রান্সক্রিপ্টটি দিতে পারো!