تطبيقنا المونوليث كان وحشًا: كيف أنقذنا ‘نمط التين الخانق’ من جحيم التحديث المستحيل؟

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

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

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

ما هو المونوليث (Monolith)؟ ولماذا يصبح مشكلة؟

قبل ما نغوص في الحل، خلينا نفهم أصل المشكلة. التطبيق المونوليثي (Monolithic Application) هو تطبيق مبني كوحدة واحدة متكاملة. كل أجزاء التطبيق – واجهة المستخدم، منطق العمل (Business Logic)، الوصول للبيانات – كلها مدمجة في قاعدة كود واحدة ويتم نشرها ككتلة واحدة.

في البداية، هذا الأسلوب ممتاز. تبدأ مشروعك بسرعة، التطوير سهل، والنشر بسيط. لكن مع مرور الوقت ونمو التطبيق، تبدأ المشاكل بالظهور مثل الأعشاب الضارة:

  • الترابط الشديد (Tight Coupling): كل جزء يعتمد على الآخر. تغيير صغير يمكن أن يسبب تأثير الدومينو ويؤثر على النظام بأكمله.
  • صعوبة التحديث: تبني تقنية جديدة (مثل استخدام إطار عمل JavaScript حديث أو لغة برمجة جديدة) يكاد يكون مستحيلًا، لأن عليك تحديث التطبيق بأكمله.
  • بطء التطوير والنشر: أي تغيير، مهما كان بسيطًا، يتطلب اختبار وإعادة نشر التطبيق الضخم بأكمله، وهي عملية بطيئة ومحفوفة بالمخاطر.
  • عوائق التوسع (Scalability): إذا كان جزء واحد فقط من التطبيق (مثل خدمة معالجة الصور) يحتاج إلى موارد أكبر، فعليك توسيع التطبيق بأكمله، وهذا هدر كبير للموارد.

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

الكابوس الأكبر: إعادة الكتابة من الصفر (The Big Bang Rewrite)

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

من خبرتي، هذه واحدة من أخطر القرارات التي يمكن أن يتخذها فريق تقني. لماذا؟

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

شفت بعيني فرقًا قضت سنتين في إعادة كتابة نظام، وفي النهاية، ألغي المشروع لأن الشركة لم تعد تستطيع الانتظار أكثر. إذن، ما هو البديل الآمن والعملي؟

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

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

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

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

هذا ليس كلامًا نظريًا، بل هو خطة عمل طبقناها ونجحت. إليكم الخطوات بالتفصيل:

الخطوة الأولى: تحديد الحدود وإنشاء الواجهة الخانقة (The Façade)

أول وأهم خطوة هي وضع “واجهة” أو “بوابة” أمام تطبيقك المونوليثي. هذه الواجهة، التي غالبًا ما تكون Reverse Proxy أو API Gateway، ستكون نقطة الدخول الوحيدة لكل الطلبات الموجهة لنظامك.

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

نصيحة من أبو عمر: يمكنك استخدام أدوات مثل Nginx, Traefik, Kong, أو خدمات سحابية مثل AWS API Gateway أو Azure API Management. ابدأ بأبسط شيء ممكن.

مثال بسيط جدًا باستخدام Nginx:


# nginx.conf

server {
    listen 80;
    server_name my-legacy-app.com;

    location / {
        # في البداية، كل الطلبات تذهب إلى المونوليث
        proxy_pass http://monolith_server:8080;
        proxy_set_header Host $host;
    }
}

الخطوة الثانية: تحديد أول “ضحية” (Choosing the First Service)

الآن، حان وقت اختيار أول قطعة من المونوليث لنستبدلها. كيف تختار؟

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

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

الخطوة الثالثة: البناء والتطوير التدريجي (Incremental Build)

الآن قم ببناء خدمة مصغرة (Microservice) جديدة لتنفيذ الوظيفة التي اخترتها. هذه هي فرصتك الذهبية لاستخدام التقنيات الحديثة التي تحبها!

