Blog >>> Crew_

Crew Hackathon XIV

Vergangene Woche war es mal wieder so weit - unser insgesamt 14. und erster Hackathon 2022 fand statt. Wie immer haben wir unsere Kundenprojekte für diesen Tag ruhen lassen und uns mit drei komplett anderen Themen beschäftigt, darunter endlich mal wieder etwas mit echter Hardware und einem Serverless-Framework.
09.03.2022
Bene Clauß
Bene Clauß
Projektmanager
Crew Hackathon XIV

Der Ablauf

Im Lauf der Jahre und durch unsere bisherigen Hackathons hat sich ein ziemlich gut funktionierender Ablauf für diesen Tag etabliert. So klappt die Umsetzung sowohl vor Ort im Büro, als auch komplett remote aus dem Homeoffice und inzwischen auch in einem Hybrid-Modell, bei dem ein Teil vom Büro aus und ein Teil im Homeoffice arbeitet.

Im Wesentlichen läuft unser Hackathon so ab:

  • Alle paar Monate lassen wir unser Tagesgeschäft einen Tag ruhen und veranstalten unseren Crew Hackathon
  • Hauptziel ist, dass jede:r etwas Neues lernt
  • Erreicht wird das i.d.R. durch die Bearbeitung von drei bis fünf Themen, von denen wir uns durch den Lerneffekt idealerweise einen Mehrwert für unseren Arbeitsalltag, einzelne Großprojekte oder ganz einfach einen “Invest in die Zukunft” erhoffen
  • Wir starten mit einem gemeinsamen und gespannten Blick auf unser Ideen-Board. Dort hat im Vorfeld jede:r schonmal einen Blick draufgeworfen, eigene Vorschläge eingebracht und sich ein paar Favoriten herausgesucht
  • Eventuell werden manche Themen nochmal kurz vorgestellt und dann geht es eigentlich auch schon an die Gruppenfindung
  • Danach beginnt der eigentliche Hackathon mit Arbeitssession eins, gefolgt von einem kurzen Update jeder Gruppe, um einen Zwischenstand und ggf. Herausforderungen mit der großen Gruppe besprechen zu können, anschließend Mittagspause, Arbeitssession zwei und zum Schluss Präsentation und Besprechung der Ergebnisse. Und dann ist der Tag auch schon wieder rum

Die Themen

Wie eigentlich immer mangelte es auch dieses Mal nicht an vielversprechenden Themen, eher das Gegenteil war der Fall und viele von uns hatten ihr Herzensthema mitgebracht. So musste erst eine Weile eisern verhandelt und gefeilscht werden, bis wir uns schließlich auf drei Themen einigen konnten.

So ergaben sich für unseren Hackathon XIV die folgenden Projekte:

Elixir Nerves

  • Team: Hauke, Lennart, Simon
  • Ziel: Erste Erfahrungen mit Elixir Nerves sammeln.

Elixir ist eine funktionale Programmiersprache, die wir seit Jahren mit Freude bei der Entwicklung von skalierbaren und robusten System im Web verwenden. Durch das Nerves Projekt können diese Vorteile auch im Bereich IoT ausgespielt werden. Das wollten wir unbedingt ausprobieren.

Ausgerüstet mit zwei Raspberry Pis haben wir die Geräte mit Nerves aufgesetzt. Anstatt die Standard-Firmware zu verwenden, haben wir uns für eine Livebook-Variante entscheiden. Livebook ist gut mit Jupyter Notebooks aus dem Python Universum vergleichbar – interaktive und kollaborative Notebooks in Elixir. Dank der gewohnt guten Dokumentation und des umfangreichen Toolings hatten wir innerhalb von Minuten eine Livebook-Instanz auf dem Raspberry Pi laufen und konnten direkt loslegen. Wahrscheinlich für viele etwas ungewohnt ist, dass der Raspberry Pi nach dem Booten direkt in die BEAM (Erlang virtual machine) startet und nicht ins Linux-Betriebssystem. Ist man den Umgang mit Elixir-Projekten gewohnt, hat man die BEAM und die interaktive Elixir-Shell IEx schon längst lieben gelernt.

Durch Livebook konnten wir direkt ein Notebook erstellen und die ersten Funktionen und Module implementieren. Ein erster Schritt war ein LED-Modul, um die System-LED auf dem Raspberry Pi anzusteuern:

defmodule LED do
  @led Path.join("/sys/class/leds", "led0")

  def switch(:on) do
    File.write(Path.join(@led, "brightness"), "1")
  end

  def switch(:off) do
    File.write(Path.join(@led, "brightness"), "0")
  end
