تطبيقي المونوليثي كان وحشًا: كيف أنقذني نمط ‘التين الخانق’ (Strangler Fig) من جحيم التحديث المستحيل؟

يا جماعة الخير، السلام عليكم ورحمة الله. معكم أخوكم أبو عمر.

قبل كم سنة، وقع بين إيدي مشروع… يا ساتر! تطبيق ضخم وقديم لإدارة علاقات العملاء (CRM)، مكتوب بلغة وتقنيات عفى عليها الزمن. كان التطبيق عبارة عن كتلة واحدة متراصة، أو زي ما بنحكي بلغة المبرمجين “مونوليث” (Monolith). كان هذا المونوليث هو قلب الشركة النابض، كل عمليات البيع والدعم والتسويق بتمر من خلاله.

المشكلة؟ كان وحشًا لا يمكن المساس به. كل ما نحاول نضيف ميزة جديدة، حتى لو كانت بسيطة زي تغيير لون زر، “بتولع” الدنيا وبتبدأ المشاكل تظهر في أماكن ما إلها أي علاقة. فريق التطوير كان مرعوبًا من مجرد التفكير في عمل “deploy” جديد. كنا في جحيم حقيقي اسمه “التحديث المستحيل”. أذكر مرة طلب منا مدير المنتج إضافة بوابة دفع جديدة… يا زلمة، قعدنا شهرين بس بنحاول نفهم كيف الكود مربوط ببعضه، وفي النهاية فشلنا فشلًا ذريعًا وتسببنا بتوقف النظام لساعات.

في ليلة من ليالي الإحباط، وأنا ببحث عن حلول سحرية، قرأت مقالة لمارتن فاولر عن نمط معماري اسمه “نمط التين الخانق” (Strangler Fig Pattern). الاسم غريب، بس الفكرة كانت عبقرية وبسيطة لدرجة إنها بدت كطوق نجاة أُرسل لنا من السماء. ومن هنا، بدأت رحلة ترويض الوحش.

ما هو التطبيق المونوليثي؟ ولماذا هو جحيم متنقل؟

قبل ما ندخل في تفاصيل الحل، خلينا نوصف المشكلة صح. التطبيق المونوليثي هو تطبيق تم بناؤه كوحدة واحدة متكاملة. كل شيء – واجهة المستخدم، منطق العمل (Business Logic)، الوصول للبيانات – كله موجود في قاعدة كود واحدة (codebase) ويتم تشغيله كعملية واحدة (single process).

تخيلها زي “طبخة المقلوبة” بالضبط. كل المكونات (رز، دجاج، باذنجان) مطبوخة مع بعض في طنجرة واحدة. لو بدك تغير طعم الباذنجان بس، مستحيل! لازم تفكك الطبخة كلها وتعيدها من الأول. هذا هو المونوليث.

أبرز مشاكل المونوليث:

  • صعوبة التحديث: أي تغيير صغير يتطلب اختبار وإعادة نشر التطبيق بأكمله، مما يزيد من المخاطرة والوقت.
  • التعقيد المتزايد: مع مرور الوقت، يصبح الكود متشابكًا لدرجة يصعب معها فهمه أو صيانته. نسميه بالعامية “كود معكرونة” (Spaghetti Code).
  • صعوبة التوسع (Scalability): إذا كان جزء واحد فقط من التطبيق عليه ضغط كبير (مثلاً، خدمة البحث)، يجب عليك عمل نسخة كاملة من التطبيق لتلبية هذا الضغط، وهذا هدر كبير للموارد.
  • قيود التكنولوجيا: أنت عالق مع التقنيات التي بدأ بها المشروع. هل تريد تجربة لغة برمجية جديدة أو قاعدة بيانات أحدث؟ حظًا موفقًا في إقناع المونوليث بذلك!

كان المونوليث الذي أعمل عليه يعاني من كل هذه المشاكل وأكثر. كان وحشًا يلتهم وقتنا وجهدنا وأعصابنا.

