خليني أحكيلكم قصة صارت معي قبل كم سنة. كنا في اجتماع متأخر بالليل، والقهوة السادة اللي بتعدل الراس ما عادت تجيب نتيجة. كنا غرقانين في مشروع ضخم لإعادة كتابة نظامنا الأساسي، نظام “مونوليثي” قديم ومعقد زي حارات البلد القديمة، كل شارع بودّي على عشرين زقاق، ولو غيرت حجر واحد ممكن السقف كله يوقع.
المشروع كان اسمه “فينيكس”، على أساس إنه رح ينبعث من رماد النظام القديم. لكن بعد سنة ونص، الفينيكس كان لسا ما طلع من البيضة. الميزانية انفجرت، والمواعيد النهائية صارت مجرد ذكرى حلوة، وفريق العمل وصل لمرحلة من اليأس والإحباط ما الها مثيل. المدير التقني (CTO) كان على وشك يكبس الزر الأحمر ويلغي المشروع كله، ونرجع “لجحيم” النظام القديم، بس مع خسارة ملايين الدولارات وسنة ونص من عمرنا.
في هذيك اللحظة، وأنا بتصفح مذكراتي، تذكرت مقال قرأته لـ “مارتن فاولر”، الأب الروحي لكثير من مفاهيم هندسة البرمجيات. كان بيحكي عن نمط اسمه “التين الخانق” (Strangler Fig Pattern). قمت وقفت وقلت: “يا جماعة الخير، صلوا على النبي… إحنا بنحرث في البحر. ليش ما نجرب ن’خنق’ النظام القديم بدل ما نحاول نفجره؟”. نظرات الاستغراب كانت كافية، لكنها كانت بداية الخيط اللي أنقذنا كلنا.
ما هو النظام المونوليثي (Monolith) ولماذا هو مشكلة؟
قبل ما نكمل القصة، لازم نفهم مين هو “العدو” اللي كنا بنواجهه. النظام المونوليثي (Monolithic Architecture) هو تطبيق برمجي كل مكوناته مترابطة ببعضها في كتلة واحدة. تخيل بيت كل غرفه مبنية فوق بعضها بدون أبواب خارجية، عشان تروح من المطبخ للحمام لازم تمر بغرفة النوم والصالون. في البداية، بيكون البناء سريع وسهل، لكن مع الوقت بصير كابوس.
صعوبة التحديث والتطوير
أي تغيير بسيط، حتى لو كان تعديل لون زر، بيحتاج إعادة اختبار ونشر (Deploy) للنظام بأكمله. العملية بطيئة ومرعبة، لأن أي خطأ صغير ممكن يوقف كل شيء. كنا بنسميها “جمعة الرعب” لأنه يوم النشر كان مرعب بحق وحقيق.
المخاطر العالية عند النشر (Deployment)
بما أن كل شيء كتلة واحدة، ففشل جزء واحد يعني فشل النظام كله. ما في عزل بين المكونات. لو خدمة الدفع وقفت، موقعك كله بيوقف، حتى صفحة “من نحن” اللي ما الها علاقة.
الارتباط التقني المقيت (Technology Lock-in)
النظام مبني بتقنية واحدة قديمة (مثلاً Java 6 أو .NET Framework 3.5). هل تريد تجربة لغة جديدة مثل Go أو Python في جزء معين؟ مستحيل! أنت محبوس في التكنولوجيا القديمة اللي بدأت فيها، وتحديثها مغامرة بحد ذاتها.
صعوبة التوسع (Scalability)
إذا صار ضغط على جزء معين من النظام (مثلاً، خدمة البحث)، لازم تعمل نسخة من النظام كله عشان تتحمل الضغط. هذا استهلاك غير فعال للموارد بشكل كبير.
فخ إعادة الكتابة الكاملة (The Big Bang Rewrite)
لما توصل لهاي المرحلة من الألم، أول حل بيخطر على بالك هو: “يلا نمسح كل شيء ونبنيه من جديد صح!”. هذا الفخ اللي وقعنا فيه، واللي بيسموه “إعادة الكتابة الشاملة” أو “الانفجار الكبير”. هو فخ جذاب لكنه قاتل للأسباب التالية:
- الوقت الطويل: ممكن يستغرق سنوات، وفي هذا الوقت البزنس ما رح يستناك. المنافسين بيطلقوا ميزات جديدة وأنت لسا بتبني الأساسات.
- الهدف المتحرك: النظام القديم ما بيوقف. بيستمروا بإضافة ميزات صغيرة عليه عشان البزنس يمشي. فبتصير كأنك بتطارد هدف بيتحرك باستمرار.
- المخاطرة الفلكية: بعد سنوات من العمل، ممكن تكتشف إن النظام الجديد لا يعمل كما هو متوقع، أو إنك نسيت منطق عمل (business logic) مهم كان موجود في النظام القدGيم ومحدش كان فاهمه.
باختصار، إعادة الكتابة الكاملة هي رهان عالي المخاطر، ونسبة نجاحه ضئيلة جداً في الأنظمة الكبيرة والمعقدة.
المنقذ: نمط التين الخانق (Strangler Fig Pattern)
وهنا يأتي دور بطل قصتنا. اسم النمط مستوحى من شجرة التين الخانق في الغابات الاستوائية. هذه الشجرة الذكية تبدأ حياتها كبذرة صغيرة على أغصان شجرة قديمة ضخمة. ثم تبدأ بإنزال جذورها الهوائية نحو الأرض، وتلتف ببطء حول جذع الشجرة المضيفة. مع مرور الوقت، تنمو هذه الجذور وتصبح سميكة وقوية، وتشكل شبكة تحيط بالشجرة القديمة بالكامل، وتنافسها على الضوء والموارد. في النهاية، تموت الشجرة القديمة وتتحلل في الداخل، وتبقى شجرة التين الخانق مكانها، قوية وشامخة.
هذا بالضبط ما يفعله النمط في البرمجة: بناء الجديد حول القديم، والسماح للقديم بأن “يموت” بسلام وبشكل تدريجي.
كيف يعمل النمط خطوة بخطوة؟
الفكرة بسيطة بشكل عبقري وتعتمد على مبدأ “الاعتراض والتوجيه”.
- إنشاء واجهة توجيه (Router Façade): هذه هي أهم خطوة. نضع طبقة جديدة أمام النظام المونوليثي القديم. كل طلبات المستخدمين الآن تمر من خلال هذه الواجهة أولاً. في البداية، كل ما تفعله هذه الواجهة هو تمرير كل الطلبات كما هي إلى النظام القديم.
- تحديد وتطوير الوظيفة الأولى: نختار وظيفة واحدة من النظام القديم لنستبدلها (مثلاً، صفحة عرض ملف المستخدم). نقوم ببناء هذه الوظيفة كخدمة مصغرة (Microservice) جديدة ومستقلة.
- الخنق (Strangling): نقوم بتحديث منطق “واجهة التوجيه”. الآن، عندما يأتي طلب لملف المستخدم، تقوم الواجهة بتوجيهه إلى الخدمة المصغرة الجديدة. أما باقي الطلبات (مثل الطلبات، المنتجات، إلخ) فتظل تمر إلى النظام المونوليثي القديم.
- التكرار والتوسع: نكرر العملية. نختار وظيفة أخرى (مثلاً، سلة المشتريات)، نبنيها كخدمة جديدة، ونحدّث الواجهة لتوجيه الطلبات إليها. وهكذا دواليك، قطعة قطعة.
- تقاعد المونوليث: مع مرور الوقت، يتم “خنق” المزيد والمزيد من وظائف النظام القديم واستبدالها بخدمات جديدة. سيأتي يوم لا تصل فيه أي طلبات للنظام القديم، وعندها يمكننا إطفاؤه وتقاعده بأمان. 🎉
مثال عملي: خنق وحدة إدارة المستخدمين
لنفترض أن لدينا نظام متجر إلكتروني مونوليثي، والطلبات تذهب مباشرة إليه. نريد استبدال وحدة إدارة المستخدمين.
الخطوة 0: الوضع الحالي
العميل يطلب api.my-shop.com/users/123 ويذهب الطلب مباشرة إلى السيرفر المونوليثي.
الخطوة 1: إنشاء الواجهة الأمامية (Façade)
سنستخدم Nginx كـ Reverse Proxy ليكون واجهتنا. كل الطلبات الآن ستذهب إلى Nginx أولاً. في البداية، إعدادات Nginx ستكون بسيطة جداً، فقط لتمرير كل شيء إلى النظام القديم.
# nginx.conf (Initial Setup)
server {
listen 80;
server_name api.my-shop.com;
location / {
proxy_pass http://monolith-internal-ip:8080;
proxy_set_header Host $host;
}
}
الآن، لا شيء تغير بالنسبة للمستخدم، لكننا وضعنا “شرطي المرور” في مكانه.
الخطوة 2: بناء الخدمة الجديدة
نقوم ببناء خدمة مصغرة (باستخدام Node.js, Python, Go.. أي شيء!) تعالج طلبات المستخدمين. لنفترض أنها تعمل على http://user-service-ip:3000 وتستجيب للطلبات على المسار /api/v2/users/{id}.
الخطوة 3: تحديث الواجهة وتوجيه الطلبات (الخنق)
الآن نعود إلى شرطي المرور (Nginx) ونعطيه تعليمات جديدة. سنطلب منه أن يوجه أي طلب يبدأ بـ /api/users/ إلى الخدمة الجديدة، وما عدا ذلك يذهب إلى القديم.
# nginx.conf (After Strangling)
server {
listen 80;
server_name api.my-shop.com;
# --- STRANGLER RULE ---
# Intercept requests for the user profile and route them to the new service
location ~ ^/api/users/(d+)$ {
proxy_pass http://user-service-ip:3000/api/v2/users/$1;
proxy_set_header Host $host;
}
# --- DEFAULT RULE ---
# Everything else goes to the old monolith
location / {
proxy_pass http://monolith-internal-ip:8080;
proxy_set_header Host $host;
}
}
وهكذا، قمنا بخنق أول جزء من المونوليث بنجاح! المستخدم لا يشعر بأي فرق، لكننا في الخلفية بدأنا رحلة التحديث بأمان وبدون مخاطر.
نصائح من خبرة أبو عمر الميدانية
هذا النمط ليس مجرد كود، بل هو استراتيجية وفن. من خلال تجربتي، هذه بعض النصائح اللي بتمنى لو حدا قلي إياها من زمان:
ابدأ صغيرًا وبأقل المخاطر (Start Small)
لا تبدأ بأكثر جزء معقد وحيوي في النظام. ابدأ بشيء بسيط، ويفضل أن يكون للقراءة فقط (read-only)، مثل صفحة “الأسئلة الشائعة” أو “سياسة الخصوصية”. هذا يتيح لك بناء البنية التحتية للنمط (الواجهة، النشر، المراقبة) بدون ضغط كبير.
البيانات أولاً (Data First)
أصعب جزء في هذه العملية هو التعامل مع قاعدة البيانات. كيف ستصل الخدمة الجديدة إلى البيانات؟ هل ستشارك نفس قاعدة البيانات (مؤقتاً)؟ أم ستقوم بمزامنة البيانات؟ أم ستبني طبقة Anti-Corruption Layer؟ فكر في استراتيجية البيانات جيداً قبل أن تكتب سطراً واحداً من الكود.
المراقبة والتوثيق (Monitoring & Logging)
لقد انتقلت من نظام واحد إلى نظام موزع. بدون مراقبة مركزية، ستضيع. استثمر في أدوات لجمع السجلات (Logs) والمقاييس (Metrics) من كل خدماتك في مكان واحد. يجب أن تعرف بالضبط أين يذهب كل طلب، وكم من الوقت يستغرق، وهل نجح أم فشل.
لا تقع في فخ “الخدمة المصغرة لكل شيء”
الهدف هو التخلص من المونوليث، وليس بالضرورة إنشاء ألف خدمة مصغرة. أحيانًا يكون من الأفضل تجميع الوظائف المترابطة في خدمة أكبر قليلاً (Service). فكر في منطق البزنس وليس في التقنية فقط. بدها نفس طويل يا خال، لا تستعجل.
الخلاصة: الاختناق التدريجي أفضل من الانفجار الكبير 🚀
في النهاية، مشروع “فينيكس” الكارثي تم إلغاؤه، وبدأنا رحلة جديدة مع نمط التين الخانق. كانت رحلة أطول، لكنها كانت آمنة، ويمكن التنبؤ بها، وناجحة. كل أسبوعين، كنا “نخنق” جزءاً جديداً من النظام القديم، وكنا نحتفل بهذه الانتصارات الصغيرة كفريق.
نمط التين الخانق يعلمنا درساً مهماً في الحياة والبرمجة: التغيير الجذري والمفاجئ غالباً ما يكون مدمراً. أما التغيير التدريجي، المدروس، والمستمر، فهو الذي يبني المستقبل. نظامك القديم ليس عدوك؛ إنه محارب قديم خدمك جيداً. وهذا النمط هو الطريقة التي تكرم بها خدمته، بينما تبني مستقبلاً أفضل وأكثر مرونة. فلا تخف من المونوليث، بل تعلم كيف تخنقه بحب وحكمة.