← Back to the gamebug or idea?Terrapin Trail//Code BibleIIhow the game works, archive to van
Reel 11 · 5 min read

The part that isn't in your browser

What a server is, why this version needs one, and where shared things like leaderboards are kept.

Most of the game still runs on your computer, inside your browser. But this version does things your browser can't do alone: it looks up thousands of bands on the Internet Archive, keeps leaderboards that everyone shares, and remembers which hashtag means which tour. For that it needs a computer in the middle that every player can reach: a server.

Concept: "client and server". The client is the program on your device (the game in your browser). A server is a shared computer, always on, that many clients talk to over the internet. Anything that must be shared between people, like a leaderboard everyone sees, needs a server.

One small server program

The whole server is one Python program. When it starts, one function builds every page and every answer the game can ask for:

●runner.py : 172–185trace ↗
172def create_app(data_dir: Path, store=None) -> Flask:
173    """Build the Flask app, reading and writing its caches under ``data_dir``.
174
175    ``data_dir`` is a parameter (not a hardcoded path) so a test can point a
176    throwaway instance at a temp directory seeded with cache fixtures and drive
177    the whole flow offline, exactly as the live app runs against ``DATA_DIR``.
178    ``store`` holds the shared state (leaderboards, tags, run tickets); it
179    defaults to Redis when configured, else files under ``data_dir``.
180    """
181    app = Flask("terrapin_trail", static_folder=None)
182    store = store if store is not None else make_store(data_dir)
183
184    # ------------------------------------------------------------ helpers
185    def band_name_for(collection: str) -> str:
create_app builds the server. Notice it's told where to keep its files and where to keep shared data, instead of deciding for itself. That's what lets a test run a private copy of the whole server.

Concept: "route". A route is one address the server answers, like /play (the game) or /api/bands (the list of bands). Each route is a small function: a request comes in, an answer goes out.

Where shared things are kept

Shared things (scores, tags, share counts) have to be kept somewhere every copy of the server can see. When the game runs on Vercel, that's a database called Redis. In the workspace it's plain files. The rest of the code doesn't care which:

●store.py : 231–235trace ↗
231def make_store(data_dir: Path):
232    url = redis_url_from_env()
233    if url:
234        return RedisStore(url)
235    return FileStore(data_dir / "store")
If a Redis address is configured, use Redis; otherwise use files. Both offer the same operations, so nothing else has to change.

Concept: "interface". An interface is a promise about what something can do ('add a score', 'get the top 50') without saying how. Two different storage systems keep the same promise here, so the rest of the program can use either one.

The ideas to keep
  • The client is the game on your device; the server is the shared computer behind it.
  • The server is one Python program whose routes answer each kind of request.
  • Shared data goes through one interface, kept in Redis on Vercel and in files in the workspace.