Entwicklung eines Features



Geschrieben von: dbdtDev 31. Juli, 2011
401 mal aufgerufen

 

In diesem Artikel möchte ich euch anhand des Beispiels Hall of Fame näher bringen, wie ein Feature bei Du-bist-der-Teamchef entwickelt wird und wie das Spiel allgemein aufgebaut ist. Der Artikel besteht vor allem im zweiten Teil hauptsächlich aus technischen Abschnitten und wird dementsprechend eher für Leute interessant sein, die grundlegende Programmierkenntnisse besitzen.

Am 14.07. wurde von dem bekannten Teamchef ChiefFred ein Thread mit dem Titel Offizielle dbdt-Rekorde im Forum Anregungen und Beschwerden eröffnet. Darin schlug er vor, im Spiel eine Liste mit verschiedenen Rekorden einzuführen. Am 26.07. ging das Feature im Klubhaus online.

Ideenfindung
Ideen für neue Features kommen von drei verschiedenen Seiten: den Usern (Forum), von Kamil oder von mir.
Vorschläge im Forum werden, sofern sie sinnvoll sind, notiert. Wenn es sich um ein grosses Feature handelt, welches die Balance des Spiels berührt, muss genau analysiert werden, ob und wenn ja, in welcher Form und mit welchen Parametern das Feature umgesetzt werden kann und wann dies geschehen soll. Sofern möglich und nötig wird alles vor Beginn der Programmierung festgesetzt, auch unter Berücksichtigung der Meinungen der User. Wann ein Feature dann umgesetzt wird hängt von vielen Faktoren ab; es steht jedenfalls noch einiges auf meiner Liste für die Zukunft!
Auch wenn Kamil nicht mehr bei der Firma arbeitet bringt er doch oft neue Ideen. Anstehende Features besprechen wir regelmässig und er gibt auch während der Entwicklung fruchtbare Vorschläge zu den Parametern, eventuellen Erweiterungen und zum Layout und Design. Das Spiel wird immer Kamils "Baby" bleiben; er verbringt viel Zeit im Forum und beobachtet die Entwicklung genau.

Im Fall der Hall of Fame kam die Idee wie so oft von euch. Als ich den Thread sah, entschloss ich sofort, die Idee umzusetzen und bat die User um weitere Vorschläge. Solche Statistiken sind relativ schnell zu programmieren und bieten den Teamchefs Informationen, ohne das Spiel komplizierter oder unübersichtlicher zu machen.

Die Berechnung der Hall of Fame
Wir verwenden bei Teamchef LAMP. Das beudeutet:
- Linux (Betriebssystem)
- Apache (Webserver)
- MySQL (Datenbank)
- PHP (Programmiersprache)

Diese Technologien werden am häufigsten für die Webentwicklung verwendet, und sind alle open source. Für das front end (die Oberfläche, die der User sieht) wird Javascript, HTML und CSS benutzt.

Die Berechnung aller Statistiken für die Hall of Fame kann auf unterschiedliche Arten geschehen. Entweder man berechnet alles wenn die Statistik auf der Seite von einem User aufgerufen wird, oder man berechnet regelmässig alle Statistiken und zeigt dann die in der Datenbank gespeicherten Informationen nur noch an wenn sie angefordert werden. In diesem Fall ist klar dass eine ständige Neuberechnung auf Anfrage nicht in Frage kommt, weil die Berechnung zu lange dauern würde. Es ist den Usern nicht zuzumuten, mehrere Sekunden (bei manchen Statistiken sogar einige Minuten) auf eine Statistik zu warten. Zudem würde es den Server unnötig belasten wenn viele User gleichzeitig auf eine Statistik zugreifen.

Trotz der langwierigen Berechnung ist die Hall of Fame ein sehr einfaches Feature und benötigt, auch aufgrund der sehr speziellen Informationen, nur eine einzige Funktion für die gesamte Berechnung. Diese Funktion wird per Cron-Job einmal täglich, nämlich um 05:30 Uhr, aufgerufen. Viele Berechnungen werden per Cron-Job aufgerufen. Das bedeutet lediglich, dass der Server, genauer gesagt das Linux-Betriebssystem, automatisch einen bestimmten Befehl ausführt, in den meisten Fällen einen Funktionsaufruf. Die aufgerufene Funktion kann dann alles mögliche berechnen, zum Beispiel die Ligaspiele jeden Montag und Donnerstag, abgelaufene Auktionen alle fünf Minuten, aber auch Kleinigkeiten wie das Forum-Widget oder Ähnliches. Bei Du-bist-der-Teamchef gibt es derzeit circa fünfzig verschiedene Funktionenen, die zu unterschiedlichen Zeiten per Cron-Job aufgerufen werden.

Die Berechnung der Hall of Fame hat derzeit genau 1.099 Zeilen. Sehen wir uns einen kleinen Ausschnitt an:



