أذكرها وكأنها البارحة. كانت ليلة شتاء باردة، والساعة قد تجاوزت الثانية صباحاً. أنا وفريقي كنا في حالة استنفار قصوى، نحاول إنقاذ “الوحش”، وهو نظام مالي ضخم وقديم لأحد العملاء. هذا النظام، الذي نسميه في عالمنا “مونوليث” (Monolith)، كان قلب عمليات الشركة النابض، وأي توقف له يعني خسائر بالآلاف كل دقيقة.
المشكلة بدأت بطلب بسيط: “أبو عمر، بدنا نضيف طريقة دفع جديدة”. على الورق، تبدو مهمة سهلة. لكن مع هذا “الوحش”، أي تغيير صغير كان أشبه بمحاولة نزع خيط من كُبّة صوف معقّدة ومتشابكة منذ عشر سنوات. بعد أسابيع من العمل، أطلقنا التحديث… وبعدها بدقائق، انهار كل شيء. ليس فقط نظام الدفع، بل تقارير المخزون، نظام الفواتير، وحتى صفحة تسجيل الدخول! رنّ هاتفي وكان صوت المدير على الطرف الآخر يملؤه الهلع: “شو اللي بصير يا أبو عمر؟! النظام كله واقع!”.
في تلك اللحظة، وأنا أرى فريقي المنهك يحاول إعادة النظام للحياة، أدركت أن طريقتنا كانت خاطئة تماماً. محاولة “الجراحة المباشرة” لهذا المونوليث كانت انتحاراً تقنياً. كنا بحاجة إلى استراتيجية مختلفة، استراتيجية تسمح لنا بتحديث النظام قطعة قطعة دون أن نوقف قلبه عن النبض. وهنا، تذكرت نمطاً مستوحى من الطبيعة، نمط غيّر طريقة تفكيري في تحديث الأنظمة القديمة إلى الأبد: نمط الشجرة الخانقة (Strangler Fig Pattern).
ما هو النظام المونوليث (Monolith)؟ ولماذا هو “بعبع” المبرمجين؟
قبل أن نغوص في الحل، دعونا نتفق على تعريف المشكلة. النظام المونوليث، يا جماعة الخير، هو تطبيق برمجي تم بناؤه كوحدة واحدة عملاقة. تخيل كل شيء – واجهة المستخدم، منطق الأعمال (Business Logic)، الوصول للبيانات – كله مكدّس في قاعدة كود واحدة، ويتم نشره (deploy) ككتلة واحدة.
في البداية، يكون هذا النهج سريعاً وسهلاً. لكن مع مرور السنوات وتزايد الميزات، يتحول هذا “المبنى” الجميل إلى “وحش” متشابك، أو كما أحب أن أسميه “كُبّة خيطان معجّقة”. أي محاولة لتغيير خيط صغير قد تتسبب في شدّ عشرات الخيوط الأخرى وعمل كوارث. أبرز مشاكله:
- صعوبة التحديث: تغيير بسيط في جزء قد يؤثر على أجزاء أخرى غير متوقعة تماماً.
- التحجيم (Scaling) غير الفعّال: إذا كان جزء واحد فقط من النظام عليه ضغط (مثلاً، خدمة البحث)، يجب عليك عمل نسخة كاملة من التطبيق العملاق لتلبية هذا الضغط، وهذا هدر كبير للموارد.
- التقيّد التكنولوجي (Technology Lock-in): أنت عالق مع لغة البرمجة وقواعد البيانات التي بدأت بها. هل تريد تجربة لغة Go لخدمة عالية الأداء؟ أو استخدام قاعدة بيانات NoSQL لجزء معين؟ حظاً موفقاً مع المونوليث!
- بطء التطوير والنشر: أي تغيير، مهما كان صغيراً، يتطلب اختبار ونشر التطبيق بأكمله، وهي عملية بطيئة ومحفوفة بالمخاطر.
باختصار، المونوليث يبدأ كصديق وفيّ، لكنه مع الزمن يصبح سجيناً يصعب الهروب منه.
المنقذ من الطبيعة: نمط الخانق (Strangler Fig Pattern)
بعد ليلة الكارثة تلك، بدأت أبحث بجنون عن حلول. الحل لم يأتِ من كتاب تقني معقد، بل من مقال للمهندس الأسطوري “مارتن فاولر” الذي استلهم الفكرة من رحلة له في غابات أستراليا.
شجرة التين الخانقة (Strangler Fig) هي نبتة تبدأ حياتها كبذرة صغيرة على أغصان شجرة قديمة ضخمة. ثم تبدأ بإنزال جذورها ببطء نحو الأرض، وتنمو أغصانها حول الشجرة المضيفة. مع مرور الوقت، تنمو هذه النبتة وتتشابك جذورها وأغصانها لتشكل هيكلاً قوياً حول الشجرة القديمة، تحجب عنها ضوء الشمس وتنافسها على الموارد، حتى تموت الشجرة القديمة وتتحلل، تاركةً وراءها شجرة التين الجديدة القوية قائمة بذاتها.
الفكرة عبقرية وبسيطة: بدلاً من محاولة “جراحة” المونوليث، سنبني نظاماً جديداً حوله، قطعة قطعة، حتى “نخنقه” تدريجياً ويصبح بلا فائدة، ثم نتخلص منه. كل هذا والنظام القديم لا يزال يعمل ويخدم المستخدمين.
خطوات عملية لتطبيق نمط الخانق: دليل أبو عمر خطوة بخطوة
هذا ليس كلاماً نظرياً، بل هي الخطوات التي طبقناها بالزبط لإنقاذ “الوحش” وتحويله إلى مجموعة خدمات حديثة (Microservices) دون توقف يذكر. إليكم خارطة الطريق:
الخطوة الأولى: تعيين “الحارس الجديد” (The Facade)
أول وأهم خطوة هي وضع “واجهة” أو “بوابة” (Facade) أمام النظام القديم. هذه الواجهة هي عبارة عن Reverse Proxy أو API Gateway. ستصبح هي نقطة الدخول الوحيدة لكل الطلبات القادمة من المستخدمين أو الأنظمة الأخرى.
في البداية، وظيفة هذا الحارس بسيطة جداً: تمرير كل الطلبات كما هي إلى المونوليث القديم. لا شيء يتغير من ناحية وظيفية، لكننا الآن نملك نقطة تحكم مركزية.
مثال بسيط باستخدام Nginx كـ Reverse Proxy:
# nginx.conf
server {
listen 80;
server_name my-awesome-app.com;
location / {
# في البداية، كل الطلبات تذهب إلى النظام القديم
proxy_pass http://legacy_monolith_address:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
نصيحة من أبو عمر: بلّش صغير. لا تعقّد الأمور. فقط ضع الواجهة واجعلها تمرر كل شيء. هذه الخطوة وحدها تمنحك القدرة على المراقبة والتحكم في المستقبل.
الخطوة الثانية: اختيار أول “ضحية” للخنق
الآن بعد أن أصبح لدينا “حارس” على البوابة، حان وقت اختيار أول جزء من المونوليث لنستبدله. كيف نختار؟
- ابدأ بشيء قليل المخاطر: لا تبدأ بأكثر جزء حساس في النظام (مثل نظام الدفع!). ابدأ بصفحة “من نحن” أو وحدة التقارير التي تعتمد على القراءة فقط (Read-only).
- اختر شيئاً ذا قيمة: اختر وحدة يكثر عليها الطلب للتعديل والتطوير. بهذا، سيشعر العميل والمدراء بقيمة ما تفعله بسرعة.
- ابحث عن الحدود الواضحة: اختر وحدة مستقلة نسبياً ولها حدود واضحة (Bounded Context). مثلاً، نظام إدارة ملفات المستخدمين (User Profiles) غالباً ما يكون خياراً ممتازاً.
نصيحة من أبو عمر: في حالتنا، اخترنا نظام “إدارة العروض والخصومات”. كان نظاماً يتغير باستمرار، ومشاكله كثيرة، ولكنه ليس جزءاً حيوياً لدرجة أن أي خطأ فيه سيوقف العمل بالكامل.
الخطوة الثالثة: بناء الخدمة الجديدة وتوجيه الطلبات
الآن يبدأ المرح الحقيقي. قم ببناء الوظيفة التي اخترتها كخدمة جديدة مستقلة (Microservice). استخدم أحدث التقنيات التي تريدها! بايثون؟ Node.js؟ Go؟ لك الحرية الكاملة.
بعد أن تصبح الخدمة الجديدة جاهزة، نعود إلى “الحارس” (الـ Proxy) ونقوم بتعديل بسيط على إعداداته. سنجعله يوجه الطلبات الخاصة بهذه الوظيفة الجديدة إلى الخدمة الجديدة، بينما باقي الطلبات تستمر بالذهاب إلى المونوليث.
مثال لتحديث إعدادات Nginx:
# nginx.conf - UPDATED
# عنوان الخدمة الجديدة
upstream new_promotions_service {
server new_promotions_service_address:3000;
}
server {
listen 80;
server_name my-awesome-app.com;
# الطلبات الخاصة بالعروض تذهب للخدمة الجديدة
location /api/promotions {
proxy_pass http://new_promotions_service;
proxy_set_header Host $host;
}
# أي طلب آخر يذهب للنظام القديم
location / {
proxy_pass http://legacy_monolith_address:8080;
proxy_set_header Host $host;
}
}
نصيحة من أبو عمر: أكبر تحدٍ هنا هو التعامل مع البيانات. هل ستتصل الخدمة الجديدة بنفس قاعدة بيانات المونوليث القديمة (مؤقتاً)؟ أم ستقوم بنسخ البيانات إلى قاعدة بيانات خاصة بها والمحافظة على تزامنها؟ هذا قرار معماري مهم يحتاج إلى تخطيط دقيق. نحن بدأنا بالاتصال بنفس قاعدة البيانات لتسريع العملية، ثم خططنا لفصلها لاحقاً.
الخطوة الرابعة: التكرار والخنق التدريجي (Rinse and Repeat)
الآن، كل ما عليك فعله هو تكرار الخطوتين الثانية والثالثة. اختر وحدة أخرى، ابنها كخدمة مستقلة، ثم قم بتحديث “الحارس” لتوجيه الطلبات إليها. مع كل تكرار:
- تنمو “شجرة التين الخانقة” (نظامك الجديد) وتصبح أقوى.
- يتقلص دور “الشجرة القديمة” (المونوليث) وتصبح وظائفها أقل.
- فريقك يكتسب ثقة وخبرة أكبر مع كل خطوة ناجحة.
الخطوة الخامسة: إعلان وفاة المونوليث 🥳
بعد أشهر (أو ربما سنوات، حسب حجم النظام)، ستصل إلى اللحظة المجيدة التي تكون فيها كل وظائف المونوليث قد تم نقلها إلى خدمات جديدة. المونوليث القديم أصبح الآن مجرد هيكل فارغ لا يستقبل أي طلبات. هنا، وبكل فخر واحتفال، يمكنك إيقافه عن العمل وحذفه إلى الأبد.
نصيحة من أبو عمر: لا تستعجل في هذه الخطوة. راقب سجلات “الحارس” (الـ Proxy) لأسابيع وتأكد 100% أنه لا توجد أي طلبات تذهب إلى النظام القديم. بعدها، احتفل مع فريقك، فأنتم لم تقوموا فقط بتحديث نظام، بل قمتم بعملية جراحية معقدة وناجحة دون أن يشعر المريض (العميل) بأي ألم.
خلاصة أبو عمر ونصيحة من القلب 💡
تحديث الأنظمة القديمة ليس مهمة سهلة، ومحاولة إعادة كتابة كل شيء من الصفر (Big Bang Rewrite) غالباً ما تنتهي بالفشل أو بتجاوز فلكي للميزانية والوقت. نمط الخانق (Strangler Fig Pattern) ليس حلاً سحرياً أو سريعاً، بل هو استراتيجية منهجية وواقعية تقلل المخاطر بشكل هائل وتسمح لك بتحقيق قيمة ملموسة بشكل تدريجي.
تذكر دائماً، تحديث الأنظمة القديمة ليس سباق سرعة، بل هو ماراثون. خذ نفساً عميقاً، خطط جيداً، استعن بفريقك، واستخدم نمط الخانق كخارطة طريق لك. قد تكون الرحلة طويلة، لكن الوصول إلى خط النهاية ورؤية نظام حديث، مرن، وقابل للتطوير يعمل بكفاءة هو شعور لا يقدر بثمن.
يعطيكم ألف عافية، وشدّوا حيلكم يا شباب!