DEV Community

Cover image for The Coordination Layer Fallacy: Why Your Multiplayer Architecture Is Probably Overbuilt
turboline-ai
turboline-ai

Posted on

The Coordination Layer Fallacy: Why Your Multiplayer Architecture Is Probably Overbuilt

Most developers building their first turn-based multiplayer game immediately reach for WebSockets. It feels right. Real-time connection, persistent state, bidirectional messaging. The mental model of "multiplayer equals live connection" is so deeply baked in that questioning it feels almost irresponsible.

But that instinct is borrowed from the wrong genre. It belongs to shooters, MOBAs, and anything where a 200ms lag spike is the difference between winning and dying. Chess does not care. Poker does not care. Anything where a player sits, thinks, and eventually makes a deliberate choice does not care.

The actual problem turn-based multiplayer needs to solve is much simpler: coordinate who joins, track whose turn it is, and preserve the order of moves. That is it. No low-latency delivery. No persistent connections. No push notifications. Just a reliable, ordered log of actions and a way for clients to read it.

What WebSockets Actually Buy You

WebSockets reduce the round-trip time between a server event and a client receiving it. In a fast-paced game, that matters enormously. A 50ms difference is perceivable. A 500ms difference is fatal.

In a turn-based game, the human is the bottleneck. A player thinking through their next move introduces latency measured in seconds, sometimes minutes. The technical transport layer is irrelevant at that scale. Whether your client learns about the opponent's move via a WebSocket push or a polling request that fires every two seconds, the player experience is identical.

What WebSockets do add is operational complexity. You need a server that can hold open long-lived connections, usually meaning something like Node.js, Go, or a specialized service. You need to think about connection drops, reconnect logic, and heartbeat mechanisms. You need infrastructure that scales horizontally in a stateful way, which is considerably harder than stateless HTTP.

For a turn-based game, you are paying that cost and getting nothing back.

The Five-Endpoint Architecture

A project called AbraTabia Game Server makes this argument in concrete form. It is a single PHP file backed by a single SQLite database, and it handles everything a turn-based multiplayer game actually needs:

  • Join a public matchmaking queue or create a private game with a join code
  • Poll until a second player joins and the match is confirmed
  • Submit a move
  • Read the full ordered move log
  • Check current match state

That covers the entire lifecycle. Any client that can make a POST request over HTTPS can use it, which means a web app, a native mobile app, a desktop client, or even a command-line tool built for testing.

A simplified version of the move submission endpoint looks roughly like this:

// POST /move
// Body: { match_id, player_token, move_data }

$stmt = $pdo->prepare(
    "INSERT INTO moves (match_id, player_id, move_data, created_at)
     VALUES (?, ?, ?, ?)"
);
$stmt->execute([
    $body['match_id'],
    $player['id'],
    json_encode($body['move_data']),
    time()
]);

echo json_encode(['status' => 'ok', 'move_sequence' => $pdo->lastInsertId()]);
Enter fullscreen mode Exit fullscreen mode

The sequence number from lastInsertId() is what makes the move log trustworthy. Both clients can always reconstruct the authoritative game state by reading moves in order. There is no ambiguity about what happened or when.

Zero Game Rules on the Server

The design choice that makes this architecture genuinely flexible is that the server holds no game logic whatsoever. It does not know what a valid chess move looks like. It does not know the rules of your card game. It accepts whatever move data the client sends and appends it to the log.

Validation, win detection, and legal move checking all live in the client. Both clients run the same game engine locally and apply moves from the log as they arrive. If a client sends an illegal move, the opponent's client simply rejects it when processing the log.

This keeps the server as a pure coordination layer. It does one thing: it lets players find each other, and it preserves the order of what they did. Swapping the game out means changing nothing on the server. You could run chess, Go, a custom card game, and a word puzzle all against the same backend simultaneously.

When This Stops Being Enough

There are real cases where this model breaks down. If you need to prevent cheating at the server level, you need game rules on the server, because clients cannot be trusted. If your game has hidden information that the server needs to arbitrate, like shuffled decks where neither player should see the full order, a dumb relay is not sufficient.

And if your "turn-based" game has a time component where reaction speed matters at all, the polling delay starts to matter.

But for a large category of games, none of those constraints apply. Many turn-based games are fully transparent, fully deterministic, and played by people who are not trying to cheat. For those games, a coordination layer is genuinely all you need.

The Takeaway

The next time you start planning a turn-based multiplayer feature, write down what the server actually needs to do before you pick any technology. If the list is "match players, store moves in order, let clients read them back," you have a polling problem, not a WebSockets problem. A SQLite file and five HTTP endpoints will serve you for longer than you expect, and your future self will appreciate not maintaining a stateful connection server.

Top comments (0)