تحديث النظام القديم كان كابوساً: كيف أنقذني نمط ‘التين الخانق’ (Strangler Fig) من إعادة كتابة كل شيء من الصفر؟

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

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

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

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

شو القصة؟ ليش إعادة الكتابة من الصفر فكرة سيئة جداً؟

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

  • مخاطرة عالية جداً: أنت تراهن بكل شيء على مشروع واحد ضخم. أي خطأ في التقدير أو التنفيذ قد يؤدي إلى فشل المشروع بالكامل، وضياع ملايين الدولارات وسنوات من العمل.
  • الوقت الطويل للقيمة (Time to Value): لن يرى المستخدمون أو الشركة أي فائدة من النظام الجديد إلا بعد اكتماله بنسبة 100%، وهذا قد يستغرق سنوات. خلال هذه الفترة، يكون منافسوك قد أطلقوا ميزات جديدة وتطوروا.
  • تجميد النظام القديم: أثناء عملك على النظام الجديد، هل ستتوقف عن إضافة أي ميزات أو إصلاحات للنظام القديم؟ هذا شبه مستحيل. ستجد نفسك تدير مشروعين في نفس الوقت، مما يزيد من التعقيد والتكلفة.
  • فقدان المعرفة الكامنة: الأنظمة القديمة، رغم فوضويتها، تحتوي على سنوات من منطق العمل (Business Logic) الخفي وحالات خاصة (Edge Cases) لم يتم توثيقها أبداً. إعادة كتابتها من الصفر تعني أنك ستواجه كل تلك المشاكل من جديد.
  • تأثيره على معنويات الفريق: المشاريع الطويلة التي لا نهاية واضحة لها محبطة جداً للمطورين. يبدأ الحماس عالياً ثم يتلاشى مع مرور الوقت وظهور المشاكل.

وهنا يأتي المنقذ: نمط التين الخانق (Strangler Fig Pattern)

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

ما هو نمط التين الخانق برمجياً؟

ببساطة، هو استراتيجية لتحديث الأنظمة القديمة (Legacy Systems) بشكل تدريجي. بدلاً من استبدال النظام بأكمله دفعة واحدة، تقوم بإنشاء “واجهة” (Façade) أمام النظام القديم، ثم تبدأ تدريجياً ببناء خدمات جديدة (Microservices مثلاً) لتحل محل أجزاء من النظام القديم. يتم توجيه الطلبات (Requests) عبر هذه الواجهة، التي تقرر إما إرسال الطلب إلى النظام القديم أو إلى الخدمة الجديدة.

كيف يعمل على أرض الواقع؟ (الخطوات العملية)

دعنا نفصل العملية إلى خطوات عملية وواضحة يمكنك اتباعها:

  1. تحديد وتغليف (Identify & Wrap): أول خطوة هي تحديد جزء معين من النظام تريد تحديثه. ليكن مثلاً نظام إدارة المستخدمين أو نظام الطلبات. بعد ذلك، تضع “واجهة خانقة” (Strangler Façade) أمام النظام بأكمله. هذه الواجهة هي مجرد بروكسي (Proxy) بسيط يمرر كل الطلبات كما هي إلى النظام القديم في البداية.
  2. بناء الخدمة الجديدة (Build): الآن، ابدأ ببناء الخدمة الجديدة التي ستحل محل الجزء الذي حددته. ابنها باستخدام أحدث التقنيات، بأفضل الممارسات، واجعلها مستقلة تماماً.
  3. التحويل التدريجي (Divert/Redirect): هذه هي الخطوة السحرية. تبدأ بتعديل منطق الواجهة الخانقة. بدلاً من تمرير كل الطلبات إلى النظام القديم، تبدأ بتحويل الطلبات المتعلقة بالجزء الجديد إلى خدمتك الجديدة. يمكنك أن تبدأ بنسبة صغيرة من المستخدمين (مثلاً 1% فقط)، أو المستخدمين الداخليين، أو بناءً على “feature flag”.
  4. المراقبة والتحقق (Monitor & Verify): راقب أداء الخدمة الجديدة عن كثب. هل تعمل كما هو متوقع؟ هل هناك أخطاء؟ هل البيانات متزامنة؟ هذه المرحلة حاسمة لضمان انتقال سلس.
  5. الخنق (Strangle): عندما تتأكد من أن الخدمة الجديدة تعمل بشكل مثالي، تبدأ بزيادة نسبة التحويل تدريجياً. من 1% إلى 10%، ثم 50%، حتى تصل إلى 100%. في هذه المرحلة، كل الطلبات المتعلقة بهذا الجزء تذهب إلى النظام الجديد، والنظام القديم لم يعد يستقبلها.
  6. التخلص من القديم (Decommission): بعد أن تم “خنق” الجزء القديم بالكامل، يمكنك الآن وبكل أمان حذفه من الكود القديم. يا له من شعور رائع! كرر هذه العملية مع جزء آخر من النظام، وهكذا دواليك.

