Composing Behavior: What Games Teach Us About Software Architecture
In the game Iram, players collect Orbital Shards — fragments of behavior that snap together to create new abilities. Equip Defend and Mend together, and your shields heal 1.5x faster. Equip Disrupt and Fabricate, and your traps deal area damage.
This isn't just a game mechanic. It's a software architecture pattern that solves the microservices vs monolith debate.
The Composition Problem
Software architecture is stuck between two bad options:
Monolith: Everything in one codebase. Easy to build, impossible to scale. Every change risks breaking something unrelated.
Microservices: Everything in its own service. Easy to scale, impossible to coordinate. Every feature requires orchestrating 5 services, 3 message queues, and a prayer.
Both approaches treat behavior as a location problem: where does the code live?
The real question is: how does behavior compose?
Lessons from Game Design
In Iram, a dungeon-crawling action RPG built on Almadar, the player's character is defined by which Orbitals they equip:
| Orbital | Behavior |
|---|---|
| Defend | Absorb damage, generate shields |
| Mend | Heal over time, cure status effects |
| Disrupt | Interrupt enemies, apply debuffs |
| Fabricate | Create traps, build turrets |
| Pathfind | Reveal map, detect hidden enemies |
| Transmute | Convert resources, upgrade equipment |
| Command | Buff allies, coordinate group actions |
| Archive | Record enemy patterns, reveal weaknesses |
Each Orbital is a self-contained state machine. Defend doesn't know about Mend. Pathfind doesn't know about Fabricate.
But when you equip them together, emergent behavior appears.
Resonance: Composition Creates Emergence
When compatible Orbitals are equipped simultaneously, they create Resonance — synergy effects that neither Orbital defines alone:
{
"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 }
}
]
}
The key insight: neither Orbital changes. Defend doesn't have code for "work better with Mend." The resonance is a property of the combination, not the individuals.
This is exactly how software composition should work.
The Pattern: Orbital Composition
In Almadar, Orbitals communicate through events. Each Orbital declares what it emits and what it listens to:
{
"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]]]
]
}
]
}
}]
}
Defend emits SHIELD_DEPLETED. Mend listens for it. When the shield breaks, healing kicks in automatically. Neither Orbital references the other by name. They communicate through the event bus.
This is:
- Loosely coupled — Defend works without Mend
- Composable — Add Mend and new behavior emerges
- Verifiable — The compiler checks that every
emithas alisten - Discoverable — Read the event declarations to understand interactions
Software Architecture Implications
This pattern translates directly to business software:
