تطبيقنا المونوليث كان وحشاً لا يمكن المساس به: كيف أنقذنا “نمط التين الخانق” من جحيم التحديث المستحيل؟

يا أهلاً وسهلاً فيكم، معكم أخوكم أبو عمر.

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

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

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

ما هو هذا “الوحش” الذي نسميه المونوليث؟

قبل ما نغوص في الحل، خلينا نفهم المشكلة كويس. التطبيق المونوليثي (Monolithic Application) هو تطبيق مبني كوحدة واحدة متكاملة. تخيلوا بناية كاملة عبارة عن كتلة خرسانية واحدة، ما فيها غرف منفصلة. في البداية، هذا الأسلوب بيكون ممتاز: سهل التطوير، سهل الاختبار، وسهل النشر. كل شيء في مكان واحد.

لكن مع مرور الوقت ونمو التطبيق، بتبدأ الكوابيس:

  • الترابط الشديد (Tight Coupling): أي تغيير صغير في جزء ممكن يسبب مشاكل غير متوقعة في جزء آخر تماماً (زي ما صار معنا).
  • صعوبة التطوير: إضافة ميزة جديدة بتصير عملية بطيئة ومعقدة ومحفوفة بالمخاطر.
  • التقنية القديمة: التطبيق كله محبوس في إطار عمل أو لغة برمجة قديمة، وتحديثها يعني إعادة كتابة كل شيء.
  • صعوبة التوسع (Scaling): إذا احتجت تزيد قدرة جزء معين من التطبيق (مثلاً، خدمة البحث)، لازم تنسخ التطبيق كله وتزيد قدرته بالكامل، وهذا هدر كبير للموارد.

بنوصل لمرحلة بنخاف نلمس الكود، وبنصير نردد المقولة الشهيرة: “إذا شغال، لا تلمسه!”. لكن السوق ما برحم، والمنافسين ما بستنوا، والتطوير لازم يستمر.

بصيص الأمل: تعرف على “نمط التين الخانق” (Strangler Fig Pattern)

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

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

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

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

الخطوة الأولى: تحديد “واجهة الخنق” (The Strangler Façade)

أول وأهم خطوة هي بناء “واجهة” أو “بوابة” (Proxy/Gateway) بسيطة جداً. هذه البوابة رح تكون النقطة اللي بتستقبل كل الطلبات من المستخدمين قبل ما توصل للتطبيق. في البداية، كل وظيفة هاي البوابة هي إنها تمرر كل الطلبات زي ما هي للتطبيق القديم (المونوليث).

هذه البوابة هي اللي رح تعطينا القدرة على “توجيه” الطلبات لاحقاً. ممكن تكون عبارة عن Reverse Proxy بسيط باستخدام أدوات مثل Nginx أو HAProxy، أو ممكن تكون تطبيق صغير مبني بـ Node.js أو أي لغة سريعة.

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

كمثال، لو استخدمنا Nginx، الإعدادات الأولية ممكن تكون بسيطة جداً:


# nginx.conf