مع مرور الوقت، ستجد أن نظامك الجديد ينمو ويكبر، بينما النظام القديم “يموت” ويختفي تدريجياً، كل ذلك بدون توقف الخدمة وبأقل قدر من المخاطر.

مثال عملي: خنق وحدة “الطلبات” في نظامنا القديم

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

المرحلة الأولى: الواجهة الخانقة (Strangler Façade)

استخدمنا Nginx كـ Reverse Proxy. كان الإعداد الأولي بسيطاً جداً، مجرد تمرير كل شيء للنظام القديم.


# nginx.conf

# النظام القديم يعمل على هذا العنوان
upstream legacy_system {
    server legacy.myapp.local:8080;
}

# الخدمة الجديدة (فارغة الآن)
upstream new_orders_service {
    server new-orders.myapp.local:3000;
}

server {
    listen 80;

    location /api/ {
        # في البداية، كل شيء يذهب للنظام القديم
        proxy_pass http://legacy_system;
        proxy_set_header Host $host;
    }
}

في هذه المرحلة، كل الطلبات التي تأتي على /api/orders أو /api/users أو غيرها، يتم تمريرها مباشرة إلى النظام القديم. لا يوجد أي تغيير في السلوك.

المرحلة الثانية: بناء الخدمة الجديدة وتحويل جزء من الطلبات

قمنا ببناء خدمة مصغرة جديدة باستخدام Node.js و Express للتعامل مع طلبات GET /api/orders فقط. بعد اختبارها جيداً، قمنا بتحديث إعدادات Nginx للبدء في التحويل.

استخدمنا حيلة بسيطة: إذا كان الطلب يحتوي على هيدر (Header) معين، مثلاً X-Use-New-API: true، يتم توجيهه للخدمة الجديدة. هذا سمح لفريقنا بالاختبار على البيئة الحقيقية بدون التأثير على المستخدمين العاديين.


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

http {
    # ... upstreams from before

    # متغير يحدد أين نرسل الطلب
    map $http_x_use_new_api $orders_destination {
        default "legacy";
        "true"  "new";
    }

    server {
        listen 80;

        # التعامل مع طلبات "الطلبات" بشكل خاص
        location /api/orders {
            # إذا كانت القيمة "new"، اذهب للخدمة الجديدة
            if ($orders_destination = "new") {
                proxy_pass http://new_orders_service;
            }
            # وإلا، اذهب للنظام القديم
            if ($orders_destination = "legacy") {
                proxy_pass http://legacy_system;
            }
            proxy_set_header Host $host;
        }

        # باقي الطلبات تذهب للنظام القديم كالعادة
        location /api/ {
            proxy_pass http://legacy_system;
            proxy_set_header Host $host;
        }
    }
}

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

نصائح أبو عمر من قلب المعركة: كيف تنجح في تطبيق هذا النمط؟

من خلال تجربتي، تعلمت بعض الدروس التي قد توفر عليك الكثير من العناء:

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

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

الخلاصة: لا تهدم البيت القديم، بل ابنِ حوله قصراً جديداً 🏛️

يا جماعة، التعامل مع الأنظمة القديمة هو جزء لا يتجزأ من حياة أي مبرمج. الهروب منها ليس خياراً دائماً، ومحاولة هدمها بالكامل غالباً ما تكون مخاطرة لا تُحمد عقباها. نمط التين الخانق يقدم لنا طريقاً ثالثاً: طريقاً حكيماً، عملياً، وآمناً.

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

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

أبو عمر

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

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

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

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

آخر المدونات

نصائح برمجية

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

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

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

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

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

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

واجهاتي البرمجية كانت ترسل جبلاً من البيانات لتعرض اسماً واحداً: كيف أنقذني GraphQL من كابوس الـ Over-fetching؟

أشارككم قصتي مع "الـ Over-fetching" وكيف تسببت واجهات REST API التقليدية في إبطاء تطبيقاتي. اكتشفوا معي كيف كانت لغة GraphQL هي المنقذ الذي غيّر طريقة...

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

تطبيقنا كان على وشك الاختفاء: كيف أنقذتني استراتيجية “الاستعداد النشط” (Active-Active) من كارثة محققة؟

في صباح ذلك اليوم، استيقظت على كارثة: منطقة سحابية رئيسية تعطلت بالكامل. في هذه المقالة، أروي لكم يا جماعة كيف أنقذت استراتيجية "الاستعداد النشط" (Active-Active)...

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