end

Wir konnten somit eine LED ansteuern – als Nächstes wollten wir etwas auslesen. Gut, dass wir noch einen Schalter von Knoop im Lager hatten.

Raspberry Pi mit Button

Als der Schalter verdrahtet und eine erste Variante des Button-Moduls implementiert war, mussten wir feststellen, dass das Button-Event öfter empfangen, als auf den Button gedrückt wurde. Der große grüne Hot Button musste offensichtlich entprellt werden. Die finale Version mit Entprellung des Schalters verwendet noch ein Slack-Modul, welches eine Nachricht in einen Slack-Channel postet. Aber seht selbst:

defmodule Button do
  # The threshold is in nano seconds
  @threshold 500 * 10 ** 4

  # Watch for the button press
  def listen_forever(last \\ 0) do
    receive do
      {:circuits_gpio, _p, now, state} ->
        state
        |> to_action()
        |> receive_msg(last, now)
    end
  end

  def to_action(1), do: :on
  def to_action(0), do: :off

  def receive_msg(action, last, now) when now >= last + @threshold do
    IO.puts("#{now} #{action}")

    :ok = LED.switch(action)

    maybe_notify(action)
    listen_forever(now)
  end

  def receive_msg(_action, last, _now), do: listen_forever(last)

  def maybe_notify(:on), do: Slack.post()
  def maybe_notify(:off), do: nil
end

Das gesamte Livebook haben wir bei GitHub veröffentlicht: https://github.com/sourceboat/hackathon-14-elixir-nerves-hot-button/blob/main/notebook.livemd

Kurz vor Ende des Hackathons haben wir damit angefangen eine eigene Firmware, ohne Livebook zu erstellen, da jedes Livebook explizit gestartet werden muss und eher für das Prototyping gedacht ist. Mit einer eigenen Firmware ist sichergestellt, dass alle Prozesse auch nach einem Neustart noch laufen – nicht, dass der Hot Button irgendwann nicht mehr funktioniert. :-)

Zusammengefasst können wir sagen, dass unser Hackathon-Projekt mit Nerves Lust auf mehr macht. Und das, obwohl nicht alle aus unserem Team Erfahrungen mit Elixir hatten. Es war mit Sicherheit nicht der letzte Nerves-Content.

Flutter: Multiplattform (Windows, macOS, Linux…)

  • Team: Tristan, Mats
  • Ziel: Flutter auf verschiedenen Plattformen ausprobieren und die Entwicklung mit Apple M1 Chip testen.

Flutter ist ein Open-Source-Framework von Google zur Erstellung von plattformübergreifenden Anwendungen aus einer einzigen Codebasis. Durch das neueste Update, wurde der Support für weitere Betriebssysteme wie Windows, macOS und Linux freigeschaltet. Um diese Plattformen zu testen, haben wir eine kleine Test-App gebaut, die eine eigene API anbindet und diese auf allen Umgebungen einmal ausgeführt. Unser Testergebnis schaut dabei wie folgt aus:

  • Android: App funktioniert problemlos ✅
  • iOS: App funktioniert problemlos ✅
  • Web (Chrome): CORS-Probleme ⛔️
  • macOS: Probleme mit der Websocket-Verbindung ⛔️
  • Windows: App funktioniert problemlos ✅
  • Linux: wurde nicht getestet ❓

Die Entwicklung auf unseren MacBooks mit M1 Chip lief dabei problemlos und deutlich schneller als auf unseren alten MacBooks mit Intel Chips.

Serverless functions on Kubernetes

  • Team: Kevin, Sebastian, Phil
  • Ziel: Eine serverlose PHP-Funktion via Fission in einem Kubernetes-Cluster deployen.

Wir haben uns bei diesem Hackathon mit Fission auseinandergesetzt. Fission ist ein Framework, um serverlose Funktionen im eigenen Kubernetes-Cluster zu provisionieren. Dies könnte eine extreme Erleichterung für ein kommendes Produkt von uns als auch für interne Spielereien wie unseren Learning Tips Bot sein, den wir beim letzten Hackathon begonnen haben.

Neben Fission gibt es noch eine Reihe weiterer Frameworks, die in eine ähnliche Richtung gehen - z.B. Apache OpenWhisk, Fn Project, Knative und OpenFaaS. Fission überzeugte uns durch einen einfachen Einstieg und dem Konzept der “warmen” Function Pools, die eine besonders kurze Startzeit von inaktiven Funktionen ermöglicht, da wir in unserem kommenden Produkt voraussichtlich viele unterschiedliche, aber verhältnismäßig wenig genutzte Funktionen bereitstellen möchten.