Dies ist die Berechnung der Statistiken, welches Team die meisten ersten Plätze in den einzelnen Ranglisten hat. Zum Testen war es hilfreich, einzelne Statistiken berechnen zu können, anstatt immer alle neu zu berechnen; deshalb gibt es ein Array $calculate, indem steht, was berechnet werden soll. Die Überprüfung darauf steht gleich zu Beginn an Zeile 9.123 (die Zeilennummern werden links im Screenshot angezeigt). Wenn die Statistiken berechnet werden sollen kommen wir zu einer for-Schleife. Alles was darin steht wird in diesem Fall 4mal ausgeführt. In den Zeilen 9.127 bis 9.134 wird festgelegt, in welchem Durchlauf welche Rangliste verwendet wird. Insgesamt werden also hier vier verschiedene Statistiken berechnet. Dann kommt die eigentliche Query, eine Abfrage der Datenbank, in diesem Fall der einzelnen Ranglisten-Tabellen. Es wird die Anzahl an ersten Plätzen in der aktuell verwendeten Rangliste (rangliste_fanbasis, rangliste_skills, rangliste_taktiken oder rangliste_einnahmen) abgefragt und absteigend sortiert nach der Anzahl der ersten Plätze. Das Ergebnis wird auf $nr_teams Zeilen limitiert, wobei $nr_teams am Anfang der Funktion definiert wird, aktuell als 10. Diese Variable wird bei allen Statistiken verwendet; man muss also lediglich einmal die Anzahl an Ergebnissen ändern wenn man mehr oder weniger als 10 Teams pro Statistik berechnen möchte. Die while-Schleife weist jede einzelne Zeile des Ergebnisses der Variable $tmp zu. Darin steht also (in diesem Fall 10 mal) die Anzahl an ersten Plätzen. Es werden noch Bezeichnung der Statistik und andere Dinge zugewiesen, und das Array $tmp wird dann in das Array $arr gepusht, also hinten angehängt. In $arr stehen nacheinander alle berechneten Statistiken. Am Ende der Funkion wird jeder Eintrag in $arr in die Datenbanktabelle hall_of_fame geschrieben, nachdem die Tabelle zuvor geleert wird.

Zu Beginn der Programmierung wurde davon ausgegangen, pro Statistik nur das jeweils beste Team zu speichern und dann alle Statistiken untereinander anzuzeigen. Sollten in Zukunft noch mehr als 10 Teams pro Statistik berechnet werden, wird die Berechnung so umgeschrieben dass es keine Zwischenspeicherung in $arr mehr gibt und die Einträge direkt mit einer einzelnen Query "INSERT INTO hall_of_fame SELECT ..." in die Tabelle eingefügt werden. Zusätzlich wäre es dann eine Platzverschwendung, zu jedem Eintrag die Bezeichnung "Team mit ..." in die Tabelle zu speichern. Weil die Tabelle derzeit sehr klein ist stellt das kein Problem dar. Die Lösung hierzu wäre, die zu berechnenden Statistiken inklusive Bezeichnung und einem Flag, ob die jeweilige Statistik berechnet werden soll, in einer eigenen Tabelle zu speichern.

Die Berechnung aller 51 Statistiken dauert derzeit ungefähr fünf Minuten.

Das Holen der Daten
Nachdem die Daten nun täglich berechnet werden, beginnt man mit dem nächsten Schritt: den Einbau in die Seite.
Teamchef benutzt einen sogenannten MVC-Framework. Das bedeutet grob, dass die Logik (Models) von der Anzeige der Daten (Views) getrennt ist und der Datenaustausch von einem Controller durchgeführt wird. Gesteuert wird das Ganze von einer globalen Funktion. Der Framework wurde von Kamil für Teamchef entwickelt und seither vor allem um die automatische Übersetzung der Texte in allen Views erweitert. Wenn man sich die URLs bei Teamchef ansieht kann man folgendes herauslesen: www.du-bist-der-teamchef.at/?q=klubhaus/hall_of_fame bedeutet: rufe im Controller "klubhaus" die Funktion "hall_of_fame" auf. Die Funktion holt sich die gewünschten Daten, in diesem Fall die Statistiken der Hall of Fame, indem sie eine Funktion im Model "klubhaus" aufruft, wo die Daten aus der Datenbank gelesen werden. Die zurückgegebenen Daten werden dann der View übergeben, die sie für den User anzeigt.

So sieht die Funktion im Controller aus:



Als erstes wird die Liste aller Statistiken (= welche Statistiken werden in der DropDown-Box angezeigt und können vom User ausgewählt werden) vom Model angefordert (Zeile 471).
In den Zeilen 473 bis 484 wird geregelt, welche Statistik angezeigt werden soll. Entweder der User hat eine Statistik ausgewählt oder es wird die erste Statistik angezeigt. Wenn der User etwas ausgewählt hat, entweder über die DropDown-Box oder über die grünen Pfeile, wird die Auswahl per POST übergeben, in eine Integer-Variable verwandelt (zur Verhinderung von SQL-Injections) und geprüft ob die ausgewählte Statistik tatsächlich existiert. In den Zeilen 486 bis 490 werden die Pfeile, die der User zur Navigation durch die Statistiken verwenden kann, festgelegt. Danach werden die entsprechenden Daten vom Model angefordert. Der Funktion wird die gewünschte Statistik als Variable übergeben. Dann liefert der Controller die Daten an die View.

