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

يا جماعة الخير، السلام عليكم.

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

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

في ليلة من هالليالي، وأنا ببحث بيأس عن أي حل، قرأت مقالة عن نمط معماري غريب اسمه “نمط الخانق” أو “Strangler Fig Pattern”. الاسم لحاله لفت انتباهي. قرأت عنه أكتر وأكتر، وشوي شوي، بدأت لمبة تضوي براسي. هل ممكن يكون هاد هو طوق النجاة اللي بنستناه؟ هل ممكن نتحايل على “الصخرة” ونبني حواليها نظام جديد يخنقها شوي شوي لحد ما تختفي؟ كانت فكرة مجنونة، لكنها كانت الأمل الوحيد. ومن هنا، بدأت رحلتنا اللي راح أحكيلكم تفاصيلها اليوم.

ما هو “نمط الخانق” (Strangler Fig Pattern)؟ وليش سمّوه هيك؟

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

في عالم البرمجيات، الفكرة نفسها تماماً. بدل ما ندخل في مشروع إعادة كتابة كامل (Big Bang Rewrite) اللي غالباً بيفشل وبكلف الملايين، بنتبع استراتيجية أذكى وأكثر أماناً:

  1. بنبني “واجهة” جديدة (Facade) بتكون هي نقطة الدخول لكل المستخدمين.
  2. هاي الواجهة بالبداية ما بتعمل إشي غير إنها تحوّل كل الطلبات للنظام القديم (المونوليث).
  3. بعدين، بنبدأ نختار جزء صغير من النظام القديم (مثلاً، صفحة ملف المستخدم) وبنبنيها من الصفر كتطبيق جديد ومستقل (خدمة مصغرة أو Microservice).
  4. بنعَدّل الواجهة عشان أي طلب رايح لملف المستخدم، يروح للخدمة الجديدة بدل النظام القديم.
  5. بنكرر هاي العملية مرة بعد مرة، “نخنق” جزء جديد من النظام القديم ونستبدله بخدمة جديدة، لحد ما نلاقي حالنا بعد فترة إنه النظام القديم بطل إله أي وظيفة، وبنقدر نطفيه ونحذفه بكل أمان.

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

الوحش الذي واجهناه: تشريح “الصخرة”

عشان تفهموا حجم التحدي، لازم أوصفلكم نظام “الصخرة” اللي كنا نتعامل معه:

  • مونوليث ضخم (Giant Monolith): تطبيق واحد كبير مكتوب بلغة برمجة قديمة، وكل إشي فيه بنفس قاعدة الكود. الواجهة الأمامية، منطق العمل (Business Logic)، التعامل مع قاعدة البيانات… كله كتلة وحدة.
  • كود متزاوج بشدة (Tightly Coupled): تغيير متغير في وحدة تسجيل الدخول ممكن يكسر نظام التقارير. ما كان في أي حدود واضحة بين المكونات.
  • قاعدة بيانات مركزية فوضوية: جدول واحد ممكن يكون فيه 200 عامود، وبيتم استخدامه من 50 مكان مختلف لأغراض مختلفة تماماً. كابوس!
  • نشر كارثي (Deployment Hell): عشان ننشر أي تحديث، حتى لو كان سطر واحد، كنا نحتاج نوقف النظام كله لساعات، ونعمل “build” لكل المشروع، ونقعد ندعي إنه ما في إشي ينضرب.

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

خطة المعركة: كيف طبقنا نمط الخانق خطوة بخطوة؟

بعد ما اقتنع الفريق بالإمكانية، وضعنا خطة عمل واضحة ومقسمة لمراحل. ما استعجلنا، ومشينا “شوي شوي” عشان نضمن النجاح.

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

أول وأهم خطوة هي بناء الجدار الأمامي اللي راح يستقبل كل الطلبات. هذا الجدار هو اللي بيقرر: هل الطلب هذا أوديه للنظام الجديد ولا أخليه يكمل طريقه للنظام القديم؟

استخدمنا لهذا الغرض ما يسمى بالـ Reverse Proxy. في حالتنا، كان NGINX هو بطل المرحلة. الفكرة بسيطة جداً، كل الترافيك اللي جاي على app.mycompany.com بيوصل أولاً للـ NGINX.

