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

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

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

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

لماذا كانت “القلعة” المونوليثية كابوسًا؟

قبل ما أكمل القصة، خلوني أوضح للي مش ملم بالموضوع شو يعني “مونوليث” (Monolith). باختصار شديد، هو تطبيق كل مكوناته ملمومة في “طنجرة” واحدة. قاعدة بيانات واحدة، كود واحد، عملية نشر (Deployment) واحدة. كل إشي مع بعضه البعض.

في البداية، هذا الأسلوب رائع وسريع. لكن مع نمو التطبيق، بدأت الكوابيس تظهر:

  • التلاصق الشديد (Tight Coupling): كانت المكونات متشابكة مثل أسلاك سماعات قديمة في الجيبة. تغيير في وحدة تسجيل المستخدمين قد يؤثر بشكل غير متوقع على وحدة إدارة المخزون.
  • التقيّد بتقنية واحدة (Technology Lock-in): “القلعة” كانت مبنية بتقنية معينة (خلينا نقول نسخة قديمة من Java). كنت أحلم بإضافة جزء يستخدم الذكاء الاصطناعي بلغة Python، لكن هذا كان مستحيلًا. التطبيق كله لازم يكون بنفس التقنية.
  • صعوبة التوسع (Scalability Issues): لو صار ضغط على جزء واحد فقط من التطبيق (مثلاً، صفحة المنتجات)، كنت مضطرًا أعمل نسخة كاملة من التطبيق الضخم كله عشان أتحمل الضغط، وهذا مكلف جدًا وغير فعال.
  • بطء النشر والتحديث (Slow Deployment): أي تعديل، مهما كان بسيطًا، كان يتطلب اختبار التطبيق بأكمله وإعادة نشره بالكامل. عملية كانت تأخذ ساعات طويلة ومحفوفة بالمخاطر.

فكرة “الانفجار العظيم” ولماذا هي وصفة للكارثة

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

لكن من خبرتي، هذا الطريق هو وصفة شبه مؤكدة للكارثة. لماذا؟

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

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

شجرة التين الخانقة (Strangler Fig Pattern): طوق النجاة الذي لم أتوقعه

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

في عالم البرمجيات، الفكرة مماثلة تمامًا. بدلًا من هدم “القلعة” المونوليثية دفعة واحدة، سنبني خدمات جديدة (Microservices) حولها، ونحوّل المستخدمين إليها تدريجيًا، حتى “نخنق” النظام القديم بالكامل ويصبح بلا فائدة، فنقوم بإزالته بأمان.

كيف “خنقنا” المونوليث خطوة بخطوة؟ (الدليل العملي)

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

المرحلة الأولى: بناء الواجهة الأمامية (The Façade)

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

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

استخدمنا NGINX لهذه المهمة. إعداداته الأولية كانت تبدو كالتالي:


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

    location / {
        # في البداية، كل الطلبات تذهب إلى المونوليث
        proxy_pass http://monolith_server_address;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

المرحلة الثانية: تحديد أول ضحية واستخلاصها

الآن جاء وقت اختيار أول جزء من “القلعة” لنستبدله. كيف تختار؟

  • ابدأ بجزء ليس حيويًا جدًا (Low Risk) لكنه مستخدم بكثرة.
  • اختر وحدة يتم طلب تعديلات عليها باستمرار (Frequently Changing).
  • يفضل أن تكون وحدة ذات حدود واضحة (Clear Boundaries).

في حالتنا، كانت وحدة “ملفات المستخدمين الشخصية” (User Profiles) هي المرشح المثالي. قمنا ببناء خدمة مصغرة (Microservice) جديدة تمامًا باستخدام Node.js، مع قاعدة بيانات خاصة بها، تقوم فقط بإدارة ملفات المستخدمين.

المرحلة الثالثة: التحويل التدريجي (The Switch)

بعد أن أصبحت خدمة “ملفات المستخدمين” جاهزة، عدنا إلى الحارس (NGINX) وأعطيناه تعليمات جديدة. قلنا له: “اسمع، أي طلب يبدأ بـ /api/users، لا ترسله إلى القلعة القديمة، بل أرسله إلى الخدمة الجديدة”.

أصبح ملف الإعدادات كالتالي:


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

    # توجيه الطلبات الخاصة بالمستخدمين للخدمة المصغرة الجديدة
    location /api/users/ {
        proxy_pass http://user_profile_microservice_address;
        proxy_set_header Host $host;
        # ...
    }

    # باقي الطلبات لا تزال تذهب إلى المونوليث
    location / {
        proxy_pass http://monolith_server_address;
        proxy_set_header Host $host;
        # ...
    }
}

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