شجرة التين الخانقة: طوق النجاة من الطبيعة

اسم النمط مستوحى من شجرة التين الخانق في الغابات الاستوائية. هذه الشجرة الذكية تبدأ حياتها كبذرة صغيرة على أغصان شجرة قديمة ضخمة. ثم تبدأ بإنزال جذورها ببطء نحو الأرض، وتنمو حول الشجرة المضيفة. مع مرور السنين، تنمو جذوع التينة الخانقة وتصبح أقوى وأسمك، وتحجب الشمس والموارد عن الشجرة القديمة، حتى تموت الشجرة القديمة وتتحلل، وتبقى شجرة التين الخانقة مكانها قوية وشامخة.

هذه هي الفكرة بالضبط في عالم البرمجيات! بدلاً من إعادة كتابة التطبيق المونوليثي بالكامل في مشروع ضخم ومحفوف بالمخاطر (Big Bang Rewrite)، نقوم ببناء النظام الجديد تدريجيًا “حول” النظام القديم. ومع مرور الوقت، يأخذ النظام الجديد وظائف القديم قطعة قطعة، حتى “يختنق” النظام القديم تمامًا ويمكننا إيقافه بأمان.

كيف طبّقت نمط الخانق خطوة بخطوة؟ (قصة ترويض الوحش)

في مشروعنا، قررنا أن نبدأ بأكثر جزء يسبب لنا الألم: وحدة إدارة المنتجات. كانت بطيئة، صعبة التحديث، والكل يكره التعامل معها. هنا كانت خطواتنا العملية:

الخطوة الأولى: بناء “الواجهة الخانقة” (The Strangler Façade)

أول وأهم خطوة هي وضع “وسيط” بين المستخدمين والتطبيق المونوليثي. هذا الوسيط هو الذي سيقوم بتوجيه الطلبات. في حالتنا، كان هذا الوسيط عبارة عن Reverse Proxy بسيط باستخدام NGINX (يمكن استخدام أي تقنية مشابهة مثل API Gateway أو حتى قطعة برمجية بسيطة).

في البداية، كل ما فعله هذا البروكسي هو تمرير جميع الطلبات كما هي إلى المونوليث القديم. لم يلاحظ المستخدمون أي فرق.

# NGINX Configuration - Phase 1
# All traffic goes to the old monolith

server {
    listen 80;
    server_name my-awesome-app.com;

    location / {
        # Proxy all requests to the legacy monolith
        proxy_pass http://legacy-monolith-app:8080;
        proxy_set_header Host $host;
    }
}

هذه الخطوة، رغم بساطتها، هي حجر الأساس. الآن أصبحنا نتحكم في تدفق الطلبات بالكامل.

الخطوة الثانية: بناء الخدمة المصغرة الجديدة

بدأ فريق صغير بالعمل على بناء خدمة مصغرة (Microservice) جديدة لإدارة المنتجات. استخدمنا تقنيات حديثة (Node.js و MongoDB) مما أعطى الفريق دفعة معنوية هائلة. هذه الخدمة الجديدة لها قاعدة بياناتها الخاصة ومنطقها الخاص.

ركزنا فقط على وظائف قراءة المنتجات في البداية (GET requests) لتكون المخاطرة أقل ما يمكن.

الخطوة الثالثة: الخنق التدريجي (The Fun Part!)

هنا يبدأ السحر. قمنا بتحديث إعدادات NGINX. الآن، أي طلب يبدأ بـ /api/products سيتم توجيهه إلى الخدمة المصغرة الجديدة. أي طلب آخر (مثل /api/orders أو /api/users) سيظل يذهب إلى المونوليث القديم.

# NGINX Configuration - Phase 2
# Strangling the products API

upstream monolith_server {
    server legacy-monolith-app:8080;
}

upstream new_products_service {
    server new-products-microservice:3000;
}

server {
    listen 80;
    server_name my-awesome-app.com;

    # STRANGLE: Route product-related traffic to the new service
    location /api/products {
        proxy_pass http://new_products_service;
        proxy_set_header Host $host;
    }

    # All other traffic still goes to the monolith
    location / {
        proxy_pass http://monolith_server;
        proxy_set_header Host $host;
    }
}

أطلقنا هذا التغيير… ونجح! أصبحت طلبات المنتجات أسرع بكثير، واستطعنا إضافة ميزات جديدة لها بسهولة بدون الخوف من كسر أي شيء في النظام القديم.

الخطوة الرابعة: التكرار حتى الاختناق الكامل

بعد نجاح “خنق” خدمة المنتجات، كررنا العملية. أخذنا الجزء المؤلم التالي، وهو “إدارة الطلبات” (Orders). بنينا خدمة مصغرة جديدة لها، وقمنا بتحديث الواجهة الخانقة لتوجيه طلبات /api/orders إليها. وهكذا دواليك.

مع كل خدمة جديدة نضيفها، كانت قطعة من المونوليث تموت. وبعد حوالي سنة ونصف، وصلنا إلى اللحظة التاريخية: المونوليث القديم لم يعد يستقبل أي طلبات. كان مجرد خادم يعمل في الخلفية بلا أي فائدة. قمنا بإيقافه، وأخذنا “سكرين شوت” للحظة، واحتفلنا وكأننا حررنا أسيراً. لقد تخلصنا من الوحش بنجاح. 🎉

نصائح من مطبخ أبو عمر 👨‍🍳

هذا النمط ليس سهلاً دائماً، وهذه بعض النصائح من تجربتي الشخصية:

  • ابدأ صغيرًا وآمنًا: اختر جزءًا من النظام لا يمثل خطورة كبيرة كبداية. وظائف القراءة (Read-only) هي مرشح مثالي لأول عملية خنق.
  • الرصد والمراقبة هما عيناك: يجب أن يكون لديك نظام مراقبة (Monitoring) ولوحات متابعة (Dashboards) قوية. أنت بحاجة لمعرفة أداء الخدمة الجديدة، وكمية الطلبات التي يتم توجيهها، وأي أخطاء تحدث في الواجهة الخانقة. بدونها، أنت تقود وأنت أعمى.
  • مزامنة البيانات هي التحدي الأكبر: في كثير من الأحيان، ستحتاج الخدمة الجديدة والمونوليث القديم إلى الوصول إلى نفس البيانات أثناء الفترة الانتقالية. هذه أصعب مشكلة. فكر في حلول مثل استخدام (Change Data Capture – CDC)، أو نشر الأحداث (Event Sourcing)، أو حتى وجود طبقة بيانات مشتركة مؤقتًا.
  • اجعل الواجهة الخانقة ذكية: يمكن للـ Façade أن يفعل أكثر من مجرد التوجيه. يمكنك استخدامه لإضافة مصادقة (Authentication)، أو تسجيل (Logging)، أو حتى اختبار A/B بين الخدمة القديمة والجديدة.

الخلاصة: متى تستخدم نمط الخانق؟

نمط التين الخانق ليس حلاً لكل المشاكل، لكنه سلاح فعال بشكل لا يصدق في الحالات الصحيحة.

استخدمه عندما:

  • لديك نظام مونوليثي ضخم وحيوي (mission-critical) لا يمكنك تحمل مخاطرة إيقافه أو إعادة كتابته بالكامل.
  • تريد تحديث تقنياتك بشكل تدريجي وبأقل مخاطرة ممكنة.
  • تريد الانتقال إلى معمارية الخدمات المصغرة (Microservices) بطريقة منظمة.

تجنبه عندما:

  • التطبيق صغير وبسيط ويمكن إعادة كتابته بسهولة.
  • ليس لديك القدرة على التحكم في تدفق الطلبات (لا يمكنك وضع Façade).

في النهاية، لا تخف من الكود القديم. كل “وحش” برمجي له نقطة ضعف. نمط التين الخانق يعلمنا أن الصبر والتخطيط والعمل التدريجي يمكن أن يروض أعظم الوحوش وأكثرها تعقيدًا. فبدلاً من محاربة الوحش وجهًا لوجه، قم ببناء قفص جميل حوله، ثم شاهده وهو يختفي بسلام. 💪

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

أتمتة العمليات

كان مطورنا الجديد ينتظر أياماً: كيف أنقذتنا ‘أتمتة إعداد البيئة’ من جحيم الأسبوع الأول الضائع؟

أتذكر جيداً كيف كان انضمام مطور جديد للفريق يعني بداية أسبوع من المعاناة والإحباط. في هذه المقالة، أسرد لكم قصة حقيقية حول كيف أنقذتنا أتمتة...

15 مايو، 2026 قراءة المزيد
نصائح برمجية

كانت إعادة المحاولة تدمر بياناتنا: كيف أنقذتنا ‘اللامتناهية’ (Idempotency) من جحيم العمليات المكررة؟

في ليلة لم أنم فيها، كانت أنظمتنا المالية تنهار بسبب عمليات دفع متكررة. أشارككم اليوم قصة كيف أنقذنا مفهوم "اللامتناهية" (Idempotency) من كارثة محققة، وكيف...

15 مايو، 2026 قراءة المزيد
​معمارية البرمجيات

كانت خدماتنا تتحدث في نفس الوقت: كيف أنقذتنا ‘المعمارية القائِمَة على الأحداث’ (EDA) من جحيم الاقتران المحكم؟

في ليلة إطلاق عصيبة، كادت خدماتنا المترابطة أن تُغرق المشروع بأكمله. أروي لكم كيف تحولنا من فوضى الاقتران المحكم إلى مرونة المعمارية القائمة على الأحداث...

15 مايو، 2026 قراءة المزيد
ذكاء اصطناعي

كانت نماذجنا تموت بصمت: كيف أنقذتنا ‘مراقبة تعلم الآلة’ (ML Monitoring) من كارثة التنبؤات الفاسدة؟

أشارككم قصة حقيقية من الميدان، حين كادت نماذج الذكاء الاصطناعي التي بنيناها بجهد أن تنهار بصمت. اكتشفوا معنا ما هي "مراقبة تعلم الآلة" (ML Monitoring)،...

15 مايو، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

نقرات المستخدمين كانت تذهب في الفراغ: كيف أنقذتنا ‘التفاعلات الدقيقة’ من جحيم التجربة الصامتة؟

أشارككم قصة حقيقية من قلب معركة تطوير أحد التطبيقات، وكيف أن تفاصيل صغيرة تُدعى "التفاعلات الدقيقة" (Microinteractions) حوّلت تجربة مستخدم صامتة ومحبطة إلى حوار ممتع...

15 مايو، 2026 قراءة المزيد
برمجة وقواعد بيانات

كانت استعلاماتنا تزحف كالسلحفاة: كيف أنقذنا ‘فهرس قاعدة البيانات’ من جحيم البحث الكامل في الجداول (Full Table Scan)؟

أشارككم قصة حقيقية عن يوم كادت فيه استعلاماتنا البطيئة أن تدمر مشروعًا بالكامل، وكيف كان "الفهرس" البسيط في قاعدة البيانات هو طوق النجاة. سنتعلم معًا...

15 مايو، 2026 قراءة المزيد
الشبكات والـ APIs

كانت خوادمنا تستجدي التحديثات: كيف أنقذتنا ‘خطافات الويب’ (Webhooks) من جحيم الاستطلاع المستمر (Polling)؟

بصفتي أبو عمر، أشارككم قصة حقيقية من معاناتنا مع استنزاف الموارد بسبب الاستطلاع المستمر (Polling). سأشرح كيف كانت خطافات الويب (Webhooks) هي طوق النجاة، مع...

15 مايو، 2026 قراءة المزيد
البودكاست