TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 550 subscribers
Post #650 293
حالا Billing و Shipping دیگر نمی‌توانند مستقل تکامل پیدا کنند.
یک تغییر در Billing:
➡️ نیاز به Recompile
➡️ نیاز به Retest
➡️ نیاز به Redeploy
برای Shipping خواهد داشت.
شما دو Bounded Context را که قرار بود مستقل باشند، فقط برای صرفه‌جویی در چند Property به هم جوش داده‌اید.
داشتن دو مدل Order مستقل دقیقاً همان دلیلی است که داده‌ها باید داخل مرزهای خودشان باقی بمانند.
شباهت داشتن آن‌ها کاملاً طبیعی است.
آن‌ها یک مفهوم واقعی را از دو زاویه متفاوت مدل می‌کنند؛ زاویه‌هایی که به مرور زمان از هم فاصله خواهند گرفت.

📏 قانونی که من استفاده می‌کنم: تا بار سوم صبر کن

من بار دوم چیزی را Deduplicate نمی‌کنم.
تا بار سوم صبر می‌کنم و فقط یک سؤال می‌پرسم:
اگر این قانون تغییر کند، آیا هر دو نسخه باید با هم تغییر کنند؟

اگر پاسخ بله باشد:
✅ با تکرار واقعی روبه‌رو هستید.
✅ همان حقیقت در چند نقطه نوشته شده است.
✅ آن را استخراج کنید.
اگر پاسخ خیر باشد:
✅ شباهت فقط تصادفی است.
✅ آن را به حال خودش رها کنید.
✅ ءCoupling آینده هزینه بیشتری خواهد داشت.
اجازه دهید کد تکرار شود تا زمانی که Abstraction مناسب خودش را نشان دهد.
ءAbstractionهای خوب از مثال‌های واقعی کشف می‌شوند، نه اینکه از ابتدا حدس زده شوند.
بعضی افراد این رویکرد را AHA (Avoid Hasty Abstractions) می‌نامند.

💡 یک نشانه عملی

وقتی بتوانید مفهوم را نام‌گذاری کنید، زمان استخراج فرا رسیده است.
نام‌هایی مثل:
✅ Money
✅ TaxRate
✅ InvoiceNumber
احتمالاً دانش دامنه هستند و ارزش تبدیل شدن به Value Object را دارند.
اما اگر بهترین نامی که پیدا می‌کنید این‌ها باشد:
❌ Helper
❌ Utils
❌ ProcessData
احتمالاً در حال Abstract کردن شکل کد هستید، نه دانش.

✅ زمانی که DRY واقعاً درست است

وقتی درست استفاده شود، DRY فوق‌العاده ارزشمند است.
یک قانون کسب‌وکار باید فقط در یک مکان وجود داشته باشد.
فرض کنید قانون زیر را در سه بخش مختلف کپی کرده‌ایم:
«سفارش‌های بالاتر از ۱۰۰۰ دلار نیاز به تأیید مدیر دارند.»

// OrderService
if (order.Total > 1000) { /* require approval */ }

// CheckoutService
if (order.Total > 1000m) { /* require approval */ }

// AdminController - someone bumped the limit here, and only here
if (order.Total > 5000) { /* require approval */ }

بالاخره روزی دو مورد را تغییر می‌دهید و سومی را فراموش می‌کنید.
همین نسخه سومِ منحرف‌شده منشأ باگ خواهد بود.
قانون را به Domain Model منتقل کنید تا تنها یک خانه داشته باشد:
public bool RequiresManagerApproval() => Total > 1000;

این دقیقاً همان «نمایش یکتای مرجع» است که DRY درباره آن صحبت می‌کند.

📝 جمع‌بندی

🔹 ءDRY درباره دانش است، نه کدهایی که شبیه هم هستند.
🔹 هزینه یک Abstraction اشتباه از هزینه Duplication بیشتر است و حذف آن نیز سخت‌تر خواهد بود.
🔹 تا بار سوم صبر کنید. فقط زمانی استخراج کنید که هر دو نسخه یک حقیقت مشترک را نمایش می‌دهند و باید با هم تغییر کنند.
🔹 دفعه بعد که خواستید یک کد تکراری را حذف کنید، از خودتان نپرسید:
«آیا این دو قطعه کد شبیه هم هستند؟»
بپرسید:
«آیا معنای یکسانی دارند؟»
همین یک سؤال، دردسرهای نگهداری بیشتری را از شما دور خواهد کرد تا هر مقدار تایپ نکردنی که DRY برایتان ذخیره می‌کند. 🚀

🔖هشتگ‌ها:
#cleanarchitecture #dry #dotnetdeveloper
More from @csharpgeeks
  1. Sep 22, 2026یه مدتی قراره از دنیای NET. فاصله بگیرم، چون وقتشه برم سربازی. راستش نمیدونم این مدت رو چج…
  2. Sep 20, 2026🔥 حالا مشکل اصلی: Alert Storm فرض کن Database از دسترس خارج شده. ۱۰۰ Pod داری. هر Pod می‌…
  3. Sep 20, 2026🚨 طراحی سیستم Monitoring و Alerting در یک سیستم بزرگ فرض کن ساعت ۳ صبح است. سیستم شما با…
  4. Sep 19, 2026#Engineering_Leadership تصمیم نگرفتن هم یک تصمیم است یه چیز عجیب توی تیم‌های مهندسی: گاهی…
  5. Sep 19, 2026☑ چک‌لیست آماده‌سازی تیم، فرایندها و زیرساخت برای توسعه با AI توجه: هیچ چک‌لیستی جهان‌شمول…
  6. Sep 19, 2026📌پایان یک انتظار طولانی: اعتبارسنجی ناهمگام (Async Validation) در NET 11.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →