Skip to main content

Back to Projects

Project Detail

Crazy - Multiplayer Card Game

A real-time, full-stack multiplayer card game where players create/join rooms, receive dealt hands, play cards according to configurable rules, and the server enforces rule effects and turn progression. Provides low-latency synchronized ga...

developerDuration: 3 monthsType: platform

Key Achievement Metrics

avg_websocket_rtt_ms

50

avg_room_state_kb

5

estimated_rooms_per_instance

200

Architecture View

Processing state: architecture signal graph is initializing...

Decision Log

Use Redis as canonical game state store with TTL

Low-latency reads/writes, easy serialization of full room state, native TTL for cleanup.

Trade-off: No long-term history; Redis outage stalls game; requires careful serialization and atomic updates to avoid race conditions.

Event-driven single-process Socket.IO server

Simpler development, direct in-process calls from handlers to service layer, lower operational complexity at small scale.

Trade-off: Scaling requires sticky sessions or a Socket.IO adapter (Redis adapter) and additional coordination; single-process increases blast radius for faults.

Separate Rule Engine (RuleService) from transport

Improves testability and keeps real-time handlers focused on event flow.

Trade-off: Additional indirection; needs thorough unit tests to ensure correctness.

Architecture Narrative

Challenge

Provides low-latency synchronized gameplay and session persistence for short-lived multiplayer card sessions with reconnection support.

Solution

Event-driven monolith (single Node.js process hosting an Express HTTP server + Socket.IO real-time layer) with an in-memory persistence tier (Redis) used as the canonical game state store.

Result

Key measurable signals: avg_websocket_rtt_ms (50), avg_room_state_kb (5), estimated_rooms_per_instance (200).

Trade-off Matrix

DimensionSelected OptionImpactCompromise
Real-time transportSocket.IO (WebSocket + polling fallback)Reliable reconnects, ease of use, acknowledgementsAdditional abstraction and potential overhead vs raw WebSocket
State persistenceRedis in-memory keys with TTLLow-latency reads/writes, built-in expiry for stale sessionsNo long-term audit/history and requires Redis availability

What I'd Do Differently

+

Add robust observability: Prometheus metrics, structured logs, and request/operation tracing (error rates, message rates, handler latency).

+

Harden concurrency around room updates: add Redis WATCH/MULTI or optimistic versioning to prevent lost writes and race conditions.

Estifanos Kebede

System Engineer & Full Stack Developer

Social

SYSTEM: ESTIFANOS.PORTFOLIO

STATUS: OPERATIONAL

LAST_UPDATED: 2026

© 2026 Estifanos Kebede. Built with precision and intent.