Die Installation via Helm Chart war unkompliziert und ohne große Hürden. Funktionen in Fission laufen in sogenannten Environments. Dies sind fertige oder eigens erstellte Docker Images, die eine bestimmte Programmiersprache unterstützen. Es kann definiert werden, wie viele Container einer bestimmten Umgebung in einem Pool “warm” gehalten werden. Sofern dann eine explizite Funktion ausgelöst wird, kann eine Umgebung in kürzester Zeit auf diese Funktion spezialisiert werden, um diese Funktion auszuführen. Bis zu einer definierten Idle Time bleibt dieser Container dann verfügbar für weitere Funktionsaufrufe derselben Art und entfernt sich danach selbst.

$ fission env create --name nodejs --image fission/node-env --poolsize=5

$ cat hello.js
module.exports = function(context, callback) {
  callback(200, "Hello world!")
}

$ fission function create function --name hello --env nodejs --code hello.js

$ fission route add --function hello --url /hello

$ curl http://router.fission/hello
Hello world!

Fission stellt für diverse Sprachen eine Umgebung bereit. Für PHP steht allerdings nur eine rudimentäre Variante zur Verfügung, die lediglich PHP 7.3 unterstützt. Da wir neugierig sind, wie sich PHP in einer serverlosen Umgebung schlägt, und wir als Experiment einen existierenden PHP-Bot testen möchten, haben wir uns dazu entschieden ein eigenes Image mit PHP 8.1 zu implementieren.

Um die Struktur der vorgehaltenen Pools und der Spezialisierung auf Anfrage umzusetzen, sind Environments als Webserver implementiert. Es werden zwei Routen zu Verfügung gestellt: eine welche zur Spezialisierung dient und eine weitere um die Funktion auszuführen. In unserem Experiment haben wir die Implementation des offiziellen PHP 7.3 Environment angepasst. Hier wird beim Spezialisieren festgelegt, welche Funktion in welchem Dateipfad ausgeführt werden soll. Bei Aufruf der Route zum Ausführen der Funktion, wird der PHP-Code vom spezifizierten Dateipfad geladen und anschließend die eingestellte Funktion aufgerufen. Hierbei ist zu beachten, dass es nötig ist require_once zu verwenden, um Mehrfachdefinition von Klassen und Funktionen zu vermeiden. Das hat zur Folge, dass Anweisungen, die direkt auf oberster Ebene der auszuführenden Dateien definiert sind, nur beim ersten Aufruf durch das require_once-Statement ausgeführt werden, solange der Container verfügbar ist.

Zum Testen haben wir unseren in PHP geschriebenen Learning-Bot umgeschrieben, um ihn als serverlose Funktion ausführen zu können. Sobald die Funktion ausgeführt wird, wird ein Tipp - bestehend aus Titel, Beschreibung und URL (optional) - aus einer Datenbank ausgelesen und in einen Slack-Channel gepostet.

Die Funktionsdatei enthält eine Klasse zum Auslesen der Daten und eine Klasse, um die Nachricht in Slack zu posten. Weiterhin enthält die Datei eine handler(array $context)-Funktion, die beim Ausführen der Funktion aufgerufen wird und die beiden Klassen nutzt. Die Klassen und die Funktion werden beim ersten Aufruf durch require_once geladen und anschließend wird die handler($context) Funktion aufgerufen. Wenn die serverlose Funktion innerhalb der Idle Time erneut aufgerufen wird, so wird erneut die handler($context) Funktion aufgerufen.

function handler($context) {
    $slack = Slack::make($webhookUrl);

    LearningTips::make()
        ->rows('learning_tips', 'tips', static function(Response $response) use ($slack) {
            $datasets = $response->getData();
            $data = $datasets[rand(0, count($datasets) - 1)];
            $slack->send($data->title, $data->long_version, $data->url);
        });
}

class LearningTips {
    ...
}

class Slack {
    ...
}

Noch nicht genug von unseren Hackathons oder Softwareentwicklung? Hier geht’s zu den Blogposts unserer bisherigen Hackathons:

Außerdem suchen wir aktuell sowohl PHP-, als auch Elixir-Softwareentwickler:innen. Zu unseren Jobs geht es hier entlang. :-)

Teilen @
Lust auf was Neues?
Aktuelle Stellenangebote >>>