المعمارية English

ADR-0002 — نمط أحادي معياري بدلًا من الخدمات المصغّرة

الحالة: مُعتمَد · التاريخ: 2026-07-20 · صاحب القرار: أمير هارون (القائد التقني) ذو صلة: arc42 §5 · CON-14 · QAS-MOD-03 · R-08 · CONF-04


السياق#

Qwizin منصة SaaS متعددة الأطراف تضم اثنتي عشرة قدرة عمل قابلة للتمييز، وستة أنواع من الجهات الفاعلة، وخارطة طريق للمرحلة الثانية (CONF-04) موجّهة للمستثمرين وتفوق نطاق الـ MVP بأضعاف — POS/PMS، إدارة المخزون، CRM، الحجوزات، والتكامل الحكومي.

طرح المعماري صراحةً سؤال ما إذا كانت الخدمات المصغّرة (microservices) هي الخيار الأفضل. القيود ذات الصلة بالإجابة:

  • CON-01 — تنفيذ منخفض التكلفة، حساسية للميزانية
  • CON-15 — Kubernetes كمنصة orchestration مستهدفة
  • مورّد تنفيذ واحد (آفاق السبل)، فريق واحد
  • هدف نمو طموح: نحو 10⁴ حساب ومئات جلسات الفيديو المتزامنة خلال 12–18 شهرًا
  • CONF-04 — نطاق مؤجَّل كبير سيصل حتمًا

القرار#

نمط أحادي معياري (modular monolith) مبني بإطار Laravel مع حدود داخلية مُفروضة، بالإضافة إلى عدد محدود من الخدمات المرافقة (sidecars) المنشورة بشكل منفصل.

يُفصَل أي مكوّن فقط عندما يمتلك ملف توسّع، أو بيئة تشغيل، أو نطاق فشل مختلفًا فعليًا:

المكوّن المفصول السبب
Document Renderer بيئة تشغيل متصفح بلا واجهة؛ استهلاك مئات الميغابايت لكل عملية عرض سيشوّه حجم الـ API pods. كما أنه المكوّن الوحيد الذي يحتاج حزمة الخطوط والتشكيل العربي.
Malware Scanner قاعدة توقيعات بحجم ~1 غيغابايت؛ معزول عن قصد بوصفه المكوّن الذي يلامس المدخلات غير الموثوقة أولًا
Search Engine ذو حالة (stateful)، بملف ذاكرة وقرص خاص به
Media / TURN (مشروط) متطلّب hostNetwork يجعله مختلفًا معماريًا عن كل شيء آخر في الـ cluster

معالجات الطوابير (workers) والـ scheduler تعمل من نفس الصورة (image) التي يعمل منها الـ API، بنقطة دخول مختلفة — وهي ليست خدمات منفصلة عن قصد.


المبررات#

لماذا لا الخدمات المصغّرة#

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

2. لا مبرر من ناحية بنية الفرق. حدود الخدمات المصغّرة تؤتي ثمارها حين تنعكس على فرق تنشر بشكل مستقل. هنا فريق واحد. حدود الخدمات ستخلق عبء تنسيق عبر حدّ لا وجود له تنظيميًا.

3. المعاملات الموزّعة ستكون خسارة صافية. تدفق الحجز ↔ الدفع ↔ الفيديو يتطلب أصلًا إدارة حالة دقيقة — فهو يمتد عبر قفل موعد، وحجز مبلغ (authorization)، وقبول الطرف المقابل، ودورة حياة جلسة (CONF-02). تقسيمه عبر خدمات يحوّل معاملة قاعدة بيانات واحدة إلى saga، ويضيف تعقيد الإجراءات التعويضية دون فائدة.

4. يتعارض مباشرة مع CON-01 وQAS-OPS-01. الخدمات المصغّرة تضاعف السطح التشغيلي الذي يجب أن يديره فريق صغير — عدد أكبر من الوحدات المنشورة، وأنماط فشل شبكي أكثر، وسطح مراقبة أوسع. CON-15 يرفع أصلًا الأرضية التشغيلية؛ والخدمات المصغّرة فوقه سترفعها إلى ما يتجاوز طاقة الفريق.