Die Funktionen im Model sehen so aus:



"hall_of_fame_list" liefert die Liste der Statistiken, zum Auswahl in der DropDown-Box. "hall_of_fame" liefert die Liste der ausgewählten Statistik zurück. Mit der Query ab Zeile 3.220 werden die Daten geholt. Für jeden einzelnen Eintrag wird, falls ein Team zum Eintrag gehört, Teamname, Username und userid aus der Tabelle team geholt (Zeilen 3.231 - 3.247). Ist wie bei einigen Statistiken ein Spieler eingetragen, so wird dessen Vor- und Nachname aus der Tabelle spieler geholt (Zeilen 3.249 - 3.263). Das Ergebnis wird in ein Array $arr gepusht und zurückgegeben.

Damit stehen alle Daten zur Verfügung und müssen nur noch korrekt angezeigt werden.

Anzeige
Wir verwenden Grundsätzlich keine tables zur Formatierung der Anzeige, sondern einzelne Elemente (div's). Die Elemente bekommen per CSS Eigenschaften zugewiesen. Die Kommunikation zwischen HTML und dem Controller passiert mittels Javascript.

Es gibt für die Hall of Fame zwei Views. Die eine View ("hall_of_fame.php") inkludiert die andere ("hall_of_fame_content.php"). Wenn der User eine Statistik auswählt, wird nur "hall_of_fame_content.php" per Javascript asynchron aktualisiert.

View hall_of_fame.php:


Hier wird nur das Grundgerüst gebaut, welches auf allen Seiten praktisch gleich aussieht. Oben wird das Tool für die Übersetzer eingebunden, dann folgt die Headline und die Beschreibung. Die "!*" und "*!" zu Beginn und am Ende der Beschreibung zeigen dem Framework an dass es für den Text dazwischen eventuell eine Übersetzung ins Englische gibt. Findet er eine solche, wird der Text für User, die die Sprache auf Englisch gestellt haben, mit dem englischen Text ersetzt. Ansonsten werden einfach die "!*" und "*!" entfernt. Nach einer weiteren Headline wird der Content ("hall_of_fame_content.php") eingebunden, der die eigentliche Anzeige der Daten vornimmt. Nanach folgt noch der Link nach oben und die Werbung. Zum Schluss steht noch eine Javascriptanweisung, die den korrekten Link in der Navigation links aktiviert.

View hall_of_fame_content.php:


Von Zeile 1 bis 32 wird die Navigation gezeigt, mit dem Pfeil nach links, dem DropDown und dem Pfeil nach rechts. Wenn der User einen Pfeil klickt oder einen Eintrag in der DropDown wählt, wird eine Javascriptfunktion aufgerufen (siehe unterhalb). In $hof_navi stehen die Daten, die "hall_of_fame_list" im Model an den Controller zurückgeliefert hat, und die uns jetzt in der View zur Verfügung stehen.
$hof beinhaltet die Liste der Einträge aus "hall_of_fame" im Model. Solange es Einträge gibt (Zeile 35), wird eine neue Box angezeigt, worin Wappen, Platzierung, Teamname und so weiter stehen. Am Ende der Box wird noch die "Stern-Grafik" für die ersten drei Teams angezeigt.

Javascript:


Für den Wechsel der Statistiken wird nur eine kurze Javascriptfunktion benötigt. Sie ruft die Funktion "hall_of_fame" im Controller "klubhaus" auf und aktualisiert die View "hall_of_fame_content.php" mit den zurückgelieferten Daten. Übergeben wird dem Controller die vom User gewünschte Statistik.
Wir verwenden bei Teamchef den Javascript-Framework "Prototype", der unter anderem die Funktionalitäten zum asynchronen Aktualisieren (AJAX) zur Verfügung stellt.

CSS:


Abschliessend noch das etwa hundert Zeilen lange CSS für das Feature, welches das Layout und Design festlegt. Für ein so einfaches Feature wird nicht extra ein Grafiker beauftragt. In diesem Fall habe ich für die Sternchen der ersten drei Teams eine Grafik benutzt und ausgeschnitten, die für die noch unveröffentlichten "Achievements" erstellt wurden. Die Sternchen werden einfach rechts neben die Boxen gesetzt und mittels negativem margin-left nach links in die Box verschoben (Zeile 953).

Nach ausreichendem Testen auf allen Browsern und Prüfen der Daten auf Korrektheit ist das Feature nun fertig und kann veröffentlicht werden. Hoffentlich habe ich euch einen kleinen Einblick in das Gefüge Du-bist-der-Teamchef geben können. Mit den angesprochenen Technologien und den Hinweisen, wie diese verwendet werden, könnt ihr jetzt beginnen, eure eigenen Online-Manager zu programmieren! :)

Liebe Grüsse,
Thomas


Warning: include_once(comment.php) [function.include-once]: failed to open stream: No such file or directory in /users/tcw-archiv/www/artikel/ausgabe64/entwicklung.php on line 186

Warning: include_once() [function.include]: Failed opening 'comment.php' for inclusion (include_path='.') in /users/tcw-archiv/www/artikel/ausgabe64/entwicklung.php on line 186