نصيحة من أبو عمر: لا تعقد الأمور هنا. ابدأ بأبسط Reverse Proxy ممكن. ممكن يكون NGINX, Traefik, YARP إذا كنت من جماعة .NET, أو حتى قطعة Middleware بسيطة في تطبيق Node.js. المهم تبدأ.

مثال بسيط جداً على إعدادات NGINX ممكن تكون كالتالي:


# /etc/nginx/conf.d/strangler.conf

# الخادم القديم (المونوليث)
upstream legacy_app {
    server legacy-app-server:8080;
}

# الخادم الجديد (اللي فيه الخدمات المصغرة)
upstream new_microservices {
    server new-app-server:3000;
}

server {
    listen 80;
    server_name app.mycompany.com;

    location / {
        # بالبداية، كل إشي بيروح للقديم
        proxy_pass http://legacy_app;
        proxy_set_header Host $host;
        # ... باقي إعدادات البروكسي
    }
}

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

الخطوة الثانية: اختيار أول ضحية (أول خدمة مصغرة)

هون بيجي القرار المهم: من وين نبدأ؟ القاعدة الذهبية هي: ابدأ بجزء صغير، قليل المخاطر، لكنه يعطي قيمة واضحة.

في حالتنا، اخترنا “وحدة الإشعارات” (Notifications). كانت وحدة شبه معزولة، مسؤولة عن إرسال الإيميلات والـ Push Notifications للمستخدمين. كانت مكتوبة بطريقة سيئة وبتسبب مشاكل كثيرة.

قمنا ببناء خدمة مصغرة جديدة باستخدام Node.js و RabbitMQ. كانت خدمة بسيطة، نظيفة، ومستقلة تماماً. بعد ما اختبرناها بشكل كامل، جاء وقت التفعيل.

رجعنا لملف إعدادات NGINX وعدّلناه:


# ... نفس الإعدادات السابقة

server {
    listen 80;
    server_name app.mycompany.com;

    # أي طلب يبدأ بـ /api/notifications يروح للخدمة الجديدة
    location /api/notifications/ {
        proxy_pass http://new_microservices;
        proxy_set_header Host $host;
        # ... 
    }

    # باقي الطلبات تروح للنظام القديم
    location / {
        proxy_pass http://legacy_app;
        proxy_set_header Host $host;
        # ...
    }
}

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

الخطوة الثالثة: التعامل مع البيانات (الجزء الأصعب)

هاي هي العقبة الكبيرة في أي عملية ترحيل. كيف الخدمة الجديدة راح تقرأ وتكتب بيانات وهي موجودة في قاعدة بيانات النظام القديم؟

هناك عدة استراتيجيات، وما في حل واحد سحري. إحنا استخدمنا مزيج منها حسب الحاجة:

  1. واجهة برمجة تطبيقات فوق النظام القديم (API Layer on Legacy): في البداية، كانت خدمتنا الجديدة (خدمة الإشعارات) تحتاج معلومات عن المستخدمين. بدل ما نوصلها مباشرة بقاعدة البيانات القديمة الفوضوية، بنينا API بسيط جداً فوق النظام القديم مهمته فقط يرجع بيانات المستخدمين. الخدمة الجديدة كانت تنادي هذا الـ API. هذا بيخلق طبقة عزل وبيمنع الفوضى من الانتشار.
  2. مزامنة البيانات عبر الأحداث (Data Sync via Events): لما انتقلنا لأجزاء أكثر تعقيداً مثل “الطلبات” (Orders)، اتبعنا نهجاً مختلفاً. كل ما كان النظام القديم ينشئ طلب جديد في قاعدة بياناته، كان يطلق “حدث” (Event) على Message Queue (استخدمنا RabbitMQ). كان في خدمة صغيرة مهمتها تسمع هاي الأحداث وتكتب البيانات بشكل نظيف في قاعدة البيانات الجديدة الخاصة بخدمة الطلبات الجديدة. هذا النهج يضمن أن الأنظمة منفصلة ولكن بياناتها متزامنة.
  3. قاعدة البيانات المشتركة (Shared DB): هذا الخيار حاولنا نتجنبه قدر الإمكان، لأنه بيخلق “تزاوج” من نوع آخر. لكن في مرحلة انتقالية قصيرة جداً، اضطرينا نسمح لخدمة جديدة بالقراءة من جدول معين في قاعدة البيانات القديمة. بنصح بشدة إنك تعتبر هذا الحل هو الملاذ الأخير والمؤقت فقط. زي اللي بيبني بيتين على أساس واحد قديم… خطير!