إذا كان المونوليث مكتوبًا بلغة قديمة، يمكنك كتابة الخدمة الجديدة باستخدام Go, Python (مع FastAPI مثلًا), أو Node.js. يمكنك استخدام قاعدة بيانات حديثة. أنت حر!

نقطة مهمة (البيانات): غالبًا ما ستحتاج خدمتك الجديدة إلى الوصول إلى بيانات موجودة في قاعدة بيانات المونوليث. هنا تكمن الصعوبة. لديك عدة خيارات:

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

خطط جيدًا لهذه الخطوة، فهي قلب عملية الترحيل.

الخطوة الرابعة: الخنق! (The Strangling)

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

باستخدام مثال Nginx السابق، إذا كانت خدمة الإشعارات الجديدة تعمل على عنوان `http://notifications_service:3000` والمسار الخاص بها هو `/api/notifications`, فسنقوم بتحديث الإعدادات كالتالي:


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

server {
    listen 80;
    server_name my-legacy-app.com;

    # توجيه الطلبات الجديدة إلى الخدمة الجديدة
    location /api/notifications {
        proxy_pass http://notifications_service:3000;
        proxy_set_header Host $host;
    }

    # باقي الطلبات لا تزال تذهب إلى المونوليث
    location / {
        proxy_pass http://monolith_server:8080;
        proxy_set_header Host $host;
    }
}

بهذه البساطة! الآن، أي طلب يذهب إلى `/api/notifications` سيتم التعامل معه بواسطة خدمتك الجديدة اللامعة، بينما باقي أجزاء التطبيق تعمل كالمعتاد على المونوليث القديم. لقد قمت بأول عملية خنق ناجحة!

الخطوة الخامسة: المراقبة، التكرار، والتقاعد

العمل لم ينتهِ بعد. يجب عليك مراقبة أداء الخدمة الجديدة عن كثب. استخدم أدوات المراقبة (Monitoring) وتسجيل الأخطاء (Logging) للتأكد من أن كل شيء يعمل بسلاسة.

بعد التأكد من استقرار الخدمة الأولى، كرر العملية: اختر “الضحية” التالية، ابنِ الخدمة الجديدة، وقم بتحديث الواجهة الخانقة. ومع كل تكرار، ستنمو شجرة التين الجديدة، وسيتقلص دور المونوليث القديم.

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

الخلاصة: رحلة الألف ميل تبدأ بخطوة 😉

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

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

بالتوفيق يا جماعة!

أبو عمر

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

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

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

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

آخر المدونات

نصائح برمجية

مدخلاتنا كانت قنابل موقوتة: كيف أنقذتنا “حراسة الشروط” (Guard Clauses) من جحيم الشروط المتداخلة؟

كود يتسبب بكارثة في نظام حيوي، والمشكلة؟ شروط متداخلة معقدة. في هذه المقالة، أشارككم قصة كيف أنقذنا أسلوب "حراسة الشروط" (Guard Clauses) من هذا الجحيم،...

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

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

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

17 أبريل، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

واجهاتنا كانت ميتة: كيف أنقذتنا ‘التفاعلات الدقيقة’ من جحيم الصمت الرقمي؟

أشارككم قصة حقيقية من مسيرتي كمبرمج، عندما كان تطبيقنا "صامتاً" ومملاً رغم عمله بكفاءة. اكتشفوا معنا كيف أحيينا واجهاتنا باستخدام "التفاعلات الدقيقة" (Micro-interactions)، وحولناها من...

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

تحديثاتنا كانت تصل متأخرة دائمًا: كيف أنقذتنا WebSockets من جحيم الـ HTTP Polling المستمر؟

أشارككم قصة حقيقية من أحد المشاريع، حيث كانت التحديثات البطيئة كابوسًا لنا. سأشرح كيف انتقلنا من جحيم ال-HTTP Polling إلى نعيم الاتصال الفوري باستخدام WebSockets،...

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