5. الخيار محفوظ على أي حال. QAS-MOD-03 يفرض حدودًا مُتحقَّقًا منها في الـ CI، ما يبقي استخراج وحدات المرحلة الثانية رخيصًا (≤ 20 يوم-شخص لكل وحدة). الخيار محفوظ دون دفع ثمنه الآن.

لماذا لا النمط الأحادي التقليدي#

CONF-04 هو العامل الحاسم. تطبيق Laravel تقليدي — حيث تعلّق كل وحدة علاقاتها على User، وتكون المفاتيح الأجنبية عبر الوحدات أمرًا معتادًا، ويتنقّل Eloquent بحرية عبر المجالات — يجعل المرحلة الثانية إعادة كتابة لا امتدادًا. الانضباط المعياري هو قسط التأمين على خارطة طريق التزم بها العمل أمام المستثمرين بالفعل.

الفشل المحدّد الذي يحمي منه هذا القرار#

الأنماط الأحادية المعيارية لا تفشل لأن الحدود رُسمت خطأً. بل تفشل لأن لا شيء منع تآكلها. سهولة استخدام Eloquent هي بالضبط ما يذيب الحدود: $user->bookings->first()->consultant->company يمتد عبر أربع وحدات في سطر واحد، ويُترجم دون خطأ، ويُقرأ بشكل طبيعي — وهو غير قابل للاستخراج.

لذلك فإن القرار لا ينفصل عن آلية فرضه — انظر النتائج.


النتائج#

مطلوب، وليس اختياريًا#

هذا القرار صالح فقط إذا شُحنت العناصر التالية. بدونها يتدهور النمط الأحادي المعياري إلى نمط أحادي تقليدي خلال عام، ويصبح تقدير المرحلة الثانية وهمًا.

المتطلَّب التفصيل
فصل مساحات الأسماء Public/ مقابل Internal/ لكل وحدة arc42 §5.2
Deptrac في الـ CI مع --fail-on-uncovered ⚠️ تغيّرت الحزمة: qossmic/deptrac مهجورة ← استخدم deptrac/deptrac
اختبارات معماريةIdentity وحدها تشير إلى User؛ لا نماذج تعبر الحدود arc42 §5.6
لا مفاتيح أجنبية عبر الوحدات، مفروض باختبار على الـ schema
transactional outbox + واجهة EventBus خاصة، في الأسبوع الأول ~يوم واحد؛ أرخص تأمين متاح على الاستخراج

مفاضلات مقبولة#

التكلفة التخفيف
لا سلامة مرجعية عبر الوحدات domain events للتتابعات؛ ووظيفة reconciliation تُبلّغ عن السجلات اليتيمة كمؤشر، لا كعملية كتابة فاشلة
الإسقاطات المحلية تكرّر بعض البيانات كل وحدة تملك ما تحتاجه بالضبط؛ لا joins موزّعة
قوالب أكثر — DTOs وعقود وأحداث يبقى الاستخراج إعادة هيكلة لا إعادة كتابة
تطوير أولي أبطأ مقصود: R-08 هو الخطر الوحيد الموسوم بأنه غير قابل للعكس فعليًا
نشر التطبيق ككل مقبول عند هذا الحجم من الفريق؛ وهو أيضًا أبسط من إصدارات متعددة الخدمات تحتاج تنسيقًا

أعِد النظر عند#

  • تطوّر قدرة ما بملف توسّع مختلف فعليًا (LMS المرحلة الثانية أو المشتريات هما المرشحان الأرجح)
  • تغيّر بنية الفرق — فرق مستقلة متعددة بدورات إصدار منفصلة
  • فرض حدّ تنظيمي للعزل (مثلًا إذا أجبر R-01 معالجة المدفوعات على نشر مُدقَّق منفصل)

إذا وصل أي من هذه، ينطبق دليل الاستخراج في arc42 §5.8بشرط أن يكون الفرض أعلاه قد استمر. إن لم يكن، فالتقدير بلا معنى.

القائد التقني · أمير هارون مسودة v0.1 · بحث وتصميم فقط