الخطوة الرابعة: كرر، توسّع، واخنق!

بعد نجاح أول خدمة، صارت العملية روتينية. كنا في كل ربع سنة نختار “ضحية” جديدة من النظام القديم:

  • ملفات المستخدمين (User Profiles)
  • سلة المشتريات (Shopping Cart)
  • واجهة البحث (Search API)
  • نظام الفواتير (Invoicing)

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

بعد حوالي سنتين من العمل المتقطع والمستمر، وصلنا للحظة التاريخية. آخر وظيفة في النظام القديم تم نقلها. “الصخرة” صار مجرد هيكل فارغ ما بيعمل أي شيء. في ذلك اليوم، اجتمع الفريق كله، وبكبسة زر، أوقفنا سيرفرات النظام القديم للأبد. كانت لحظة احتفالية لن أنساها ما حييت.

ليش نمط الخانق عبقري؟ (الفوائد اللي لمسناها)

  • تقليل المخاطر: ما قامرنا بمستقبل الشركة في مشروع إعادة كتابة ضخم. التغييرات كانت تدريجية وآمنة.
  • قيمة أسرع للسوق: بدل ما ننتظر سنتين لنطلع بنظام جديد، كنا بنطلع ميزات وتحسينات جديدة كل بضعة أشهر.
  • تحديث تدريجي للتقنيات: قدرنا نستخدم Go و Python و قواعد بيانات حديثة في الخدمات الجديدة، بينما بقي النظام القديم يعمل بتقنيته البالية.
  • تحسين معنويات الفريق: هاي نقطة جوهرية. المبرمجين انتقلوا من حالة الإحباط واليأس من التعامل مع كود قديم، إلى حالة من الحماس والإبداع في بناء خدمات جديدة ونظيفة.

الخلاصة: نصيحة من أخوكم أبو عمر

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

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

نصيحتي الأخيرة لك: ابدأ صغيراً، فكر كبيراً، وتحرك بثقة. وكل تحديث ناجح، اعتبره نصراً صغيراً في معركتك ضد التعقيد. بالتوفيق يا جماعة! 💪

أبو عمر

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

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

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

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

آخر المدونات

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

دليل المبرمج لأتمتة النشر: كيف قضت بايبلاينات CI/CD على كوابيس منتصف الليل؟

من ليالي النشر اليدوي المليئة بالتوتر والأخطاء الكارثية، إلى عالم الأتمتة والنوم الهانئ. أشارككم تجربتي الشخصية وكيف غيرت بايبلاينات CI/CD طريقة عملي للأبد، مع دليل...

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

شفرتي كانت مليئة بالأرقام الغامضة: كيف أنقذني مبدأ ‘لا للأرقام السحرية’ من كابوس برمجي؟

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

28 مارس، 2026 قراءة المزيد
تسويق رقمي

ميزانيتي الإعلانية كانت ثقباً أسود: كيف أنقذني نموذج الإحالة متعدد اللمسات من إهدار المال؟

هل تشعر أن ميزانيتك الإعلانية تتبخر دون عائد واضح؟ اكتشف كيف ساعدني نموذج الإحالة متعدد اللمسات (Multi-Touch Attribution) في تحديد القنوات التسويقية الفعالة حقاً وإيقاف...

27 مارس، 2026 قراءة المزيد
الحوسبة السحابية

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

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

27 مارس، 2026 قراءة المزيد
التوظيف وبناء الهوية التقنية

كنت مجرد مستهلك للكود: كيف حوّلتني ‘المساهمة في المصادر المفتوحة’ إلى مطور مطلوب؟

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

27 مارس، 2026 قراءة المزيد
التوسع والأداء العالي والأحمال

خادمي الوحيد كان على وشك الانهيار: كيف أنقذني ‘موازن الأحمال’ (Load Balancer) من التوقف التام؟

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

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