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

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

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

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

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

ما هو “نمط التين الخانق” (Strangler Fig Pattern)؟

ببساطة شديدة، نمط التين الخانق هو استراتيجية في هندسة البرمجيات لتحديث الأنظمة القديمة (Legacy Systems) بشكل تدريجي وآمن. بدل ما ترمي النظام القديم كله وتعمل واحد جديد (وهو ما يسمى بـ Big Bang Rewrite)، أنت بتبني النظام الجديد قطعة قطعة حول النظام القديم.

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

ليش هالطريقة أحسن من إعادة الكتابة الكاملة؟

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

تقليل المخاطر (Reduced Risk)

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

قيمة أسرع للمستخدم (Faster Value Delivery)

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

مرونة في استخدام التقنيات الحديثة

لما كنا بنبني الخدمات الجديدة، ما كنا مقيدين بتقنيات النظام القديم. بنينا خدمة بلغة Go عشان أدائها العالي، وخدمة تانية بـ Python عشان مكتبات الذكاء الاصطناعي، وواجهات بـ React. هاي المرونة بتسمحلك تختار الأداة الأنسب لكل وظيفة، وهذا اشي مستحيل في النظام المونوليثي.

كيف طبقنا “نمط التين الخانق” خطوة بخطوة؟

خلوني أعطيكم خريطة الطريق العملية اللي مشينا عليها، مع شوية أمثلة عشان الصورة تكون واضحة.

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

أول وأهم خطوة هي بناء “الواجهة الخانقة”. هاي الواجهة هي عبارة عن وكيل عكسي (Reverse Proxy) بيجلس بين المستخدم والنظام القديم. كل الطلبات لازم تمر من خلاله. إحنا استخدمنا Nginx لهذا الغرض لأنه قوي وسريع وسهل الإعداد.

في البداية، كل إعدادات Nginx كانت بسيطة جدًا، مجرد تمرير كل الطلبات للنظام القديم:


# nginx.conf

# عنوان النظام القديم (The Monolith)
upstream legacy_system {
    server legacy.myapp.com;
}

server {
    listen 80;
    server_name www.myapp.com;

    location / {
        # في البداية، كل الطلبات تذهب للنظام القديم
        proxy_pass http://legacy_system;
        proxy_set_header Host $host;
        # ... other proxy headers
    }
}

هيك، صار عنا نقطة تحكم مركزية بكل الترافيك.

الخطوة الثانية: تحديد أول قطعة “للخنق”

هاي خطوة استراتيجية. لازم تختار أول وحدة (module) بدك تستبدلها بحكمة.

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

الخطوة الثالثة: بناء الخدمة المصغرة الجديدة (New Microservice)

بنينا خدمة مصغرة جديدة باستخدام Node.js و Express لإدارة ملفات المستخدمين. هاي الخدمة كانت الها قاعدة بياناتها الخاصة (MongoDB في حالتنا) وكانت مسؤولة عن كل شي بخص ملفات المستخدمين: عرضها، تعديلها، إلخ.

الكود كان بسيط ومستقل، مثل هيك:


// profile-service/index.js
const express = require('express');
const app = express();

// Route to get user profile
app.get('/api/users/:id/profile', (req, res) => {
    // ... منطق جلب بيانات المستخدم من قاعدة البيانات الجديدة
    const userProfile = { id: req.params.id, name: 'أبو عمر الجديد', email: 'abu.omar.new@example.com' };
    res.json(userProfile);
});

// ... باقي الـ routes للتعديل والحذف

app.listen(3001, () => {
    console.log('Profile service is running on port 3001');
});

الخطوة الرابعة: التوجيه التدريجي (Incremental Routing)

هنا يبدأ السحر. رجعنا لملف إعدادات Nginx (الواجهة الخانقة) وعدّلناه عشان يوجه الطلبات الخاصة بملفات المستخدمين للخدمة الجديدة، بينما باقي الطلبات تضلها تروح للنظام القديم.


# nginx.conf

# عنوان النظام القديم (The Monolith)
upstream legacy_system {
    server legacy.myapp.com;
}

# عنوان الخدمة المصغرة الجديدة
upstream profile_service {
    server localhost:3001; # تعمل على نفس السيرفر أو سيرفر آخر
}

server {
    listen 80;
    server_name www.myapp.com;

    # توجيه طلبات البروفايل للخدمة الجديدة
    location /api/users/ {
        proxy_pass http://profile_service;
        proxy_set_header Host $host;
        # ... other proxy headers
    }

    # باقي الطلبات تذهب للنظام القديم
    location / {
        proxy_pass http://legacy_system;
        proxy_set_header Host $host;
        # ... other proxy headers
    }
}

بهذه الطريقة، أي طلب بروح على www.myapp.com/api/users/... بتم توجيهه للخدمة الجديدة، وأي طلب آخر (مثل www.myapp.com/products) بضل يروح للنظام القديم. المستخدم ما بحس بأي فرق، بس هو فعليًا صار يستخدم جزء من النظام الجديد.

الخطوة الخامسة: “الخنق” الكامل وإزالة القديم

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

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

تحديات واجهتنا وكيف تغلبنا عليها

الرحلة ما كانت كلها ورود، واجهتنا تحديات كبيرة، وأهمها:

التعامل مع قاعدة البيانات

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

  • في البداية: بعض الخدمات الجديدة كانت بتقرأ وبتكتب مباشرة على قاعدة بيانات النظام القديم. هذا حل سريع ولكنه خطير لأنه بخلي الخدمات الجديدة معتمدة على تصميم قاعدة البيانات القديمة.
  • الحل الأفضل: اتبعنا نمط “قاعدة بيانات لكل خدمة” (Database per service). وللمزامنة، استخدمنا تقنيات مثل (Change Data Capture – CDC) وأدوات مثل Debezium لنقل التغييرات من قاعدة البيانات القديمة إلى قواعد بيانات الخدمات الجديدة بشكل فوري. هذا أعطانا استقلالية حقيقية.

إدارة الجلسات والمصادقة (Authentication)

كيف تضمن إنه المستخدم اللي سجل دخوله في النظام القديم، يضل مسجل دخوله لما يتفاعل مع خدمة جديدة؟ الحل كان باستخدام JWT (JSON Web Tokens). عدلنا نظام المصادقة القديم ليصدر JWT token، وصارت كل الخدمات (القديمة والجديدة) تتحقق من هذا التوكن لتتأكد من هوية المستخدم.

الخلاصة: التحديث مش لازم يكون كابوس! 😅

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

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

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

أبو عمر

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

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

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

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

آخر المدونات

ادارة الفرق والتنمية البشرية

مسارنا الوظيفي كان طريقًا مسدودًا: كيف أنقذتنا ‘أطر المسار الوظيفي’ من جحيم فقدان أفضل مواهبنا؟

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

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

متغيراتنا كانت مجرد نصوص ساذجة: كيف أنقذتنا ‘كائنات القيمة’ (Value Objects) من جحيم الأخطاء الصامتة؟

هل تعاني من أخطاء صامتة ومُرهقة في برامجك؟ في هذه المقالة، أشارككم تجربتي مع 'التعلق الساذج بالمتغيرات البدائية' وكيف أنقذتنا 'كائنات القيمة' (Value Objects) من...

19 أبريل، 2026 قراءة المزيد
​معمارية البرمجيات

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

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

19 أبريل، 2026 قراءة المزيد
ذكاء اصطناعي

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

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

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

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

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

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

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

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

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