RestfulSnake

Vor wenigen Monaten hatte ich eine handvoll Bewerbungsgespräche. Von “Programmieraufgaben”, die durch das Erkennen der Fibonacci-Sequenz gelöst wurden bis zu “Wie viele Grashalme gibt es in deiner Heimatstadt?” war alles dabei. Unter anderem auch “Wir glauben, dass du noch nie Java angefasst hast, deshalb sollst du ein Programm in Java schreiben, über das wir nächste Woche reden können!”

Also bin ich jetzt Java-Experte. Und das bedeutet, dass es Zeit ist für eine weitere Snake-Version [1, 2, 3, 4, 5].

Um besonders professionell zu wirken, habe ich mich für eine Client-Server-Architektur entschieden. Steuerkommandos werden per http post zum Server geschickt und in der Antwort steht die neue Position der Schlange. Das Backend nutzt Spring Boot und läuft auf einem Tomcat Server. Das Frontend besteht hauptsächlich aus dem Visualisierungs-Code von jsnake, aber echte Nerds werden es natürlich bevorzugen per curl zu spielen.

Normalerweise würde man es natürlich mittels Kubernetes und Docker auf AWS laufen lassen, aber stattdessen habe ich mich dafür entschieden Heroku zu nutzen, um ein kleines Unternehmen zu unterstützen. Auf multijsnake.herokuapp.com kann man also eine Partie spielen. Und die Quellen liegen wie immer auf GitHub

Überraschenderweise funktioniert das tatsächlich erstaunlich gut — solange die Latenz unter ~150 ms bleibt. Und dieses Design schreit geradezu nach einen Multiplayer-Modus…

Platzhalterbilder

Große Bilder können die Ladezeit von Webseiten dramatisch verschlechtern. Schlimmer als weiße Flächen ist das sprungartige Verschieben des Textes, wenn weiter oben gerade ein Bild fertig geladen wurde. Allerdings müssen Bilder bei immer weiter steigenden Pixeldichten der Anzeigegeräte auch immer hochaufgelöster werden und gleichzeitig über langsame 3G-Verbindungen geladen werden.

Da der Eintrag über Fraktale einige recht große Bilder enthält, habe ich ein Pelican-Plugin geschrieben, das

  1. Vorschau-.jpg erzeugt, die in der Regel kleiner als 1 kB sind,
  2. jedes Bild durch die data-uri des Previews ersetzt und dies verschwommen anzeigt, bis das Originalbild per JavaScript nachgeladen ist.

Das sieht dann etwa so aus:

Glücklicherweise ist es recht einfach mit Python html zu parsen und data-uri zu erzeugen, sodass mein Plugin im Wesentlichen fertig generiertes html nimmt und folgendes tut:

import base64
from bs4 import BeautifulSoup

with open("file.html") as f:
    soup = BeautifulSoup(f, "html.parser")

    for img in soup.find_all("img"):
        thumbnail = create_thumbnail(img)
        b64 = base64.b64encode(open(thumbnail, "rb").read()).decode("utf-8")
        data_uri = f"data:image/jpeg;base64,{b64}"
        # TODO: replace img source by the data-uri

Nachdem alles vorbereitet ist, ist die clientseitige Logik mit ein paar Zeilen JavaScript und CSS recht simpel.

Die Idee ist, dynamisch die voll aufgelösten Bilder per JavaScript zu laden und mit dem onLoad Event sichtbar zu machen.

jsnake

Bisher habe ich immer nur kurze Fragmente in JavaScript geschrieben, die meist nur Gimmicks bezweckten oder Bibliotheken aufrufen. JavaScript ist im Moment möglicherweise die wichtigste Sprache: Schließlich ist sämtlicher clientseitiger Code des Webs JavaScript — und dank Node wohl auch nennenswerte Teile des Servercodes. Zumindest macht man nichts falsch, wenn man sich etwas mit JavaScript vertraut macht. Deshalb ist das neuste — und simpelste — Mitglied meiner Snake Sammlung [1, 2, 3, 4] in JavaScript gehalten.

Ausprobieren kann man es gleich hier:

In der Spielwelt herrschen helikale Randbedingungen, hauptsächlich weil es etwas anderes ist als gewöhnliche periodische Ränder. Außerdem hat es den Vorteil, dass man keinen Pause-Modus braucht, weil diese Randbedingungen dafür sorgen, dass die Schlange sich nicht beißt, wenn man sie einfach geradeaus laufen lässt.

Ich habe gehört, dass JavaScript sich in den letzten Jahren stark weiterentwickelt hat. Tatsächlich scheint mir diese Sprache einige interessante Sprachelemente erhalten zu haben, wie arrow functions x => x*x für lambdas oder den spread operator ... den ich am ehesten mit Pythons splat * vergleichen möchte. Ich will nicht behaupten, dass das folgende kartesische Produkt der beste Code oder leserlich wäre, aber interessant allemal:

let SIZE = 3;
let numbers = [...Array(SIZE).keys()];
let a = [].concat(
    ...numbers.map(
        x => numbers.map(
            y => [x, y]
        )
    )
);
console.log(a);

Anscheinend gibt es mit der nächsten geplanten Version (ES6) noch mehr nette Sprachelemente. Unter anderem Module. Ich bin geradezu sprachlos, dass man bisher keine Sprachunterstützung für die Verteilung des Quellcodes über mehrere Dateien hatte. Anscheinend bin ich noch zu sehr von den Konzepten der “C-artigen” Sprachen beeinflusst.

Da jsnake nur ein paar Zeilen in einer Datei sind und sich ein ganzes GitHub Repository deshalb nicht lohnt, habe ich es in einen Gist hochgeladen.