يا أهلاً وسهلاً فيكم يا جماعة الخير. اسمي أبو عمر، واليوم بدي أحكي لكم قصة صارت معي قبل كم سنة، قصة فيها عذاب وأمل، وفيها درس تعلمته بالطريقة الصعبة. كنا نشتغل على نظام تجارة إلكترونية ضخم اسمه “سوقنا”. النظام هذا كان زي الوحش، قطعة برمجية واحدة عملاقة (Monolith) مكتوبة من عشر سنين بتقنيات صارت في ذمة الله.
في البداية، كان الوضع ماشي. لكن مع الوقت، صار “سوقنا” مثل سجن كبير. أي تعديل بسيط، ولو كان تغيير لون زر، كان يحتاج نعيد فحص ونشر (Deploy) المشروع كله. والنشرة الواحدة كانت كابوس، بتضل لآخر الليل واحنا حاطين إيدينا على قلوبنا لا يضرب إشي. الفريق صار يخاف يلمس الكود، وكلمة “تحديث” صارت تسبب لنا قشعريرة. الإدارة بدها ميزات جديدة، واحنا بنقلهم “والله ورطة، النظام ما بتحمل!”.
الضربة القاضية إجت لما اكتشفنا ثغرة أمنية خطيرة في نظام تسجيل الدخول. لو بدنا نصلحها بالطريقة الصح، لازم نغير مكتبات أساسية في المشروع، وهذا معناه احتمال 90% إنه كل إشي ثاني يخرب. قعدنا يومين في اجتماعات والكل متوتر، شعور بالعجز رهيب. وقتها، واحد من الشباب حكى: “يا عمي انسفوا هالكود وخلونا نكتبه من الصفر!”. للوهلة الأولى، الفكرة كانت مغرية، حلم البداية النظيفة… لكن في قرارة نفسي كنت عارف إنه هذا فخ. كيف رح نقنع الإدارة توقف كل الشغل سنتين عشان نعيد بناء إشي هو أصلاً (نوعاً ما) شغال؟
هون، تذكرت مقال قرأته زمان لمارتن فاولر عن نمط غريب اسمه “التين الخانق”. وقتها حسيت إنه ممكن يكون طوق النجاة. ومن هنا بدأت رحلة الهروب من سجن المونوليث.
ما هو المونوليث (Monolith)؟ ولماذا يصبح سجنًا؟
قبل ما نكمل القصة، خلينا نوخذ خطوة لورا ونفهم شو يعني “مونوليث”. ببساطة، المعمارية المتجانسة أو المونوليث هي لما يكون تطبيقك كله عبارة عن قطعة واحدة. كل إشي – واجهة المستخدم، منطق العمل (Business Logic)، التعامل مع قاعدة البيانات – كله موجود في نفس المشروع، وبيتم نشره كوحدة واحدة.
في بداية أي مشروع، هذا الأسلوب ممتاز:
- بسيط: سهل تبدأ فيه وتطوره بسرعة.
- سهل الاختبار: بتقدر تشغل التطبيق كله على جهازك وتختبره بسهولة.
- نشر مباشر: عملية نشر واحدة للتطبيق كله.
لكن مع مرور الزمن وكبر المشروع، المزايا هاي بتتحول لعيوب قاتلة. المونوليث بصير زي “كرة الطين الكبيرة” (Big Ball of Mud). كل أجزاءه بتصير معتمدة على بعضها بطريقة فوضوية. وهذا هو السجن اللي كنا فيه:
- التحديثات المرعبة: أي تغيير صغير ممكن يكسر إشي ثاني في مكان ما بتتوقعه.
- صعوبة التوسع (Scaling): لو عندك ضغط على جزء واحد من النظام (مثلاً، صفحة المنتجات)، لازم تعمل نسخ من التطبيق كله، وهذا هدر للموارد.
- سجن التقنيات: أنت محبوس بنفس التقنيات اللي بديت فيها. بدك تستخدم لغة برمجة جديدة لجزء معين؟ شبه مستحيل.
- صعوبة على المبرمجين الجدد: المبرمج الجديد بحتاج شهور بس عشان يفهم الخريطة المعقدة للكود قبل ما يقدر يكتب سطر واحد مفيد.
الهروب الكبير: لماذا إعادة الكتابة من الصفر فكرة سيئة؟
زي ما حكيت، أول رد فعل طبيعي لما تشوف كود قديم ومعقد هو “خلونا نعيد كل إشي من جديد!”. هذه الفكرة، اللي بنسميها “The Big Rewrite”، تبدو منطقية لكنها من أخطر الفخاخ في عالم البرمجيات.
“القرار الوحيد الأسوأ من البدء بمونوليث هو إعادة كتابته من الصفر.”
ليش؟ لأنك بتستبدل مشكلة تقنية بمخاطر عمل (Business Risks) ضخمة:
- الوقت والتكلفة: إعادة الكتابة بتاخذ وقت طويل جداً، ممكن سنوات. خلال هذه الفترة، شركتك ما رح تقدر تضيف أي ميزات جديدة، والمنافسين رح يسبقوك.
- تكرار نفس الأخطاء: الفريق اللي بنى المونوليث المعقد الأول، إذا ما تعلم دروسه، رح يبني مونوليث معقد ثاني بتقنيات أحدث.
- فقدان منطق العمل الخفي: الأنظمة القديمة مليئة بقواعد عمل وحالات خاصة (edge cases) ما حدا متذكرها ومش مكتوبة في أي مكان. لما تعيد الكتابة، رح تنساها وتسبب مشاكل كبيرة للمستخدمين.
إذن، إذا كانت إعادة الكتابة فخاً، والبقاء مع المونوليث جحيماً، شو الحل؟
بصيص الأمل: تعرف على نمط ‘التين الخانق’ (Strangler Fig Pattern)
هنا يأتي دور بطل قصتنا: نمط التين الخانق. الاسم مستوحى من شجرة التين الخانق في الغابات الاستوائية. هذه الشجرة تبدأ حياتها كبذرة صغيرة على غصن شجرة قديمة ضخمة. مع الوقت، تنزل جذورها للأرض وتنمو حول الشجرة القديمة، وتتشابك أغصانها حتى تحجب ضوء الشمس عنها. بعد سنوات طويلة، الشجرة القديمة تموت وتتحلل، وتبقى شجرة التين الخانق مكانها، قوية وشامخة.
الفكرة في البرمجة مشابهة تماماً: بدل ما تهدم المبنى القديم، ابدأ ببناء واجهات حديثة وجميلة حوله، طوبة فوق طوبة، حتى يصبح المبنى القديم غير مرئي وغير مستخدم، وعندها يمكنك هدمه بأمان.
النمط هذا يسمح لك بتحديث نظامك تدريجياً، مع تقليل المخاطر، وبدون إيقاف عجلة تطوير الميزات الجديدة. إنه استراتيجية تعايش ثم استبدال، وليست هدم وبناء.
خطوات عملية لتطبيق نمط التين الخانق (من الميدان مباشرة)
طيب يا أبو عمر، كلام جميل، بس كيف نطبقه عملياً؟ “كيف بدنا نبلش الشغل؟”. هاي هي الخطوات اللي اتبعناها في مشروع “سوقنا” ونجحت معنا، حبة حبة.
الخطوة الأولى: تحديد الواجهة الخانقة (The Strangler Facade)
أول وأهم خطوة هي بناء “السور” اللي رح تنمو عليه الشجرة الجديدة. هذا السور هو عبارة عن نقطة دخول واحدة لكل طلبات المستخدمين، وغالباً ما يكون بروكسي عكسي (Reverse Proxy) مثل Nginx, HAProxy, أو أي API Gateway على السحابة.
في البداية، كل وظيفة هذا البروكسي هي إنه يستقبل كل الطلبات ويوجهها مباشرة للنظام القديم (المونوليث) بدون أي تغيير.
نصيحة أبو عمر: هذه الخطوة لازم تكون سهلة وسريعة. لا تعقدها. الهدف فقط هو السيطرة على نقطة الدخول. لازم كل الترافيك يمر من خلال هذا البروكسي قبل ما يوصل للمونوليث.
مثال بسيط لإعدادات Nginx في البداية:
# nginx.conf
# الخادم القديم (المونوليث) يعمل على بورت 8080
upstream monolith_app {
server monolith.internal:8080;
}
server {
listen 80;
server_name www.souqona.com;
location / {
# كل الطلبات تذهب مباشرة إلى المونوليث
proxy_pass http://monolith_app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
بهذا الإعداد، أنت الآن تتحكم في بوابة النظام. لم يتغير شيء بالنسبة للمستخدم، لكنك زرعت أول بذرة للسيطرة.
الخطوة الثانية: اختيار أول قطعة ‘للخنق’ (Identify First Service)
الآن تبدأ المتعة. بدك تختار جزء من النظام عشان تبني له بديل حديث كـ “خدمة مصغرة” (Microservice). اختيارك الأول حاسم جداً لنجاح العملية.
نصيحة أبو عمر: ابدأ صغيراً، صغيراً جداً! اختر جزءاً قليل المخاطر، ويفضل أن يكون للقراءة فقط (read-only) إن أمكن. لا تبدأ بنظام الدفع أو سلة المشتريات! ممكن تبدأ بصفحة “من نحن”، أو صفحة عرض ملف المستخدم (User Profile) بدون تعديل.
في حالتنا، اخترنا صفحة عرض الملف الشخصي للمستخدم. كانت صفحة بسيطة نسبياً، وتقدر تعملها كخدمة مستقلة باستخدام أي تقنية جديدة (اخترنا Node.js وقتها عشان السرعة).
الخطوة الثالثة: التحويل التدريجي (The Switch)
بعد ما بنيت الخدمة الجديدة وشغلتها، حان وقت “الخنق” الأول. رح نرجع لملف إعدادات Nginx ونعمل تعديل بسيط. رح نخبره: “يا بروكسي، أي طلب يجي على المسار /profile، لا ترسله للمونوليث، أرسله للخدمة الجديدة”.
# nginx.conf (بعد التحديث)
upstream monolith_app {
server monolith.internal:8080;
}
# الخدمة الجديدة للملف الشخصي تعمل على بورت 3000
upstream profile_service {
server profile-service.internal:3000;
}
server {
listen 80;
server_name www.souqona.com;
# هنا الخنق!
# الطلبات لصفحة الملف الشخصي تذهب للخدمة الجديدة
location /profile {
proxy_pass http://profile_service;
# ... باقي إعدادات البروكسي
}
# باقي الطلبات تذهب للمونوليث كالعادة
location / {
proxy_pass http://monolith_app;
# ... باقي إعدادات البروكسي
}
}
بمجرد تطبيق هذا التغيير، أنت نجحت في أول عملية استبدال. المستخدمين اللي بزوروا صفحة الملف الشخصي الآن يستخدمون الكود الجديد والحديث، بينما باقي الموقع ما زال يعمل على النظام القديم. ما حدا حس بإشي، والعملية تمت بسلاسة. شغل مرتب!
الخطوة الرابعة: التعامل مع البيانات (The Data Challenge)
هذا هو الجزء الأصعب غالباً. الخدمة الجديدة (خدمة الملف الشخصي) تحتاج بيانات المستخدمين. وين هاي البيانات موجودة؟ طبعاً في قاعدة بيانات المونوليث الضخمة.
هناك عدة استراتيجيات للتعامل مع هذا التحدي، وما في حل واحد سحري:
- قاعدة بيانات مشتركة (مؤقتاً): في البداية، ممكن تسمح للخدمة الجديدة تقرأ مباشرة من جداول قاعدة بيانات المونوليث. هذا يعتبر anti-pattern (نمط سيء) على المدى الطويل لأنه يخلق اعتمادية، لكنه ممكن يكون حل مؤقت وسريع عشان تمشي شغلك.
- التزامن عبر الأحداث (Event-Driven Sync): لما يصير أي تحديث على بيانات المستخدم في النظام القديم، النظام القديم يرسل “حدث” (event) عبر نظام طوابير رسائل (Message Queue) مثل RabbitMQ أو Kafka. الخدمة الجديدة بتسمع لهذه الأحداث وبتحدث قاعدة بياناتها الخاصة. هذا حل ممتاز لكنه يتطلب تعديل الكود القديم.
- واجهة برمجة تطبيقات (API) فوق القديم: تخلي الخدمة الجديدة تطلب البيانات اللي تحتاجها من المونوليث عبر API. يعني المونوليث يوفر API للخدمات الجديدة عشان تسحب منه البيانات. هذا حل جيد لأنه يفصل الاعتمادية على مستوى قاعدة البيانات.
نصيحة أبو عمر: لا تبحث عن الحل المثالي من أول يوم. ابدأ بأبسط حل ممكن (مثل القراءة المباشرة من قاعدة البيانات أو عبر API بسيط)، وبعد ما تثبت الفكرة، بتقدر تحسن طريقة التعامل مع البيانات لاحقاً.
الخطوة الخامسة: كرر ثم احتفل! 🎉
الآن صار عندك الوصفة. كل ما عليك هو تكرار الخطوات من 2 إلى 4:
- اختر الجزء التالي من النظام (مثلاً، كتالوج المنتجات).
- ابنِ له خدمة مصغرة جديدة.
- حدث البروكسي (Nginx) ليوجه الطلبات للخدمة الجديدة.
- حل مشكلة البيانات.
- كرر…
مع كل تكرار، الشجرة الجديدة بتكبر، والمونوليث بيصغر. الأجزاء اللي بتنتقل للخدمات الجديدة بتصير أسهل في التحديث والتطوير والتوسع. وفريقك بيكتسب ثقة وحماس.
وفي يوم من الأيام، بعد شهور أو يمكن سنوات، رح تكتشف إنك نقلت آخر قطعة من المونوليث. في تلك اللحظة، كل الطلبات صارت تروح للخدمات الجديدة، والمونوليث القديم واقف هناك محدش بستخدمه. وقتها، وبكل فخر، بتقدر تطفيه وتحذفه للأبد. هذا يوم للاحتفال الكبير!
خلاصة الكلام ونصيحة أخيرة
نمط التين الخانق ليس حلاً سحرياً، بل هو استراتيجية طويلة النفس تتطلب صبراً وتخطيطاً. لكن جمالها يكمن في أنها واقعية وعملية. هي تسمح لك بالتحرك إلى الأمام وتقديم قيمة للعمل بشكل مستمر، بدلاً من المخاطرة بكل شيء في عملية إعادة كتابة ضخمة محكوم عليها بالفشل غالباً.
لقد أنقذنا هذا النمط من جحيم حقيقي، وحوّل اليأس إلى أمل، والخوف من التغيير إلى حماس للتطوير. لقد حررنا من سجن المونوليث، غصناً تلو الآخر.
نصيحتي الأخيرة لك: لا تنظر إلى نظامك القديم على أنه عدو يجب تدميره. انظر إليه على أنه الأساس الذي خدمك لسنوات، والآن حان الوقت لتبني عليه شيئاً أفضل وأقوى. نمط التين الخانق يعلمنا احترام القديم بينما نحتضن الجديد، حبة حبة. 🌱