হ্যালো! আমি তোমার Simple Coding Tutor। বর্তমান লেকচারটি তোমার কোর্সের Section 15-এর একটি খুবই গুরুত্বপূর্ণ লেকচার, যার নাম “Add Country - xUnit Test - Part 1”। এখানে মূলত Domain Model এবং DTO (Data Transfer Object) এর কনসেপ্টগুলো প্র্যাকটিক্যালি ইমপ্লিমেন্ট করা শুরু হয়েছে।
চলো, এই লেকচারটির সম্পূর্ণ বিষয়বস্তু ধাপে ধাপে এবং সহজভাবে বুঝে নিই।
📝 লেকচার সামারি (Summary for Quick Revision)
ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য পুরো লেকচারের মূল বিষয়গুলো নিচে তালিকাভুক্ত করা হলো:
- Goal of the Lecture:
addCountryমেথডের জন্য Unit Test লেখার প্রস্তুতি নেওয়া। TDD (Test-Driven Development) অনুযায়ী আগে টেস্ট লেখা হবে, তারপর মেথডটি ইমপ্লিমেন্ট করা হবে। - How
addCountryworks: Controller থেকেCountryAddRequest(DTO) আসবে। Service সেটাকে ভ্যালিডেট করবে,Country(Domain Model) এ কনভার্ট করে ডেটাবেস/লিস্টে অ্যাড করবে এবং রিটার্ন হিসেবেCountryResponse(DTO) পাঠাবে। - Entities Project: ডাটাবেস টেবিল রিপ্রেজেন্ট করার জন্য
Entitiesনামে একটি নতুন Class Library প্রজেক্ট তৈরি করা হয়েছে এবং সেখানেCountryডোমেইন মডেল তৈরি করা হয়েছে। - ServiceContracts Project: Interfaces এবং DTOs রাখার জন্য
ServiceContractsনামে আরেকটি Class Library তৈরি করা হয়েছে। - DTO Creation:
CountryAddRequestক্লাস তৈরি করা হয়েছে, যার মধ্যে শুধুCountryNameআছে (CountryID নেই, কারণ এটি সিস্টেম জেনারেট করবে)। - Conversion Method:
CountryAddRequestকেCountryঅবজেক্টে সহজে কনভার্ট করার জন্যToCountry()নামে একটি মেথড তৈরি করা হয়েছে।
🧠 Comprehensive Breakdown (বিস্তারিত আলোচনা)
১. Understanding the Flow: Request, Domain, and Response [Priority: 10/10]
লেকচারের শুরুতেই ইন্সট্রাক্টর পুরো আর্কিটেকচারাল ফ্লো-টা ক্লিয়ার করেছেন।
- TDD Approach: আমরা
addCountryমেথডটি ইমপ্লিমেন্ট করার আগেই এর জন্য Unit Test লিখব। - The Process: 1. ইউজার একটি দেশের নাম ইনপুট দিবে।
- Controller সেই ডেটাটিকে
CountryAddRequest(Request DTO) অবজেক্ট হিসেবে Service-এর কাছে পাঠাবে। (লক্ষ্য করো, এখানেCountryIDথাকবে না, কারণ আইডি ডেটাবেস বা সিস্টেম নিজে জেনারেট করবে)। - Service সেই ডেটা ভ্যালিডেট করবে।
- Service এই DTO-কে
Country(Domain Model) অবজেক্টে রূপান্তর করবে এবং ডেটাস্টোরে (লিস্ট বা ডেটাবেস) সেভ করবে। - সেভ হওয়ার পর Service একটি
CountryResponse(Response DTO) অবজেক্ট রিটার্ন করবে, যার মধ্যে জেনারেট হওয়াCountryIDএবংCountryNameদুটোই থাকবে।
২. Domain Model (Entities Project) [Priority: 9/10]
রিয়েল-ওয়ার্ল্ড প্রজেক্টে ডেটাবেসের টেবিলগুলোকে রিপ্রেজেন্ট করার জন্য ক্লাসগুলোকে আলাদা একটি প্রজেক্টে রাখা হয়, যাকে Entities বা Domain Models বলা হয়।
- প্রজেক্ট তৈরি:
Entitiesনামে একটি Class Library তৈরি করা হয়েছে। CountryClass: এই ক্লাসেCountryIDএবংCountryNameপ্রপার্টি রাখা হয়েছে।- GUID ব্যবহার:
CountryIDএর ডেটা টাইপ হিসেবেGuid(Globally Unique Identifier) ব্যবহার করা হয়েছে। - কেন GUID? Integer বা Long ব্যবহার করলে একটি নির্দিষ্ট লিমিট (Max Value) থাকে। কিন্তু GUID (বা Guide) একটি রেন্ডম এবং ইউনিক স্ট্রিং যা আনলিমিটেড ডেটার জন্য পারফেক্ট। এটি মূলত টাইমস্ট্যাম্প, রেন্ডম নাম্বার এবং কম্পিউটারের ম্যাক এড্রেস মিলিয়ে জেনারেট হয়।
Code Implementation (Entities/Country.cs):
namespace Entities
{
/// <summary>
/// Domain Model for Country
/// </summary>
public class Country
{
// GUID is used for limitless unique IDs
public Guid CountryID { get; set; }
// ? means it is a nullable string
public string? CountryName { get; set; }
}
}
৩. DTOs and Interfaces (ServiceContracts Project) [Priority: 10/10]
Domain Model-কে সরাসরি Controller বা UI এর কাছে এক্সপোজ (expose) করা সিকিউরিটি এবং আর্কিটেকচারের দিক থেকে খারাপ প্র্যাকটিস। এর জন্যই DTO বা Data Transfer Object ব্যবহার করা হয়।
- প্রজেক্ট তৈরি:
ServiceContractsনামে আরেকটি Class Library তৈরি করা হয়েছে। - Interface: Dependency Injection এর জন্য
ICountryServiceইন্টারফেস তৈরি করা হয়েছে (যদিও এর ইমপ্লিমেন্টেশন পরের লেকচারে দেখানো হবে)। - Request DTO:
DTOফোল্ডারের ভেতরCountryAddRequestক্লাস তৈরি করা হয়েছে। এতে শুধুCountryNameআছে।
Code Implementation (ServiceContracts/DTO/CountryAddRequest.cs):
using Entities; // Entities প্রজেক্টের রেফারেন্স অ্যাড করা হয়েছে
namespace ServiceContracts.DTO
{
/// <summary>
/// DTO class for adding a new country
/// </summary>
public class CountryAddRequest
{
public string? CountryName { get; set; }
/// <summary>
/// Converts the current DTO object into a Domain Model object
/// </summary>
public Country ToCountry()
{
return new Country()
{
CountryName = this.CountryName
// Note: CountryID is not set here, it will be generated later by the service/database
};
}
}
}
৪. Project References [Priority: 8/10]
যেহেতু ServiceContracts প্রজেক্টের ভেতরে Entities প্রজেক্টের Country ক্লাসটি ব্যবহার করা হচ্ছে (উপরের ToCountry মেথডে), তাই ServiceContracts প্রজেক্টে Entities প্রজেক্টের Reference অ্যাড করতে হবে।
- কিভাবে করবে?
ServiceContractsপ্রজেক্টেরDependenciesএ Right-click ->Add Project Reference->Entitiesপ্রজেক্টে টিক চিহ্ন দিয়ে OK করতে হবে।
💡 Best Practices & Modern .NET Updates
- XML Documentation Comments: ক্লাসের বা মেথডের উপরে
///টাইপ করলে Visual Studio স্বয়ংক্রিয়ভাবে একটি<summary>ট্যাগ তৈরি করে দেয়। এটি একটি এক্সিলেন্ট বেস্ট প্র্যাকটিস। এতে অন্য ডেভেলপাররা ওই ক্লাসের উপর হোভার (Hover) করলেই বুঝতে পারে ক্লাসটির কাজ কী। - Sealed DTOs: DTO ক্লাসগুলো সাধারণত ইনহেরিট (inherit) করার প্রয়োজন হয় না। তাই বেস্ট প্র্যাকটিস হলো DTO ক্লাসগুলোকে
sealedকরে দেওয়া। এতে পারফরম্যান্স কিছুটা ভালো হয়। (যেমন:public sealed class CountryAddRequest) - .NET 10 Context / C# Records: .NET 9 বা .NET 10 এ DTO তৈরি করার সবচেয়ে আধুনিক এবং স্মার্ট পদ্ধতি হলো
classএর বদলে C# 9+ এরrecordব্যবহার করা।recordডাটা-ক্যারিং অবজেক্টের জন্য বেস্ট, কারণ এগুলো Immutable এবং ব্যাকগ্রাউন্ডে অনেক বয়লারপ্লেট কোড কমিয়ে দেয়।
Updated Modern Implementation (C# Record for DTO): তুমি চাইলে তোমার DTO কে এভাবেও লিখতে পারো, যা আধুনিক .NET প্রজেক্টে বেশি মানানসই:
// Modern way using C# Record
public record CountryAddRequest(string? CountryName)
{
public Country ToCountry()
{
return new Country { CountryName = this.CountryName };
}
}
এটি অনেক ক্লিন এবং আধুনিক! তবে কোর্সের ধারাবাহিকতা বজায় রাখতে তুমি লেকচারের কোডও ফলো করতে পারো।