Da das ein altes Posting von mir aus der Zeit, wo ich gerade mit Django anfing, ist, hier ein Update nach über zwei Jahren. Vorausschicken muss ich noch, dass ich keine echte praktische Erfahrung mit Browserspielen habe, nur eine Meinung als Software-Entwickler. Ich kenne noch nicht einmal viele davon.
Ich würde sagen, ein klassisches Spiel, welches auf einer Seite meist in Tabellenform einen Spielstand darstellt und bei dem dann Befehle über ein Formular geschickt werden, auf dass das Spiel dann seinen internen Stand, der meist in einer relationalen Datenbank repräsentiert ist, aktualisiert um darauf hin wieder eine neue Seite mit Statusinformationen anzuzeigen, lässt sich mit Django gut umsetzen.
Die Probleme, die ich in meinem Posting recht unstrukturiert zu thematisieren versuchte sind eher Randbereiche.
Ich suchte nach einem Weg, möglichst einfach ein PHP-Programm zu portieren, welches HTML-Templates und Anzeigelogik (nicht unbedingt Spiellogik) vermischte. Ich störte mich daran, dass es mit Rails, dessen Template-System ERB ja auch das Mischen von Text und Code erlaubt, viel einfacher sein würde, die Templates zu portieren. Baut man das ganze aber von Anfang an speziell für Django auf, kommt man erst gar nicht in diese Situation und hat diese Probleme.
Dennoch: Jinja bleibt eine interessante Alternative und Bottle, was ich später noch erwähnen werde, mit seinem super einfachen Template-System ebenfalls.
Gerne wird erzählt, dass der ORM, als der Teil von Django, der einem hilft, die Datensätze wie Objekte aufzufassen, nicht mächtig genug ist. Mit den Erweiterungen von Django 1.1 und 1.2 ist das glaube ich aber immer weniger ein Problem. SQLalchemy erscheint mir da deutlich komplizierter und man verliert das Admin-UI von Django, was mir auch bei einem Browserspiel für Tests und zur einfachen Korrektur von Fehlern sinnvoll erscheint.
Dennoch: Ich würde inzwischen wohl überhaupt keine relationale DB mehr benutzen, was natürlich den Admin-UI-Vorteil von Django relativiert, wieder Bottle ins Spiel bringt, aber dafür die SQLalchemy-Diskussion erübrigt.
Wie gesagt, ich kenne keine (modernen) Browserspiele, daher ist mein Stand immer noch, dass die Versuche in PHP (oder wie erwähnt in Pike und Coldfusion) echt katastrophal sind und tausende von Zeilen verschwendet werden, um mit unpassenden Technologien wie relationalen Datenbanken und maskenorientierten Batch-Prozessen wie vor 40 Jahren zu kämpfen.
In der Diskussion wurde ZODB/Durus und CouchDB erwähnt. Inzwischen kenne ich die drei Systeme soweit, dass ich mir eine Meinung zutraue: Alles nicht optimal. ZODB und Durus versuchen eine OODB zu sein, die eigentlich schon zu dem Zeitpunkt, als sie gebaut worden, tot hätten sein sollen, weil der Markt schon Mitte der 90er (leider) entschieden hatte, dass relationale DBs gegen OODBs gewonnen haben. Dabei war Gemstore richtig schick.
Inzwischen gibt es jedoch eine neue Generation von Entwicklern, die von der Entscheidung nichts mehr wusste und es ist die NOSQL-Bewegung entstanden und auf einmal sprießen überall Key-Value-Stores und andere einfache Datenspeicher aus dem Boden, die nicht im Hinblick auf ACID und kaufmännische Prozesse entworfen wurden, sondern im Hinblick auf Einfachheit und Skalierbarkeit.
Sollte ich in näherer Zukunft ein Browserspiel schreiben (was leider unwahrscheinlich ist) wäre mein Kandidat aus der Menge der NOSQL-DB-Anwärter MongoDB. Ich glaube, diese DB würde sich ausgesprochen gut für ein Postspiel (eine Spielform noch älter als Browserspiele, die ich aber besser kenne) eigenen und daher bestimmt auch für ihre moderne Fortsetzung.
Ein anderes Problem, über das ich geklagt hatte, waren Transaktionen. In einer relationalen DB könnte man das Problem bei sehr sorgfältiger Programmierung und einem ausreichend hohen Isolation Level in den Griff bekommen, aber es macht viele Dinge (jede Form von Ressourcen-Übertragung, vergleiche das klassische Account-Problem) schwer. Sie einfach zu ignorieren und ab und zu Fehler im Programm (die Spieler möglicherweise ausnutzen könnten) zu riskieren, ist aber IMHO auch keine Lösung.
Erschwerend kommt hinzu, dass NOSQL-Datenbanken ACID und Transaktionen in der Regel der Skalierbarkeit opfern (das CAP-Theorem sagt ja auch, man kann nicht alles haben) sodass die Wahl von MonoDB dieses Problem nicht nur nicht lösen würde, sondern noch verstärkt.
Ich habe mal versucht, in Redis (einem anderen NOSQL-Anwärter) durch geschickte Wahl der Reihenfolge der Befehle und eigenen Locks mit Timeouts Transaktionen zu bauen, doch das alles macht Fehler nur unwahrscheinlich, nicht unmöglich. Egal ob das für die Praxis reicht, mich macht so etwas unglücklich.
Daher würde ich einen der beiden radikalen Ansätze verfolgen:
Das Spiel wird von einem permanent laufenden Server ausgeführt. Nennen wir diesen "Application Server". Er hält den Spielstand. Er nimmt Befehle entgegen, die den Zustand ändern und Befehle, die nach dem (subjektiven) Zustand fragen. Er schreibt selbstständig das Spiel weiter. Dies ist fundamental anders als das Spiel in die Request-Response-Logik eines Webservers zu pressen, wo der Spielstand nur während eines Requests kurzfristig existiert und ansonsten in einer DB repräsentiert wird. Bis zu einer gewissen Anzahl von Spielern kann ich alle Befehle einfach serialisieren und habe keinerlei Transaktionsprobleme. Den Spielstand selbst könnte ich, wenn es mir zu gefährlich ist, ihn nur im Hauptspeicher zu halten, regelmäßig als Snapshot ablegen (so macht Redis es) oder einen Redo-Log (vergleiche die Idee von Prevayler) pflegen oder aber einen KV-Store (wie Redis oder MongoDB) benutzen. Herje, man könnte sogar eine OODB benutzen, denn genau für so einen Zweck wurde sie mal erdacht.
Weil der Server ja auch IO machen muss und dieses nicht parallel laufen darf (ansonsten hätte ich ja wieder Probleme mit Transaktionen), wäre vielleicht Tornado eine interessante Basis für den Server. Sobald aber einzelne Befehle so lang werden, dass ich sie nicht auf einmal ausführen kann, ohne dass das System stockt, müsste ich sie aufteilen und begebe mich in die Schlangengrube die da heißt CPS-Programmierung. Wer sich mal komplexere nodejs-Anwendungen anschaut, weiß, was ich meine. Man bräuchte jetzt Coroutinen auf Generatorbasis. Das total unbekannte Webrahmenwerk Diesel bautet so etwas zu bieten, ob das in der Praxis funktioniert, weiß ich jedoch nicht.
Der andere Ansatz wäre daher, Parallelität nicht um jeden Preis zu verhindern, sondern als Normalfall zu akzeptieren. Vielleicht gibt es eine brauchbare Actor-Implementierung für Python. Oder eine Implementierung von STM a la Clojure. In diese Richtung könnte man forschen. Beides erlaubt es, mit Datenstrukturen konfliktfrei in einer nebenläufigen Welt umzugehen, ohne dass es zu Deadlocks oder inkonsistenten Zuständen kommt und dennoch ist es für den Entwickler verständlich. Leider ist CPython äußerst ineffizient, wenn es mehrere parallele Threads ausführen soll und für diesen Ansatz wäre ich versucht, eine andere Programmiersprache zu wählen. Erlang (Actor-Modell) finde ich arg archaisch, wäre aber ein guter Kandidat. Ob Reia besser ist? Ich habe schon lange nicht mehr Io angeschaut, das kennt aber auch Actors. Scala oder Clojure selbst wären weitere Kandidaten. Und ich hatte neulich gesehen, dass jemand die STM-Implementierung von Clojure für JRuby portiert hat. Theoretisch könnte man das natürlich auch für Python machen, aber dann wären da wieder die Implementationsprobleme von CPython.
Bleibt man doch bei einem recht klassischen Ansatz und vergisst die ganzen "wie wäre es perfekt"-Überlegungen, bleibt noch eines zu sagen. Nach jedem Klick die Webseite neu zu laden scheint mir gerade bei einem Spiel schon lange nicht mehr der richtige Ansatz zu sein. Ich würde eher sagen, dass Spiel selbst läuft (mit genug JavaScript, welches man entweder selbst schreibt oder da wieder eine Bandbreite an Alternativen hat, die ein weiteres Posting dieser Länge wert wären) im Browser und kommuniziert mit dem Server per AJAX. Dies relativiert die Notwendigkeit für eine gute Template-Sprache sondern der Webserver muss nur noch in der Lage sein, auf bestimmte URLs mit JSON-formatierten Daten zu antworten. Hierfür brauche ich eigentlich Django nicht. Bottle scheint mir da eine einfachere Lösung zu sein. Okay, man hat das Admin-UI nicht mehr, aber wählt man da MongoDB als Backend, muss man sich eh etwas eigenes bauen. Für Redis gibt es übrigens ein Admin-UI basierend auf Bottle (nur so nebenbei).
Oder man sagt, weil man für die Client-Seite eh JavaScript beherrschen muss, kann man den Server ja auch mit JavaScript schreiben und dann empfehle ich Node.js. Siehe z.B.
http://howtonode.org/express-mongodb. Definitiv nicht die am einfachsten zu programmierende Plattform (der notwendige CPS-Stil kann schnell entarten), aber dafür super von der Performance und extrem leichtgewichtig.
Viel Spaß bei deinem Browserspiel, das garantiert auch ohne all die komplexen Überlegungen, die ich hier angestellt habe, funktionieren wird.
Stefan