مونوليث أم مايكروسيرفسز؟ قرار هندسي بمعايير رقمية لا موضة

المونوليث المنظم هو الخيار الصحيح لأغلب الشركات تحت 20 مطوراً. المايكروسيرفسز تحوّل نداء دالة من نانوثانية إلى نداء شبكة بميلي ثانية، وتضاعف التعقيد التشغيلي. القرار بالأرقام لا بالموضة.
لأغلب الشركات، وتحديداً كل فريق تحت 20 مطوراً، الجواب الهندسي الصحيح هو المونوليث المنظم (modular monolith)، لا المايكروسيرفسز. السبب ليس ذوقاً بل حساب: المايكروسيرفسز تدفع ثمناً حقيقياً قابلاً للقياس مقابل فائدة لا تحتاجها إلا فرق كبيرة. حين تقسّم تطبيقك إلى خدمات مستقلة، تتحول كل عملية كانت نداء دالة داخلي (يكلّف نانوثانية، أي جزءاً من المليار من الثانية) إلى نداء شبكة عبر HTTP أو gRPC يكلّف من 1 إلى 10 ميلي ثانية في أفضل الأحوال داخل نفس مركز البيانات، أي أبطأ بمئات آلاف المرات. صفحة واحدة كانت تجمع بياناتها بخمسة نداءات دوال في ميكروثانية قد تصير خمسة نداءات شبكة بعشرات الميلي ثانية، فضلاً عن أن كل نداء شبكة قد يفشل، فتحتاج إعادة محاولة، وقواطع دائرة (circuit breakers)، ومهلات (timeouts)، وتتبّعاً موزّعاً. الجواب المباشر: ابدأ بمونوليث منظم بحدود داخلية واضحة، وانتقل إلى الخدمات فقط حين يكون لديك سبب رقمي محدد (فريقان مستقلان يتعارضان على النشر، أو مكوّن يحتاج توسّعاً منفصلاً جذرياً، أو نطاق نشر مختلف تماماً)، لا لأن المايكروسيرفسز عنوان رائج.
القاعدة الجوهرية: المايكروسيرفسز حل لمشكلة تنظيمية (فرق كثيرة تصطدم) قبل أن تكون حلاً تقنياً. إن لم تكن تملك تلك المشكلة، فأنت تشتري تعقيدها بلا عائدها.
التكلفة الحقيقية بالأرقام
لنقارن بصدق. الفرق ليس في جودة الكود بل في أين يعيش التعقيد.
| البُعد | مونوليث منظم | مايكروسيرفسز |
|---|---|---|
| نداء بين المكوّنات | نداء دالة، نانوثانية | نداء شبكة، 1 إلى 10 ميلي ثانية |
| احتمال فشل النداء | شبه معدوم | وارد دائماً، يحتاج معالجة |
| النشر | وحدة واحدة | عشرات الأنابيب المستقلة |
| تتبّع خطأ عبر النظام | سجل واحد، stack trace واحد | تتبّع موزّع عبر خدمات |
| معاملة عبر مكوّنات (transaction) | معاملة قاعدة بيانات واحدة | معاملة موزّعة معقّدة (saga) |
| البنية التحتية | خادم أو اثنان | تنسيق حاويات، اكتشاف خدمات، بوابة |
خذ رقم المعاملة الموزّعة تحديداً. في المونوليث، تحديث الطلب وخصم المخزون معاً في معاملة قاعدة بيانات واحدة إما تنجح كلها أو تفشل كلها، بضمانة ACID مجانية. في المايكروسيرفسز، الطلب في خدمة والمخزون في أخرى، فتفقد المعاملة الواحدة وتضطر لبناء نمط saga بتعويضات يدوية عند الفشل، وهذا من أصعب ما في الهندسة الموزّعة وأكثره عرضة للأخطاء.
لماذا المونوليث المنظم صحيح تحت 20 مطوراً
المونوليث لا يعني كوداً فوضوياً. المونوليث المنظم يقسّم النظام داخلياً إلى وحدات (modules) بحدود واضحة، كل وحدة لها واجهتها العامة ولا تلمس الجداول الداخلية لغيرها، لكنها كلها تُنشر معاً وتشارك عملية واحدة. تحصل على الفوائد التنظيمية للفصل دون دفع ضريبة الشبكة:
- سرعة التطوير: مطور واحد يشغّل النظام كاملاً على جهازه بأمر واحد، لا يحتاج تشغيل 12 خدمة ليختبر ميزة.
- تصحيح مباشر: الخطأ يظهر في stack trace واحد متصل، لا تطارده عبر سجلات خمس خدمات.
- إعادة هيكلة آمنة: نقل كود بين الوحدات تغيير محلي يمسكه المصرّف، لا عقد بين خدمتين منشورتين.
- تكلفة تشغيل أقل: يعمل على خادم سحابي واحد أو اثنين، لا على بنية تنسيق حاويات تحتاج فريقاً لصيانتها.
الشركات التي شاع أنها تستخدم مايكروسيرفسز بنتها بعد أن صار لديها مئات المطورين وفرق مستقلة تتعارض على النشر. نسخ حلّها قبل بلوغ حجم مشكلتها خطأ تكلفته باهظة.
نقاط القرار الفعلية
متى تنتقل فعلاً؟ حين تظهر واحدة من هذه الإشارات الرقمية القابلة للقياس:
- فرق مستقلة تتعارض: لديك فريقان أو أكثر يعطّل كل منهما نشر الآخر، فيصير النشر المستقل حاجة تنظيمية حقيقية.
- نطاقات نشر مختلفة جذرياً: مكوّن يُحدَّث عشر مرات يومياً بجوار مكوّن يُحدَّث مرة في الشهر، فربطهما يبطّئ السريع بلا داعٍ.
- احتياج توسّع منفصل حاد: مكوّن معالجة صور أو ذكاء اصطناعي يلتهم المعالج بينما بقية النظام خفيف، فعزله ليتوسّع وحده يوفّر موارد.
- حدود تقنية إلزامية: مكوّن يجب أن يعمل بلغة أخرى أو بمتطلب امتثال يفرض عزلاً.
غياب كل هذه الإشارات يعني أن المونوليث ما زال الخيار الأرخص والأسرع.
المسار التدريجي: من مونوليث منظم إلى خدمات
أفضل استراتيجية ليست الاختيار مرة واحدة للأبد، بل بناء مونوليث منظم بحدود نظيفة من اليوم الأول، بحيث يصبح استخراج خدمة لاحقاً عملية سهلة لا إعادة كتابة. طبّق هذه المبادئ:
- وحدات بحدود صريحة: رتّب الكود بوحدات (طلبات، مخزون، فوترة) لا تصل إحداها لجداول الأخرى مباشرة، بل عبر واجهة معرّفة.
- لا مشاركة جداول عبر الوحدات: كل وحدة تملك جداولها. هذا أهم شرط يجعل الاستخراج ممكناً لاحقاً.
- استخرج عند الحاجة فقط: حين تظهر إشارة قرار حقيقية، اقتطع الوحدة المعنية وحدها إلى خدمة، فتدفع ضريبة الشبكة على حدود واحدة لا على كل النظام.
هكذا تبدأ رخيصاً وسريعاً، وتؤجّل تعقيد التوزيع حتى تجني فائدته فعلاً، لا قبلها. تطبيق نموذجي كهذا يعمل بأريحية على باقة أعمال أو مؤسسة بذاكرة تكفي قاعدة بيانات نشطة وطبقة تخزين مؤقت في عملية واحدة.
أخطاء شائعة عند التبكير بالمايكروسيرفسز
كثير من الفرق الصغيرة تختار المايكروسيرفسز مبكراً ثم تدفع الثمن بأشكال متكررة:
- المونوليث الموزّع: أسوأ النتائج، خدمات منفصلة لكنها مترابطة بحيث لا تُنشر أي واحدة دون الأخريات. حصلت على ضريبة الشبكة وتعقيد النشر بلا استقلالية، أي كل التكلفة بلا الفائدة.
- قاعدة بيانات مشتركة بين الخدمات: عدة خدمات تكتب في نفس الجداول، فتضيع حدود الملكية ويصير أي تغيير في الجدول كسراً محتملاً لخدمات لا تعرفها. هذا يلغي أهم فائدة للفصل.
- تعقيب صعب: خطأ بسيط في طلب مستخدم صار يتطلب فتح سجلات خمس خدمات وربط آثار موزّعة لمعرفة أين وقع، بينما كان stack trace واحداً في المونوليث.
- تكلفة تشغيل مضاعفة: فريق صغير صار يصون تنسيق حاويات واكتشاف خدمات وبوابة ومراقبة موزّعة، وهذه أعمال تستهلك وقت التطوير الحقيقي دون أن تضيف ميزة للعميل.
قصة توسّع نموذجية بالأرقام
تخيّل مساراً واقعياً لشركة سعودية بنظام مخصص. تبدأ بفريق من 3 مطورين ومونوليث منظم على خادم سحابي واحد، فتشحن ميزات بسرعة وتصحّح الأخطاء في stack trace واحد. تنمو إلى 8 مطورين، فتبقى على المونوليث لكنها تشدّ حدود الوحدات وتمنع مشاركة الجداول بينها، فيبقى النشر وحدة واحدة سهلة. عند 15 مطوراً في فريقين، يبدأ فريق الفوترة يتعارض نشره مع فريق الطلبات، فتظهر أول إشارة قرار حقيقية. الحل ليس تفكيك كل شيء، بل استخراج وحدة الفوترة وحدها إلى خدمة مستقلة، فتدفع ضريبة الشبكة على حدّ واحد معروف، ويستقل الفريقان في النشر. تبقى بقية النظام مونوليثاً منظماً، فتحصد فائدة العزل حيث احتجته فقط، لا في كل مكان. هذا المسار التدريجي يوفّر سنوات من التعقيد المبكر، ويؤجّل كل تكلفة حتى اللحظة التي يبرّرها فيها رقم في نظامك.
لاحظ اقتصاد هذا القرار بالأرقام. استخراج خدمة واحدة يضيف نحو 1 إلى 5 ميلي ثانية لكل نداء يعبر الحدّ الجديد، ويحتاج أنبوب نشر مستقلاً ومراقبة إضافية، فهذه تكلفة مقبولة على حدّ واحد يخدم فريقاً مستقلاً. لكن لو فكّكت النظام إلى عشر خدمات دفعة واحدة عند 15 مطوراً، لضربت هذه التكلفة في عشرة بلا مبرّر تنظيمي، وأبطأت كل صفحة تجمع بياناتها من عدة خدمات. الفارق أن التدرّج يربط كل تكلفة بفائدة مقابلة، بينما التفكيك الشامل المبكر يدفع كل التكاليف قبل أن تنضج أي فائدة، وهذا جوهر لماذا يبقى المونوليث المنظم القرار الأصح رقمياً لأغلب الفرق.
خاتمة عملية
قرّر بهذا الميزان: إن كان فريقك تحت 20 مطوراً وليس لديك فرق تتعارض على النشر ولا مكوّن يحتاج توسّعاً منفصلاً حاداً، فابنِ مونوليثاً منظماً بوحدات نظيفة الحدود ولا تشارك الجداول بينها. شغّله على خادم واحد أو اثنين، وراقب المقاييس. حين تظهر إشارة قرار رقمية محددة، استخرج الوحدة الواحدة المعنية إلى خدمة، لا النظام كله دفعة واحدة. لا تختر المايكروسيرفسز لأنها في العناوين، اخترها حين يقول رقم في نظامك إنها صارت أرخص من بقاء المونوليث، وإن أردت خادماً بموارد كافية لمونوليث منظم نشط، ابدأ من سيرفرات الرياض بزمن استجابة نحو 8ms.