المرحلة الرابعة: كرّر العملية حتى النهاية

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

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

تحديات واجهتني ونصائح من “كيس” الخبرة

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

  • مزامنة البيانات (Data Synchronization): هذا أكبر تحدٍ. كيف تتواصل الخدمة الجديدة مع قاعدة بيانات المونوليث القديمة؟ في البداية، قد تضطر للسماح للخدمة الجديدة بالقراءة من قاعدة البيانات القديمة (تجنب الكتابة عليها قدر الإمكان!). الحل الأفضل على المدى الطويل هو استخدام أنظمة الـ Event Sourcing مثل Apache Kafka. عندما يحدث تغيير في مكان، يتم إرسال “حدث” (Event) لكل الأنظمة الأخرى لتحديث نفسها.
  • إدارة المعاملات الموزعة (Distributed Transactions): ماذا لو كانت عملية ما (مثل إنشاء طلب شراء) تتطلب تحديثًا في المونوليث وخدمة مصغرة في نفس الوقت؟ هذا موضوع معقد، ويتطلب البحث في أنماط متقدمة مثل نمط “Saga Pattern”.
  • لا تلمس قلب المونوليث: قاوم إغراء “إصلاح” أو “تعديل” الكود القديم. هدفك هو استبداله، وليس تحسينه. اتركه يموت بسلام.
  • المراقبة ثم المراقبة (Monitoring): استثمر في أدوات مراقبة (Monitoring) وتسجيل (Logging) قوية. أنت الآن تدير نظامًا موزعًا، وتحتاج أن تعرف بالضبط أين تحدث المشاكل عند حدوثها.

خلاصة الحكاية: من قلعة سجينة إلى مدينة حرة 🏙️

في النهاية، تحول تطبيقنا من “قلعة” واحدة، قديمة، ومغلقة، إلى “مدينة” حديثة مكونة من عدة مبانٍ (خدمات) مستقلة، كل مبنى له تصميمه الخاص وتقنيته الخاصة، ويتواصل مع الآخرين عبر شوارع وطرق واضحة (APIs).

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

إذا كنت عالقًا مع مونوليث قديم وتشعر بالإحباط، تذكر قصة “القلعة”. ما في إشي مستحيل، بس بدها شوية تخطيط وصبر… ويا دار ما دخلك شر.

أتمنى لكم التوفيق في مشاريعكم. ودُمتم بخير.

أبو عمر

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

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

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

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

آخر المدونات

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

عمليات النشر كانت كابوساً: كيف أنقذتني ‘خطوط أنابيب CI/CD’ من جحيم أعطال ما بعد الإطلاق؟

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

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

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

هل شعرت يومًا أن الكود الذي تكتبه يقوم بنفس الحسابات مرارًا وتكرارًا؟ في هذه المقالة، أشارككم قصة شخصية حول كيف غيّرت 'البرمجة الديناميكية' طريقة تفكيري...

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

ميزانيتي الإعلانية كانت بئراً بلا قرار: كيف أنقذني ‘تتبع التحويلات’ من جحيم الإنفاق الأعمى؟

أشارككم قصتي مع إهدار المال على الإعلانات وكيف تحولت من الإنفاق الأعمى إلى استثمار ذكي بفضل "تتبع التحويلات". اكتشفوا معي كيف يمكن لهذه الأداة البسيطة...

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

مكوناتي كانت فوضى: كيف أنقذني نظام التصميم (Design System) من جحيم التناقض البصري؟

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

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

واجهاتي البرمجية كانت إما بخيلة أو مسرفة: كيف أنقذتني GraphQL من جحيم الـ Over-fetching والـ Under-fetching؟

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

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

كنت سجينًا لدى مزود سحابي واحد: كيف حررتني استراتيجية ‘السحابة المتعددة’ (Multi-Cloud) من جحيم الاعتمادية المطلقة؟

أشارككم قصتي مع "الاعتمادية المطلقة" على مزود سحابي واحد، وكيف كانت استراتيجية السحابة المتعددة (Multi-Cloud) طوق النجاة الذي حررني. هذه المقالة دليل عملي للمطورين والشركات...

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