🧩 راحتیِ اشتباهِ “Happy Path”: جدا کردن سرویسها از یکدیگر
بیایید صادق باشیم: همهٔ ما این کد را نوشتهایم. 😅
صبح دوشنبه است، یک ددلاین دارید، و باید یک قابلیت ثبتنام کاربر را پیادهسازی کنید. کار سادهای است: کاربر را ذخیره کنید، یک ایمیل خوشآمد بفرستید، و ثبتنام را در داشبورد analytics خود ثبت کنید.
شما این را مینویسید:
public class UserService(
IUserRepository userRepository,
IEmailService emailService,
IAnalyticsService analyticsService)
{
public async Task RegisterUser(string email, string password)
{
var user = new User(email, password);
await userRepository.SaveAsync(user);
// 1. Directly coupled to email service (external API)
await emailService.SendWelcomeEmail(user.Email);
// 2. Directly coupled to analytics (this could be an external API)
await analyticsService.TrackUserRegistration(user.Id);
// What if we need to add more features?
// This method will keep growing...
}
}
ظاهرش تمیز است. خوانا است. روی ماشین شما هم کار میکند.
اما این متد یک بمب ساعتی است. 💣
این متد فرض میکند فقط Happy Path وجود دارد.
فرض میکند شبکه همیشه پایدار است، سرویس ایمیل همیشه در دسترس است، و API مربوط به analytics همیشه سریع است.
در محیط production هیچکدام تضمینشده نیست. ⚠️
اگر بیشتر فکر کنید، احتمالاً مثال مشابهی را در پروژههای خودتان هم دیدهاید. ممکن است همین سناریو نباشد، اما الگو یکسان است:
یک متد که به شکل خطی چندین Side Effect را مدیریت میکند.
بیایید بررسی کنیم چرا این کد خطرناک است و چطور میتوان آن را به یک معماری Event-driven مقاوم تبدیل کرد. 🚀
🔍 خطرات پنهان در “God Method”
سه مشکل اساسی در همین ده خط کد وجود دارد.
1️⃣ Temporal Coupling (تأخیر و زمانوابستگی) ⏳
وقتی کاربر روی "Register" کلیک میکند، باید منتظر بماند برای:
Database
SMTP Server
Analytics API
اگر سرویس analytics امروز حالش خوب نباشد و پاسخگوییاش ۳ ثانیه طول بکشد،
کاربر شما هم باید ۳ ثانیه صبر کند.
شما در واقع کاربر را به خاطر کندی یک سیستم پسزمینه که حتی برایش مهم نیست مجازات میکنید. 😐
2️⃣ Partial Failure State (وضعیت شکست جزئی) 💥
این مهمترین ریسک است. تصور کنید:
SaveAsync(user) موفق میشود →
کاربر در DB ذخیره میشود.
SendWelcomeEmail موفق میشود
→ کاربر ایمیل خوشآمد را دریافت میکند.
TrackUserRegistration یک خطای
503 Service Unavailable میدهد.
حالا چه؟ 🤔
اگر همه چیز را داخل transaction بگذارید و rollback کنید:
🔸️کاربر از دیتابیس حذف میشود
🔸️اما ایمیل خوشآمد را قبلاً دریافت کرده است
🔸️کاربر تلاش میکند وارد شود → وجود ندارد
🔸️یک تجربهٔ کاربری فاجعهبار.
اگر rollback نکنید:
🔹️کاربر در سیستم هست
🔹️اما در analytics ثبت نشده
🔹️عدم سازگاری داده (Data Inconsistency) ایجاد شده است