server {
    listen 80;
    server_name yourapp.com;

    location / {
        # في البداية، كل الطلبات تذهب إلى التطبيق القديم "الختيار"
        proxy_pass http://legacy-monolith-app:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

بهذه الخطوة، صار عنا نقطة تحكم. كل الزوار بدخلوا من باب واحد إحنا حراسه.

الخطوة الثانية: اختيار أول “غصن” للزراعة

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

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

في حالتنا، اخترنا نظام إدارة “ملفات المستخدمين” (User Profiles). كان نظاماً قديماً، وبحاجة ماسة لواجهة جديدة وميزات إضافية.

الخطوة الثالثة: البناء والتوجيه (Build and Redirect)

الآن نقوم ببناء هذا الجزء (ملفات المستخدمين) كتطبيق مصغّر (Microservice) جديد ومستقل، باستخدام أحدث التقنيات اللي بنحبها (مثلاً، Node.js مع قاعدة بيانات MongoDB). هذا التطبيق الجديد له قاعدة بياناته الخاصة ومنطق العمل الخاص به.

بعد ما يصير جاهز، بنرجع لـ “واجهة الخنق” (بوابة Nginx) وبنعدّل الإعدادات. الآن، أي طلب يخص ملفات المستخدمين (مثلاً، أي طلب يبدأ بـ `/api/users/` أو `/profile`) سيتم توجيهه للخدمة الجديدة، بينما باقي الطلبات ستستمر بالذهاب إلى “الختيار”.


# nginx.conf - بعد التحديث

# عنوان الخدمة الجديدة
upstream new_profile_service {
    server new-profile-app:3000;
}

server {
    listen 80;
    server_name yourapp.com;

    # توجيه الطلبات الخاصة بالملفات الشخصية إلى الخدمة الجديدة
    location /api/users/ {
        proxy_pass http://new_profile_service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    location /profile {
        proxy_pass http://new_profile_service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # باقي الطلبات تذهب إلى "الختيار" كالعادة
    location / {
        proxy_pass http://legacy-monolith-app:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

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

الخطوة الرابعة: التعامل مع البيانات (وهنا التحدي الأكبر)

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

  1. قاعدة بيانات مشتركة (مؤقتاً): في البداية، ممكن للخدمة الجديدة أن تقرأ وتكتب في نفس قاعدة بيانات المونوليث القديم. هذا حل سريع لكنه خطير لأنه يحافظ على الترابط. استخدمه بحذر شديد وكمرحلة انتقالية فقط.
  2. مزامنة البيانات (Data Synchronization): ممكن بناء آلية لمزامنة البيانات بين قاعدة بيانات المونوليث القديمة وقاعدة البيانات الجديدة الخاصة بالخدمة الجديدة. يمكن استخدام أدوات مثل Debezium (لـ Change Data Capture) أو أنظمة الرسائل (Message Queues) مثل RabbitMQ أو Kafka. عندما يتم تحديث بيانات المستخدم في النظام القديم، يتم إرسال “حدث” (Event) للخدمة الجديدة لتحديث بياناتها، والعكس صحيح.
  3. طبقة واجهة برمجة التطبيقات (API Layer): إذا كانت الخدمة الجديدة تحتاج بيانات لا تملكها (مثلاً، تحتاج قائمة طلبات المستخدم، وهي ما زالت في المونوليث)، يمكنها أن تستدعي API في المونوليث للحصول على هذه البيانات.

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

الخطوة الخامسة: التكرار حتى “الاختناق” الكامل

الآن، ما عليك إلا تكرار العملية:

  1. اختر الجزء التالي من المونوليث (مثلاً، نظام الفواتير).
  2. ابنه كخدمة مصغّرة جديدة.
  3. حدّث بوابة التوجيه (Nginx) لتوجيه الطلبات الخاصة بالفواتير للخدمة الجديدة.
  4. عالج تحديات البيانات.
  5. أطلق الخدمة الجديدة.

مع كل تكرار، المونوليث القديم “الختيار” يصغر ويضعف، وتقل مسؤولياته. والنظام الجديد ينمو ويكبر مثل شجرة التين القوية. وفي يوم من الأيام، ستجد أن المونوليث لم يعد يفعل أي شيء مهم. كل وظائفه تم نقلها. في تلك اللحظة السعيدة، يمكنك إيقافه وحذفه إلى الأبد. торжество!

الخلاصة: من وحش كاسر إلى حديقة خدمات يانعة 🌳

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

أهم الدروس اللي تعلمناها:

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

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

بالتوفيق يا جماعة الخير!

أبو عمر

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

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

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

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

آخر المدونات

نصائح برمجية

بياناتي كانت تتغير من حيث لا أدري: كيف أنقذتني ‘اللامتغيرية’ (Immutability) من جحيم الآثار الجانبية الخفية؟

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

8 أبريل، 2026 قراءة المزيد
خوارزميات

البحث في قوائمي المرتبة كان يزحف: كيف أنقذني ‘البحث الثنائي’ من جحيم البطء الخطي؟

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

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

ميزانيتنا كانت تحترق: كيف أنقذتنا ‘نماذج الإحالة’ (Attribution Models) من جحيم تخمين القنوات الرابحة؟

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

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

من فوضى المكونات إلى نظام التصميم المتكامل: قصتنا لإنقاذ واجهات المستخدم من جحيم التضارب

أشارككم تجربتي كـ "أبو عمر" في الانتقال من واجهات فوضوية ومكررة إلى بيئة عمل منظمة بفضل "نظام التصميم". سنغوص في رحلتنا لبناء هذا النظام من...

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

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

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

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