تحديث النظام القديم كان كابوساً: كيف ‘خنقت’ المونوليث تدريجياً بنمط Strangler Fig دون توقف الخدمة

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

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

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

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

ما هو “المونوليث” (Monolith) ولماذا يصبح كابوساً؟

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

هذا هو المونوليث تماماً. كل شيء – واجهة المستخدم، منطق العمل (Business Logic)، الوصول للبيانات – مكدس في قاعدة كود واحدة ضخمة. في البداية، يكون هذا النهج سريعاً وسهلاً، ولكن مع مرور الوقت ونمو النظام، تبدأ الكوابيس:

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

“إعادة كتابة النظام بالكامل من الصفر هي فكرة مغرية، لكنها في معظم الأحيان فخ خطير يؤدي إلى تأخيرات هائلة ومخاطر لا حصر لها.”

الحل السحري المستوحى من الطبيعة: نمط شجرة التين الخانقة (Strangler Fig Pattern)

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

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

كيف يعمل النمط على أرض الواقع؟ المراحل الثلاث

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

  1. التحويل (Transform): نبدأ بتحديد جزء صغير أو وحدة وظيفية في النظام القديم نريد استبدالها. لنقل مثلاً نظام إدارة ملفات المستخدمين. نقوم ببناء هذه الوحدة كخدمة جديدة ومستقلة (Microservice) باستخدام أحدث التقنيات التي نفضلها.
  2. التعايش (Coexist): هذه هي المرحلة الأهم. نضع “واجهة” أو “بوابة” (تُعرف بـ Strangler Façade أو Reverse Proxy) أمام النظام بأكمله. هذه البوابة تستقبل كل طلبات المستخدمين، وتقوم بتوجيهها بذكاء: الطلبات المتعلقة بالوظيفة الجديدة (ملفات المستخدمين) تذهب إلى الخدمة الجديدة، بينما كل الطلبات الأخرى تذهب إلى النظام المونوليثي القديم كالمعتاد. في هذه المرحلة، يتعايش النظامان معاً بسلام.
  3. الخنق (Strangle): نكرر العملية. نختار جزءاً آخر من النظام القديم، نبنيه كخدمة جديدة، ونحدّث قواعد التوجيه في البوابة لتحويل المزيد من الطلبات إلى النظام الجديد. مع مرور الوقت، يتم “خنق” النظام القديم تدريجياً، حيث تنتقل مسؤولياته واحدة تلو الأخرى إلى الخدمات الجديدة، حتى يأتي اليوم الذي لا تصله فيه أي طلبات على الإطلاق. عندها، يمكننا إيقافه وحذفه والاحتفال! 🎉

مثال عملي: خنق نظام إدارة المستخدمين

دعونا نأخذ مثالاً عملياً لتوضيح الفكرة. لدينا نظام مونوليثي قديم لإدارة متجر إلكتروني، ونريد تحديث جزء المصادقة (Authentication) وتسجيل الدخول.

الخطوة الأولى: بناء خدمة المصادقة الجديدة

سنقوم ببناء خدمة مصغرة (Microservice) جديدة باستخدام تقنية حديثة مثل Node.js و Express.js. هذه الخدمة ستكون مسؤولة فقط عن تسجيل المستخدمين الجدد وتسجيل دخولهم وإصدار توكن (JWT Token) لهم.


// new-auth-service/index.js
const express = require('express');
const app = express();
app.use(express.json());

// نقطة نهاية جديدة لتسجيل الدخول
app.post('/api/v2/auth/login', (req, res) => {
    const { email, password } = req.body;
    // ... منطق التحقق من المستخدم في قاعدة البيانات الجديدة
    // ... إذا كان المستخدم صحيحاً، نصدر له توكن JWT
    const token = 'new_jwt_token_here';
    res.json({ message: 'Login successful from new service!', token });
});

app.listen(3000, () => {
    console.log('New Auth Service running on port 3000');
});

الخطوة الثانية: وضع الواجهة الأمامية (The Façade)

الآن، سنستخدم بروكسي عكسي (Reverse Proxy) مثل Nginx ليكون البوابة الرئيسية. سيقوم Nginx بتوجيه الطلبات بناءً على المسار (URL Path).

هذا مثال على ملف الإعدادات الخاص بـ Nginx:


# nginx.conf
server {
    listen 80;
    server_name my-legacy-app.com;

    # أي طلب يبدأ بـ /api/v2/auth/ وجهه إلى خدمة المصادقة الجديدة
    location /api/v2/auth/ {
        proxy_pass http://new-auth-service:3000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # أي طلب آخر، وجهه إلى النظام المونوليثي القديم
    location / {
        proxy_pass http://old-monolith-app:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

بهذه البساطة! الآن، عندما يرسل المستخدم طلباً إلى my-legacy-app.com/api/v2/auth/login، سيقوم Nginx بتوجيهه إلى خدمتنا الجديدة. أما إذا طلب صفحة المنتجات my-legacy-app.com/products، فسيتم توجيهه إلى النظام القديم. المستخدم لن يشعر بأي فرق، والخدمة لم تتوقف للحظة.

الخطوة الثالثة: التوسع والاحتفال

بعد نجاح تحديث نظام المصادقة، ننتقل إلى الجزء التالي، مثلاً “كتالوج المنتجات”. نبني خدمة جديدة للمنتجات، ونضيف قاعدة توجيه جديدة في Nginx:


location /api/v2/products/ {
    proxy_pass http://new-products-service:3001/;
    # ...
}

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

نصائح من قلب الميدان (من خبرة أبو عمر)

هذه العملية ليست سهلة دائماً، وهناك تحديات ستواجهها. بناءً على تجربتي، إليك بعض النصائح العملية:

  • ابدأ صغيراً وبشكل استراتيجي: لا تحاول استبدال جزء معقد وحيوي في البداية. اختر شيئاً بسيطاً ومنخفض المخاطر، ويفضل أن يكون للقراءة فقط (Read-only)، مثل عرض صفحة “عن الشركة”. هذا سيعطيك ثقة في العملية والأدوات.
  • قاعدة البيانات هي التحدي الأكبر: كيف تتعامل مع البيانات المشتركة بين النظامين؟ هذا هو أصعب جزء. هناك عدة استراتيجيات، مثل:
    • قاعدة بيانات مشتركة مؤقتاً: يمكن للنظامين القراءة والكتابة من نفس قاعدة البيانات القديمة في البداية. هذا ليس مثالياً لكنه حل عملي للانطلاق.
    • مزامنة البيانات: بناء آليات لمزامنة البيانات بين قاعدة البيانات القديمة والجديدة.
    • استخدام نمط Event Sourcing: حيث يقوم النظام القديم بإصدار “أحداث” (Events) عند كل تغيير في البيانات، وتقوم الخدمات الجديدة بالاستماع لهذه الأحداث وتحديث قواعد بياناتها الخاصة.
  • المراقبة والتوثيق هما مفتاح النجاة: يجب أن تكون لديك أنظمة مراقبة (Monitoring) وتسجيل (Logging) قوية جداً. عندما يحدث خطأ، ستحتاج إلى معرفة ما إذا كان مصدره الخدمة الجديدة أم المونوليث القديم. أدوات مثل Prometheus و Grafana و Jaeger لا غنى عنها.
  • لا تستعجل في “قتل” النظام القديم: كما يقول المثل عندنا “قيس مية مرة وقص مرة واحدة”. تأكد تماماً أن لا يوجد أي طلبات تصل إلى الجزء الذي استبدلته في النظام القديم قبل حذفه. استخدم سجلات الوصول (Access Logs) والقياسات للتأكد من ذلك.

الخلاصة: رحلة تحول وليست سباق سرعة

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

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

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

أبو عمر

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

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

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

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

آخر المدونات

التوظيف وبناء الهوية التقنية

سيرتي الذاتية عبرت فلتر الـ ATS لكنها فشلت أمام المدير التقني: كيف أعدت بناءها لتتحدث لغة المهندسين؟

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

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

خدمة واحدة فاشلة كادت أن تسقط النظام بأكمله: كيف أنقذني نمط ‘قاطع الدائرة’ (Circuit Breaker) من كارثة متتالية؟

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

27 فبراير، 2026 قراءة المزيد
اختبارات الاداء والجودة

لقد ‘هاجمت’ تطبيقي بنفسي عمداً: كيف كشفت لي ‘هندسة الفوضى’ نقاط الضعف التي لم تظهرها الاختبارات التقليدية

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

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

عاصفة من الطلبات كادت أن تغرق تطبيقي: كيف أنقذتني طوابير الرسائل (Message Queues) من كارثة الجمعة السوداء؟

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

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