تركيب السلوك: ما تعلمنا إياه الألعاب عن هندسة البرمجيات
يجمع اللاعبون في لعبة إرم شظايا مدارية — أجزاء من السلوك تتراكب معًا لخلق قدرات جديدة. جهّز الدفاع والترميم معًا، وتتجدد دروعك أسرع بمقدار 1.5 ضعف. جهّز التعطيل والتصنيع، وتُلحق فخاخك ضررًا في منطقة.
هذه ليست مجرد آلية لعب. إنها pattern (نمط معماري) في هندسة البرمجيات يحل الجدل بين الـ microservices (خدمات مصغرة مستقلة) والـ monolith (تطبيق متجانس في قاعدة كود واحدة).
مشكلة التركيب
تعلق هندسة البرمجيات بين خيارين سيئين:
الـ monolith: كل شيء في قاعدة كود واحدة. سهل البناء، مستحيل التوسعة. يخاطر كل تغيير بكسر شيء غير متعلق.
الـ microservices: كل شيء في خدمته الخاصة. سهل التوسعة، مستحيل التنسيق. تتطلب كل ميزة تنظيم 5 خدمات و3 طوابير رسائل ودعاء.
يعامل كلا النهجين السلوك كمشكلة موقع: أين يعيش الكود؟
السؤال الحقيقي هو: كيف يتركب السلوك؟
دروس من تصميم الألعاب
تُحدَّد شخصية اللاعب في إرم، لعبة أكشن RPG للزنزانات مبنية على Almadar، من خلال أي الـ orbitals (الوحدات المدارية التي تُركّب السلوك) يُجهّزها:
| الـ orbital | السلوك |
|---|---|
| الدفاع | امتصاص الضرر، توليد الدروع |
| الترميم | الشفاء بمرور الوقت، إزالة effects الحالة |
| التعطيل | مقاطعة الأعداء، تطبيق الإضعافات |
| التصنيع | إنشاء الفخاخ، بناء الأبراج |
| الاستكشاف | كشف الخريطة، اكتشاف الأعداء المخفيين |
| التحويل | تحويل الموارد، ترقية المعدات |
| القيادة | تقوية الحلفاء، تنسيق الإجراءات الجماعية |
| الأرشفة | تسجيل patterns الأعداء، كشف نقاط الضعف |
كل orbital هو state machine (آلة حالة تدير السلوك عبر حالات محددة) مكتفية ذاتيًا. لا يعرف الدفاع عن الترميم. ولا يعرف الاستكشاف عن التصنيع.
لكن عندما تُج هّزها معًا، يظهر emergent behavior (سلوك ناشئ من تركيب الأجزاء).
الـ resonance: التركيب يخلق الظهور
تخلق الـ orbitals المتوافقة resonance (رنين — تأثيرات تآزرية بين الـ orbitals) عندما تُجهَّز في وقت واحد — effects لا يُعرّفها أي orbital بمفرده:
{
"resonance": [
{
"requires": ["Defend", "Mend"],
"effect": "Shield regeneration rate increased by 1.5x",
"multiplier": { "shieldRegen": 1.5 }
},
{
"requires": ["Disrupt", "Fabricate"],
"effect": "Traps apply disruption debuffs",
"multiplier": { "trapDamage": 1.3 }
},
{
"requires": ["Archive", "Command"],
"effect": "Allies receive enemy weakness intel",
"multiplier": { "allyDamage": 1.2 }
}
]
}
الرؤية الجوهرية: لا يتغير أي orbital. لا يملك الدفاع كودًا لـ "اعمل بشكل أفضل مع الترميم." يعتبر الـ resonance خاصية التركيبة، وليس الأفراد.
هذا بالضبط كيف يجب أن يعمل تركيب البرمجيات.
الـ pattern: تركيب الـ orbital
تتواصل الـ orbitals في Almadar عبر الأحداث. يُصرّح كل orbital بما يُطلقه وما يستمع إليه:
{
"name": "DefendOrbital",
"traits": [{
"name": "ShieldTrait",
"emits": ["SHIELD_ACTIVATED", "SHIELD_DEPLETED"],
"stateMachine": {
"states": [
{ "name": "Ready", "isInitial": true },
{ "name": "Active" },
{ "name": "Cooldown" }
],
"transitions": [
{
"from": "Ready",
"to": "Active",
"event": "ACTIVATE_SHIELD",
"effects": [
["set", "@entity.shieldHp", "@entity.maxShieldHp"],
["emit", "SHIELD_ACTIVATED"]
]
},
{
"from": "Active",
"to": "Cooldown",
"event": "SHIELD_BROKEN",
"effects": [
["set", "@entity.shieldHp", 0],
["emit", "SHIELD_DEPLETED"]
]
}
]
}
}]
}
{
"name": "MendOrbital",
"traits": [{
"name": "HealTrait",
"listens": [
{ "event": "SHIELD_DEPLETED", "triggers": "EMERGENCY_HEAL" }
],
"stateMachine": {
"transitions": [
{
"from": "Idle",
"to": "Healing",
"event": "EMERGENCY_HEAL",
"effects": [
["set", "@entity.hp", ["+", "@entity.hp", ["*", "@entity.maxHp", 0.2]]]
]
}
]
}
}]
}
يُطلق الدفاع SHIELD_DEPLETED. ويستمع الترميم إليه. يبدأ الشفاء تلقائيًا عندما يُكسر الدرع. لا يشير أي orbital إلى الآخر بالاسم. يتواصلان عبر الـ event bus (ناقل الأحداث الذي يربط الـ orbitals ببعضها).
يعني هذا:
- ترابط فضفاض — الدفاع يعمل بدون الترميم
- قابلية التركيب — أضف الترميم ويظهر سلوك جديد
- قابلية الـ validation (التحقق من صحة التوصيل) — الـ compiler (المُصرِّف) يتحقق أن كل
emitلهlisten - قابلية الاكتشاف — اقرأ تصريحات الأحداث لفهم التفاعلات
الآثار على هندسة البرمجيات
يترجم هذا الـ pattern مباشرة إلى برمجيات الأعمال:
التجارة الإلكترونية: معالجة الطلبات
OrderOrbital PaymentOrbital InventoryOrbital
│ │ │
├─ emits: ├─ listens: ├─ listens:
│ ORDER_PLACED │ ORDER_PLACED │ PAYMENT_CONFIRMED
│ │ → PROCESS_PAYMENT │ → RESERVE_STOCK
│ │ │
│ ├─ emits: ├─ emits:
│ │ PAYMENT_CONFIRMED │ STOCK_RESERVED
│ │ PAYMENT_FAILED │ OUT_OF_STOCK
ثلاثة orbitals. كل منها مكتفٍ ذاتيًا. التركيب عبر الأحداث. يتحقق الـ compiler من اكتمال رسم الأحداث — لا تمر رسالة بدون معالجة.
قارن هذا بنسخة الـ microservices:
- ثلاث خدمات، ثلاث عمليات نشر، ثلاث قواعد بيانات
- طابور رسائل (Kafka/RabbitMQ) لربطها
- طوابير الرسائل الميتة للرسائل الفاشلة
- patterns الملحمة للمعاملات الموزعة
- مراقبة وتنبيهات لكل خدمة
تُصرَّف نسخة Almadar إلى نشر واحد بنفس البنية المدفوعة بالأحداث، لكن بدون أعباء البنية التحتية.
التعاون الجماعي: التطوير المتوازي
يمكن للفرق العمل بالتوازي لأن الـ orbitals تتواصل فقط عبر الأحداث:
- يبني الفريق أ orbital الطلب
- يبني الفريق ب orbital الدفع
- يبني الفريق ج orbital المخزون
يتفقون على عقود الأحداث:
{
"event": "ORDER_PLACED",
"payload": {
"orderId": "string",
"items": "array",
"total": "number"
}
}
ثم يبنون بشكل مستقل. يتحقق الـ compiler من تطابق العقود عندما تُركَّب الـ orbitals.
الـ standard library: سلوكيات جاهزة
يتضمن Almadar 11 سلوكًا في الـ standard library (المكتبة القياسية التي توفر سلوكيات جاهزة) تُدمج في أي مشروع:
| السلوك | ماذا يفعل |
|---|---|
std/Loading | حالات التحميل مع معالجة النجاح/الخطأ |
std/Fetch | جلب بيانات غير متزامن مع إعادة المحاولة |
std/Submit | إرسال النماذج مع الـ validation |
std/Retry | منطق إعادة المحاولة بتراجع أسي |
std/Poll | patterns الاستطلاع الطويل |
std/Pagination | ترقيم الصفحات بمؤشر/إزاحة |
std/Search | بحث نص كامل مع تصفية |
std/Sort | فرز متعدد المفاتيح |
std/GameCore | حلقة اللعبة الأساسية (تحديث، عرض) |
std/UnitBehavior | سلوكيات الوحدات الذكية (دورية، حراسة، هروب) |
std/Inventory | إدارة مخزون اللعبة |
استوردها في أي orbital:
{
"uses": [{ "from": "std/Pagination", "as": "Paginate" }],
"traits": [
{ "ref": "Paginate.traits.PaginationTrait" },
{ "ref": "TaskInteraction" }
]
}
تملك قائمة المهام الخاصة بك الآن ترقيم صفحات. بدون كتابة كود. مجرد تركيب.
لماذا تفهم الألعاب هذا بشكل صحيح
فهمت الألعاب التركيب منذ الأزل. شخصية RPG هي تركيب من:
- الفئة (محارب، ساحر، متسلل)
- المعدات (سيف، درع، عصا)
- المهارات (كرة نار، شفاء، تسلل)
- التقويات/الإضعافات (مسموم، مبارك، مُسرَّع)
يعتبر كل منها سلوكًا مكتفيًا ذاتيًا. ويخلقون معًا شخصية فريدة ذات قدرات ناشئة.
يجب أن تعمل البرمجيات التجارية بنفس الطريقة:
- تعتبر الفاتورة تركيبًا من عمليات CRUD + الموافقة + توليد PDF + إشعار بالبريد الإلكتروني
- يعتبر المستخدم تركيبًا من المصادقة + الملف الشخصي + التفضيلات + سجل النشاط
- تعتبر لوحة المعلومات تركيبًا من المخططات + الفلاتر + التحديثات الفورية + التصدير
كل سلوك هو orbital. التركيب عبر الأحداث. يضمن الـ compiler صحة التوصيل.
الخلاصة
يسأل الجدل بين الـ microservices والـ monolith السؤال الخاطئ. لا يكمن السؤال في أين يعيش السلوك. بل كيف يتركب السلوك.
تمنحك الـ orbitals:
- وحدات مكتفية ذاتيًا (كالـ microservices) — كل orbital يملك الـ state machine الخاصة به
- تركيب سهل (كالـ monolith) — استورد، ركِّب، صرِّف
- توصيل مُتحقق منه (لا يوفره أي منهما) — الـ compiler يتحقق من كل اتصال حدث
- emergent behavior (كالألعاب) — effects من الـ resonance بين التركيبات المتوافقة
لا تبدأ بـ "كم عدد الخدمات؟" في المرة القادمة التي تصمم فيها نظامًا. بل ابدأ بـ "ما السلوكيات التي أحتاجها، وكيف تتركب؟"
تعرف على المزيد حول الأحداث عبر الـ orbitals والـ standard library.
