تصور کن یه درخت قدیمی و پوسیده تو باغت داری، نمیتونی یهو قطعش کنی چون کل باغ رو به هم میریزه. به جاش، یه درخت جدید (مثل Strangler Fig تو جنگلهای استرالیا) رو میکاری که به تدریج دورش میپیچه، شاخههاش رو میپوشونه، و آخرش درخت قدیمی رو کامل جایگزین میکنه. بدون اینکه باغت یه لحظه بیدرخت بمونه. حالا اینو اگر ببریمش تو دنیای نرمافزار، الگوی Strangler Fig Pattern همون روشه برای جایگزینی سیستمهای قدیمی (legacy) با کد جدید، بدون اینکه سیستم از کار بیفته یا کاربرها متوجه بشن. بر اساس مقاله Chris Richardson در Microservices.io، این الگو بخشی از مدرنسازی تدریجیه که کمک میکنه سیستمهای مونولیتیک رو کمکم به سرویسهای مستقل تبدیل کنی.

سیستمهای legacy (اونایی که سالها پیش نوشته شدن) اغلب مثل یه درخت کهنهان، کار میکنن، اما نگهداریشون گرونه، تغییر دادنشون خطرناکه، و مقیاسپذیریشون محدوده. اگه بخوای یهو همه چیز رو عوض کنی (مثل Big Bang Migration)، ریسک downtime و از دست دادن دادهها زیاده – و ممکنه پروژهت رو به خاک سیاه بنشونی!
الگوی Strangler Fig (مقاله مارتین فاولر رو حتما بخونید) راه حل چنین مسئله ای هست. یه سیستم جدید رو کنار قدیمی میسازی، ترافیک رو کمکم به جدید منتقل میکنی، و قدیمی رو به تدریج خاموش میکنی. مثل همون درخت Strangler Fig که درخت میزبان رو آروم آروم میخوره!

این الگو مثل یه پروکسی (واسط) عمل میکنه، یه لایه جدید (Strangler) رو جلوی سیستم قدیمی میزاریم که درخواستها رو مدیریت کنه. بعد، بخش به بخش، کد قدیمی رو با جدید جایگزین میکنیم. این الگو بخشی از Architectural Decompositionهست، یعنی تجزیه سیستم به اجزای کوچیکتر، بدون اینکه کل سیستم رو از نو بسازیم.
مراحل کلی:
ساخت لایه Strangler: یه پروکسی (مثل API Gateway یا یه اپلیکیشن ساده) باید ساخته بشه که همه درخواستها رو بگیره و به سیستم قدیمی بفرسته.
مثلاً: درخواستهای کاربرها به legacy backend فرستاده بشه.
جایگزینی تدریجی: بخشهای کوچیک یکی یکی با کد جدید جایگزین بشن. مثلاً اول "مدیریت کاربر" جدید ساخته بشه، ترافیکش رو به سرویس جدید ببریم، و قدیمی رو خاموش کنیم.
انتقال کامل: وقتی همه بخشها جدید شدن، Strangler رو هم حذف کنیم.
نکته: همیشه fallback به قدیمی داشته باشیم تا اگه سرویس جدید مشکل داشت، سریع بتونیم برگردیم.
مثلا بیایید یک سیستم فروشگاهی قدیمی رو درنظر بگیریم. Strangler اول درخواستهای لیست محصولات رو میگیره و به legacy میفرسته. بعد، یه سرویس جدید برای محصولات میسازیم، ترافیک رو کمکم (مثل ۱۰٪ اول) به جدید میبریم، و وقتی مطمئن شدیم، کامل منتقل میکنیم. اینطوری میزان دان تایم کاهش پیدا میکنه و از سرویس جدید هم (از این نظر) اطمینان پیدا میکنیم.

بدون downtime: سیستم همیشه آنلاینه، چون قدیمی رو آروم آروم خاموش میکنیم.
ریسک کم: بخشهای کوچیک رو تست میکنیم، اگه مشکلی بود، برمیگردیم به قدیمی.
بهبود تدریجی: میتونیم معماری های جدیدی (مثل میکروسرویسها) رو بدون بازنویسی کل سیستم اضافه کنیم.
مناسب برای legacy: برای سیستمهای قدیمی که مستندات ندارن یا تستشون سخته، گزینه خیلی خوبیه.
انعطافپذیری: میتونیم از مونولیت به ماژولار مونولیت یا میکروسرویسها بریم با دردسرهای خیلی کمتر.
زمانبر: ممکنه ماهها یا سالها طول بکشه، چون باید همه چیز تست بشن (مخصوصا سناریوهای خاص که بعدا سیستم و سرویس ها رو دست خوش تغییرات برای شرایط خاص میکنه).
پیچیدگی موقت: Strangler خودش یه لایه اضافیه که باید مدیریت بشه. یعنی داریم دوتاسیستم رو همزمان نگهداری میکنیم و یکیشون درحال توسعه است.
مدیریت ترافیک: باید مطمئن بشیم که ترافیک درست تقسیم میشه (مثلا با feature flags).
تست سخت: تست همزمان قدیمی و جدید میتونه پیچیده باشه.
توی سایت Microservices.io یک مثالی از فروشگاه آنلاینی میزنه که یک legacy با ۵۰۰K خط کد، به سه تا ماژول (کاربران، سفارشات، موجودی) تقسیم شد. Strangler پروکسی استفاده کردن و ترافیک رو ۲۰٪ به جدید رسوندن، تو این حالت downtime صفر داشتن و همینطور سرعت ۳۰٪ بهتر شد. حتما پیشنهاد میکنم این مطلب رو توی سایتش پیدا کنید و بخونید.
الگوی Strangler Fig مثل یه درخت هوشمند عمل میکنه، قدیمی رو آروم آروم جایگزین میکنه بدون اینکه باغت (سیستم) از کار بیفته. اگه با سیستم قدیمی دست و پنجه نرم میکنید، از DDD برای مرزبندی ها، تستهای قوی، و پروکسی ساده شروع کنید. این روش نه تنها سیستم رو زنده نگه میداره، بلکه راه رو برای آینده (مثل میکروسرویسها) باز میکنه تا بعدا تصمیم بهتری برای آینده ی سیستم بگیرید.