Stranger Than Usual

Running at a constant 20 watts, our brains are enough to power a lightbulb – whether any bright ideas are forthcoming or not. 💡

PBS Eons: How Brawn Led to Brains

Antiquiertes HTML

Lesetipp: Antiquated HTML Snippets and Artefacts. Dort zeigt der Autor einen Haufen HTML-Snippets, die früher sehr verbreitet, die aber ihren Nutzen verloren haben. Meist, weil sie ein Workaround für etwas waren, dass man früher nicht anders machen konnte, oder ein Workaround, um mit irgendwelchen kaputten Browsern (IE) klarzukommen.

Ein paar Sachen davon stammen noch aus der Zeit bevor ich mich mit Webentwicklung beschäftigt habe. Viele davon habe ich aber auch schon in HTML-Code gesehen, mit dem ich arbeiten musste, manche habe ich auch entfernt, weil sie nicht mehr benötigt wurden. Ein Klassiker, den ich fast überall gesehen habe, ist

<meta http-equiv="X-UA-Compatible" content="IE=edge">

In eine ähnliche Schiene fallen The HTML Elements Time Forgot, ein Artikel, den der Autor oben auch verlinkt. Da geht es aber um tatsächliche HTML-Elemente, die (standardisiert oder nicht) einmal mehr oder weniger weit verbreitet waren, heute aber nicht mehr benutzt werden sollen und oft von Browsern nicht einmal mehr interpretiert werden.

Und heute hat der Autor auch noch einen weiteren Post veröffentlicht, dieses mal geht es um CSS Curiosities of the Past, wobei mir davon nur die Vendor-Prefixes bekannt waren. Die habe ich mal beruflich genutzt. Ich wollte das damals neue flex benutzen, aber wir mussten einige veraltete Browser noch unterstützen. Also habe ich zusätzlich zum standardisierten flex noch drei oder vier pre-Standard-Regeln mit Vendor-Prefixen genutzt, die (abgesehen von einer Version) sich fast so verhalten haben, wie der spätere Standard.

Auf jeden Fall lesenswert, wenn man in die Ungeheuerlichkeiten des HTMLs der 2000er einsteigen will oder Nostalgie für eine Zeit verspürt, in der das WWW noch ein Ort voller Hoffnung war und nicht der Torment Nexus, der es zu großen Teilen heute ist. Nostalgie halt.

PS: Und gerade eben habe ich über das gleiche Blog (aber einen anderen Artikel) erfahren, dass intitial-scale=1 nicht mehr nötig ist.

Rant: Java und Spring

Ich habe gestern den folgenden, etwas über zwei Jahre alten Kommentar zu Spring gelesen:

Spring is a lovecraftian ballache of unnamable horrors. Spring Boot does a decent job at putting those horrors in a box that, with some luck, you may not need to open (and God help you when you do). Of the commonly used modern web frameworks, Spring and Spring Boot are just aggressively mediocre. The learning process of Spring et al involves being thrashed around by enterprise-tier Java errors until you develop enough scar tissue that you can dodge them like a Dark Souls boss fight. I say this as someone with quite a few years professional experience using it, it's such an uneccessarily convoluted mess that's imposed on junior developers like some weird tech generational trauma.

Nun muss ich zugeben, dass meine Suche zu Meinungen über das Spring-Framework voreingenommen war. Meine Suchbegriffe waren „java spring rant“ oder so ähnlich. Aber meine Güte, dieses Framework macht mich fertig. In Kürze: Unter dem Versprechen, alles einfacher, besser geordnet und wartbarer zu machen wird so viel Komplexität, magisches Verhalten und Abstraktion eingeführt, dass am Ende alles komplizierter geworden ist, man eine overengineertes Klassenhierarchie hat und aufrufenden von aufgerufenem Code so weit getrennt hat, dass man selbst für einfache Vorgänge immer in mindestens vier verschiedene Dateien schauen muss.

Aber fangen wir mal weiter vorne an. Java. Eine Programmiersprache, die ich nie wirklich gemocht habe. In den letzten Jahren wurden ein paar Features eingeführt, die sie ein bisschen erträglicher machen, aber wirklich Spaß gemacht hat sie mir nie. Aber man kann mit ihr arbeiten. Was mir mehr Probleme bereitet sind die Paradigmen, mit denen viele große Java-Projekte entwickelt werden.

Da ist zunächst einmal der Zwang, alles zu entkoppeln. Man solle nie mit der Klasse selbst reden, immer nur mit einem Interface, dann kann man die Implementierung ganz einfach austauschen. I call bullshit. Ich habe jahrelang an einem Javaprojekt gearbeitet. In vielleicht 95 % der Fälle will man eine Implementierung eines Interfaces eh nie austauschen. In den anderen fünf Prozent ist es relativ leicht, die Implementierung auch so auszutauschen. Wenn man doch einmal Polymorphie braucht, kann man sie meist ohne Probleme nachträglich hinzufügen. Aber nein. Das wäre ja zu einfach. Stattdessen muss für alles immer erst ein Interface gemacht werden, für das es dann genau eine Implementierung gibt. Das ist immer eine Menge Boilerplate, eine Menge Indirektion und macht es schwieriger zu verstehen, welche Wege der Code gerade genommen hat.

Und dann kommt Spring. Spring will Independency Injection, aber das muss alles automagisch gehen, also hängt man irgendwelche Annotationen an irgendwelche Klassen und hofft, dass es funktioniert. Wenn es funktioniert, dann gut. Wenn nicht: Viel Spaß mit den Fehlermeldungen, die garantiert nutzlos sind um herauszufinden, was nicht funktioniert, geschweige denn, warum. Ich könnte einfach Instanzen meiner Services manuell hereinreichen, aber nein. Das muss automagisch, mit Reflektion gehen.

Was mich aber diese Woche wirklich auf die Palme getrieben hat, war Transaktionshandling. Spring hat dafür die @Transactional-Annotation. Die hängt man an Funktionen, und dann werden die automagisch in einer Transaktion ausgeführt (per default in einer existierenden, wenn keine existiert, wird eine neue geöffnet). Aber nur, wenn die Funktion aus einer anderen Klasse heraus aufgerufen wird. Wird die Funktion aus derselben Klasse heraus aufgerufen, wird die Transaktionsannotation ignoriert. Warum? Nun, das liegt an der Magie, mit der das gemacht wird.

Jetzt habe ich also eine Transaktion. Bei Transaktionen möchte ich, dass sie zurückgerollt werden, wenn irgendwas schiefgeht. Aber… Mist, Spring föngt die Datenbankexceptions von selber ab, und leitet sie nicht an mich weiter (merkt sie sich aber wohl für den Transaktionsabschluss?). Ich kann also zum Beispiel nicht direkt auf eine constraint violation exception reagieren. Also mache ich ein bisschen manuellen Kram und werfe eine Exception, damit ich weiter oben im Webservice einen ordentlichen 4xx-Statuscode zurückgeben kann. Für den seltenen Fall, dass es beim Transaktionsabschluss tatsächlich zu einer race condition mit Konflikten gekommen sein sollte, nehme ich halt den 500er-Fehler in Kauf.

Aber Pustekuchen. Beim Testen muss ich feststellen, dass meine Exception keinen Rollback ausgelöst hat. Warum nicht? Die @Transational-Annotation rollt nur zurück, wenn eine unchecked exception über die Funktionsgrenzen der annotierten Funktion hinaus fliegt. Checked Excepions? Per default kein Rollback. Aber ich kann extra angeben, dass auch die einen Rollback auslösen. Dann kommt auch der Rollback. Aber anstelle wie gewollte einen 4xx-Fehlercode zurückzugeben, fliegt jetzt eine UnexpectedRollbackException und damit gibt es einen Fehler 500.

Ich habe bis jetzt noch nicht herausgefunden, wie ich sowohl die Transaktion zurückrollen als auch einen von mir ausgewählten Fehlercode zurückgeben kann.

Also kurz zusammengefasst:

  • ich muss @Transactional verwenden, um Transaktionen zu verwalten, aber das funktioniert nur bei Aufrufen über Klassengrenzen hinweg
  • Spring hält Datenbankexceptions zurück, ich kriege sie nicht zu sehen
  • ich muss trotzdem manuell angeben, welche Exceptions ein Zurückrollen auslösen sollen
  • wenn ein Zurückrollen ausgelöst wird, kann ich das nicht graceful machen.

Und das alles soll irgendwie einfacher sein als manuelles Transaktions-Handling.

Ich schiebe die Hauptschuld hier auf Spring, aber auch ein bisschen auf die Java-Kultur, die jahrelang gepredigt hat, Design Patterns bis zum Gehtnichtmehr zu verwenden, alles auf Teufel komm raus zu entkoppeln und alles möglichst flexibel zu halten. Nur, dass diese Flexibilität in vielen Fällen garnicht nötig ist, dafür aber eine Menge Komplexität erzeugt.

Nicht umsonst hat „Everything wrong with Java in a single class“ so weite Kreise gezogen, nicht umsonst stammt das Beispiel aus dem Spring-Framework: AbstractSingletonProxyFactoryBean.

So. Genug geranted. Aber das musste raus, dieses Framework treibt mich einfach in den Wahnsinn.

PS: Der Kunde besteht darauf, dass wir Spring verwenden. Normalerweise würden wir es bei meinem Arbeitgeber nicht verwenden. Wir haben ein paar grundsätzliche Regeln gegen Pattern, die alles einfacher machen sollen, aber genau das Gegenteil erreichen:

  • benutze kein ORM
  • benutze keine dependency injection
  • benutze keine großen Frameworks
  • schreibe Interfaces nur, wenn du sie wirklich brauchst
  • fange keine neuen Projekte in Java an

Das ist nur ein Teil der Regeln, aber das sind imho die wichtigsten Regeln, die wir in diesem Projekt verletzen.

Rollenspielszenen: Gewaltfreie Demonstration

Rollenspielszene. Wir wollen den Wald retten. Die (hoffentlich große) Demo rückt näher. Shane (Pilzenthusiast, Medium und Arzt) und Siobhan (hauptberufliche Revolutionärin) reden über die Demo. Shane hat zum Beispiel die Geister des Waldes dazu angehalten, den Demonstranten zu helfen, falls die Demo gewaltsam aufgelöst wird uns sich Demonstranten in den Wald flüchten müssen. Siobhan überlegt, ob Shane mit den Pilzen nicht etwas machen könnte, um beim Militär oder der Polizei Halluzinationen hervorzurufen.

Shane, als Arzt und Pazifist, ist komplett gegen diese Idee. Es folgt ein längeres Gespräch, ob man bei der Demo Gewalt anwenden will, wenn die Gegenseite zuerst gewalttätig wird, und so weiter. Shane ist strikt gegen Gewalt. Siobhan ist gegenüber Shane vorsichtig damit, eine klare Befürwortung von Gewalt zu äußern.

Nach dem Gespräch geht sie aber in die Stadt, zu den „etwas rabiateren Leuten“, wie sie es ausdrückt, und wirbt sie für die Demo an.

Brother: Pluszeichen in der Email-Adresse

Ich hatte heute einen Scheißtag. Ich bin durch beruflichen Stress mit den Nerven am Ende, ich habe mir heute zwei Mal die rechte Schulter ausgekugelt, einige meiner Lieblingspflanzen sterben gerade und ich weiß nicht, warum. Heute Abend habe ich mir dann gedacht: Damit ich heute wenigstens eine Sache geschafft habe, kaufe ich mir endlich einen Drucker, damit ich das mal hinter mir habe (und ich endlich die dazugehörigen Tabs im Browser schließen kann).

Da OpenPrinter anscheinend immer noch nicht mit dem Verkauf angefangen hat, ich wegen andauernder Kundengängelung von Druckerherstellern wie HP dort keinen Drucker kaufen möchte und von Brother bisher eher Gutes gehört habe, bin ich zu Brother gegangen. Ich habe mir einen einfachen Monochrom-Laserdrucker ausgesucht und wollte ihn kaufen. Sollte kein Problem sein, oder?

Hahaha, doch. Natürlich kann ich nicht ohne Account einkaufen. Für den Account muss ich bei Brother meine Email-Adresse angeben. Ich gebe bei solchen Angelegenheiten gerne meine Adresse mit einem Pluszeichen am Ende des lokalen Teils an. Bei einigen Mailprovidern (mittlerweile glücklicherweise auch bei Posteo) kann man Konstrukte wie foobar+suffix@example.com angeben, und die Mails an diese Adresse landen alle im Postfach für foobar@example.com. Der Vorteil: Ich kann für jeden Dienst, bei dem ich mich anmelde, eine einzigartige Adresse angeben und dann, falls die Adresse geleaked wird und ich Spam bekomme, feststelle, wer meine Adresse geleaked hat. Soweit die Theorie.

In der Praxis erlauben viele Webservices keine Pluszeichen in Emailadressen. Und das, obwohl Pluszeichen völlig legale Zeichen im lokalen Teil der Email-Adresse sind. Zu solchen Anbietern gehören zum Beispiel Microsoft, die deutsche Telekom und Verimi (letztere stellen ihre Dienste Ende des Jahres ein, was ich mir für Microsoft auch wünschen würde).

Die Verifizierung, dass die Adresse kein Pluszeichen enthält, wird aber erst einmal rein clientseitig gemacht. Also dachte ich mir, ich könnte die vielleicht umgehen, indem ich den Regex aus dem Eingabefeld entferne. Tatsächlich geht das auch. Ich kann die Emailadresse eingeben, das Formular abschicken und kriege einen Statuscode 200 OK zurück.

Nur eine Email erhalte ich eben nicht. Also machen die mutmaßlich serverseitig keine direkte Verifizierung, geben mir eine Erfolgsmeldung, scheitern dann aber später daran, die Email auch tatsächlich zu verschicken. Also kann ich mir keinen Account anlegen und damit auch keinen Drucker kaufen.

Es war ein Scheißtag, und jeder Versuch, diesen Scheißtag zu verbessern ist fehlgeschlagen und hat ihn nur noch mehr scheiße gemacht.

PS: Es gibt da diesen Klassiker I Knew How To Validate An Email Address Until I Read The RFC, diesen jüngeren Artikel mit ähnlichem Topic: Your E-Mail Validation Logic is Wrong, und die beste Empfehlung, die ich zur Emailadressvalidierung gelesen habe ist: Akzeptiere alles mit einem @ drin, aber schicke dann eine Email an diese Adresse, um zu verifizieren, dass sie auch ankommt. Den zweiten Teil davon hat Brother implementiert. Den ersten Teil nicht. Also gut, vielleicht warte ich doch auf den OpenPrinter. Einen Laserdrucker hätte ich trotzdem gerne noch, alleine schon für die Erstellung von Stempeln aus Photopolymer.

Postgres in Prod, H2 zum Testen

In einem Projekt auf der Arbeit verwenden wir gerade mal wieder Java (meh). Und Spring (uääh). Und Hibernate (uääääääääh). Und wir schreiben integration tests, immerhin. Das System verwendet am Ende eine Postgres-Datenbank, aber für die integration tests verwenden wir eine in-memory Datenbank, H2. Das ist keine gute Idee, und ich werde hier schreiben, warum.

Ich musste für ein Feature einen etwas komplizierteren unique constraint aufbauen. Einen, der nur griff, wenn eine bestimmte Spalte einen bestimmten Wert hatte. So ungefähr (Beispielcode, nicht mein tatsächlicher Code):

create unique index open_request_unique
on requests
where status = 'awaiting_approval';

Diese Datenbankänderung funktioniert auf Postgres super. Dummerweise wurden für die Integrationstests exakt die gleichen Migrationsscripte verwendet. Nun ist aber jeder SQL-Dialekt ein bisschen unterschiedlich. H2 hat zwar einen Kompatibilitätsmodus für Postgres, aber der ist alles andere als perfekt. Ich bekam einen Fehler, wenn ich die Tests laufen lies, weil die Migration nicht funktionierte.

Hier kommt Spring (uääh) ins Spiel. Anstatt mir nämlich direkt zu sagen, dass die Datenbankmigration kaputt ist, wälzt mir Spring Seiten über Seiten mir immer der gleichen Fehlermeldung über den Bildschirm, darüber noch mehr Seiten an völlig nutzlosen Stacktraces (nutzlos, weil sie nur Spring-Klassen enthalten und mit meinem Code nichts zu tun haben) und erst darüber ein paar SQL-Fehlermeldungen. Ich musste wirklich eine halbe Minute lang nach oben scrollen, bis ich den relevanten Teil erreicht habe. Aber warum einfach, wenn es auch kompliziert geht? Fuck you, Spring.

Die Kollegen auf Kundenseite waren abgeneigt, daran etwas zu ändern, also habe ich das Problem gelöst, indem ich statt dem conditional unique request ein zweite Tabelle angelegt habe, in die nur offene requests kamen, und dort dann einen regulären unique constraint genutzt.

Und es stellt sich heraus: Ich bin nicht der einzige, der dieses Problem hat. Jemand anderes, irgendwo im Internet, hatte genau dasselbe Problem. Dieser Person ist dann auch aufgefallen, dass es noch ein paar subtilere Unterschiede gab, wo z.B. die H2-Datenbank constraints nicht durchgesetzt hat, während Postgres es getan hat.

Was mich hier ärgert ist weniger, dass sich die Testdatenbank anders verhält als die Prod-Datenbank. Das ist kacke, aber ich könnte mich damit abfinden, auch wenn es manche Tests unmöglich macht (aber die meisten Tests laufen sehr gut). Was mich wirklich ärgert ist, dass ich meinen Code schlechter (d.h. komplexer und weniger effizient) machen musste, nur damit die Tests durchlaufen. Ich habe also meinen Code an die Beschränkungen der Tests.

Grundsätzlich halte ich es übrigens nicht für ein Problem, beim Schreiben des Codes auf gute Testbarkeit zu achten. Oft ist gut testbarer Code auch einfacher zu verstehen und ordentlicher aufgebaut. Aber wenn man seinen Code schlechter machen muss, um ihn testen zu können, dann hat man ein Problem. Und in diesem speziellen Fall war allein die Existenz meines Datenbankpatches Grund für fehlschlagende Tests. Ich hätte nicht einmal Tests zu schreiben brauchen, oder auch nur Code, der die Datenbank nutzt!

Wie löst man das Problem? Nun, in diesem Fall kann man sehr gut einfach die integration tests direkt auf Postgres laufen lassen. Man kann Postgres sogar in-memory laufen lassen. Tatsächlich ist Postgres sehr mächtig. Ich würde es nicht für alle Zwecke einsetzen, die der Autor in dem verlinkten Artikel beschreibt, aber viele Vorschläge sind tatsächlich sehr nützlich, insbesondere, wenn man ohnehin schon eine Postgres-Datenbank am Start hat.

Die Kollegen auf Kundenseite sind aber gerade unter Zeitdruck und wollen keine derartigen Änderungen. Also muss ich bis auf Weiteres (und vermutlich dauerhaft) meinen schlechteren Code nutzen.

Die Brandmauer in Sachsen-Anhalt

Das ist es also. Laut dem vorläufigen Wahlergebnis hat die rechtsextreme AfD mit Abstand die meisten Stimmen und damit die meisten Sitze im Landtag von Sachsen-Anhalt. Sie hat aber keine Absolute Mehrheit.

Daraus ergibt sich die Frage: Wer wird künftig Sachsen-Anhalt regieren? Ich bin kein Politikexperte, aber die AfD sitzt hier am längeren Hebel: Sie könnte theoretisch mit jeder anderen Partei eine Koalition eingehen. Umgekehrt müssten alle anderen Parteien in eine Koalition gehen, um die Mehrheit gegenüber der AfD zu haben. Insbesondere auch die CDU, die Linke und das BSW.

Jetzt wird sich also zeigen, ob die viel beschworene Brandmauer gegen die AfD hält. Ich habe auch einer Demo mal den Spruch „Die Brandmauer der CDU ist aus Stroh“ gelesen. Ich würde eher sagen: „Die Brandmauer der CDU ist aus Holz“. Immer noch brennbar, aber braucht deutlich mehr, um Feuer zu fangen.

Aber brennbar genug, um sich Sorgen zu machen. Um Grüne, SPD und Linke mache ich mir keine Sorgen. Die werden keine Koalition mit der AfD eingehen. Aber angeblich hat irgendjemand vom BSW verkünden lassen, zur Not eine Koalition mit der AfD einzugehen (ich konnte dafür aber keine Quelle finden). Die CDU hingegen… ich kann mir vorstellen, dass sie sich irgendeine faule Ausrede einfallen lässt, warum eine Koalition mit der AfD nötig sei. Ich hoffe nur, dass es nicht so kommt.

Abgesehen von der Wahl: Eine Brandmauer alleine reicht nicht. Bei einem Hausbrand zum Beispiel ist eine Brandmauer wichtig, um die Ausbreitung eines Feuers zu verhindern. Aber das Feuer sollte trotzdem idealerweise garnicht erst entstehen, es muss Warnmechanismen geben, und man muss es löschen. Ebenso in der IT: Eine Firewall (also Brandmauer) reicht nicht aus, um einen Computer im Netzwerk zu schützen.

Wir haben die Warnungen, seit Jahren. Zivile Initiativen warnen seit Jahren, aber kriegen nicht ausreichend Gehör. Wir haben ausreichend Belege dafür, dass die AfD rechtsextrem, verfassungsfeindlich und eine Gefahr für die Demokratie ist. Aber die Politik ist zu Feige, die Verfassungsfeindlichkeit der AfD auch nur zu PRÜFen. Aber wenn wir die AfD vor das Verfassungsgericht zerren wollen, müssen Bundesregierung, Bundestag oder Bundesrat dazu einen Antrag stellen. Bisher haben sie es nicht getan.

Ich glaube auch nicht, dass sich das Problem alleine mit einem Verbot der AfD erledigt. In Sachsen-Anhalt zum Beispiel haben die Rechten jetzt 39 von 83 Sitzen, und die werden sie behalten, selbst wenn die AfD verboten wird. Auch wird das rechte Gedankengut nicht einfach aus den Köpfen der Menschen verschwinden. Aber die (dann ex-) AfD würde es damit wesentlich schwerer haben.

Book Swap: A Night in the Lonesome October

This year, I did a book swap with a group of friends and acquaintances. It worked like this: Everyone who participated picked a book that they think other people should read. Then everyone got assigned someone within the group of participants they gifted this book to (there was some check for potential trigger content and that the receiver had not read the book yet).

I got A Night in the Lonesome October by Roger Zelazny. After two weeks, I finally found he time to read it. I like the book. It is something new but it picked up a lot of tropes and character Archetypes from literature classic. WARNING: Minor spoilers ahead.

The book is narrated in first person by Snuff. Snuff is a watchdog who is helping his human master Jack with some shady business. At first, it seems that Snuff just has an overactive imagination and needs to snarl and bark and seemingly innocent things, as dogs do:

I have to keep watch on the Thing in the Circle, the Thing in the Wardrobe, the Thing in the Steamer Trunk—not to mention the Things in the Mirror.

It gets clear pretty quickly though, that things actually are pretty supernatural. A ritual is to be prepared and several other players are preparing for the same thing (or are they?). There is an old (or young?) witch, an druid, a Vampire (the classic, aristocratic, Dracula-ish kind), a Frankentstein-like mad scientist and his experiment, a rasputin-like person, a werewolf and the Great Detective (a Sherlock Holmes kind of guy). And of course Jack (the Ripper?).

They prepare a ritual for one specific day in October and they need to figure out who is in the game at all, who is on their side and who opposes them. For that, they have animal companions. There is Snuff the Dog, there is a cat, an owl, a bat, a snake, a rat… you get the picture.

Since the story is told from the perspective of Snuff, what the humans do is not the focus of the story. It is important to the events, of course, but the focus lies on Snuff's interactions with the other animal companions. They spy on each other. They exchange information and favours. They scout, sometimes they try to sabotage others. It is a constant game of paranoia, since only in the latter half of the book it becomes clear who is an „opener“ and who is a „closer“.

It is a great book with interesting views on common character archetypes, told from a rather uncommon perspective, and mostly it does not give much exposition so the reader has to piece together what is going on by themselves. It has some horror elements but the story itself is surprisingly wholesome. I really liked the book and I can recommend it.

Alt aber schnell

Seit ich 2012 mein altes Blog auf blogger.de verlassen habe und mein Blog auf meinem eigenen Server gehostet habe, hat sich dort nicht mehr viel verändert. Es läuft immer noch die gleiche alte Software (mit ein paar Patches), antville. Das letzte Mal, dass ich dort etwas gemacht habe war, als ich 2020 die Posts des alten Blogs in mein neues Blog importiert habe.

Dieser Import war mir wichtig, denn bei so einem alten System weiß man ja nie, wann der Betreiber vielleicht mal aufgibt. Aber jetzt, noch einmal fast sechs Jahre später, ist blogger.de immer noch da. Seit Jahren hält es sich, stabil und fast unverändert, während ringsherum Websites entstehen und wieder eingehen.

Und bei allem, was mir technisch an blogger.de nicht gefällt (Hallo? Nicht einmal UTF-8?), muss ich neidlos anerkennen, dass diese Stabilität eine schöne Sache ist. Und nicht nur das: Die Seite ist auch schnell. Gut, mein aktuelles Blog ist auch schnell. Mein aktuelles Blog ist aber auch ein Haufen statisch generierter HTML-Dateien. Wenn das nicht schnell ist, dann habe ich irgendetwas wirklich falsch gemacht.

Aber blogger.de ist ähnlich schnell. Und ich glaube, ein Hauptgrund dafür ist, dass es einfach viel weniger bloat gibt als auf vielen „modernen“ Websites. Das HTML wird serverseitig generiert, es gibt ein bisschen CSS und ein minimals Javascript-Script. Keine XHR-Requests. Kein langes Nachladen von nutzlosem Krams. Ich lade die Startseite meines alten Blogs und es sind 66 kiB. Bei viel zu vielen Websites heute kommt man nicht unter 1 MiB! Auch bei ebenso einfachen Blogs. Das ist nicht nötig! Wir kommen auch ohne den Bloat aus!

PS: Ich habe ein bisschen die Templates des alten Blogs angepasst und ein bisschen in Richtung HTML-5 gearbeitet. Es ist nicht komplett gültig (z.B. ist es nicht UTF-8-codiert), aber daran kann ich nichts ändern, das Encoding kommt vom Server. Immerhin sollte die Seite jetzt auf Smartphones ein bisschen schöner angezeigt werden. Ansonsten sieht sie sehr ähnlich aus wie vorher. Warum habe ich das gemacht? Eine spontane Obsession, wie ich sie häufig habe, und die ich auch schon darin ausgelebt habe, die Website einer Freundin zu verbessern oder die Website von winkekatze24.de.

Der Adenauer SRP+ hat es auf tagesschau.de geschafft

Der Adenauer SRP+ hat es in einen Artikel auf tagesschau.de geschafft. Der Bus des Zentrums für politische Schönheit, der Hauptsächlich für Demos gegen Rechts (insbesondere gegen die AfD) da ist, wird nämlich regelmäßig von der Polizei angehalten und wegen angeblicher Verkehrsuntauglichkeit festgesetzt. Und obwohl sich immer wieder ergibt, dass der Bus alle Regeln einhält, hält die Polizei an dieser Masche fest. Darüber wurde auch schon in Logbuch Netzpolitik berichtet.

Niemand kann mehr behaupten, dass es hier wirklich um Verkehrssicherheit geht. Es geht hier einfach darum, das ZfPS davon abzuhalten, zu Demos zu kommen. Dabei sollte die Polizei doch genau so gegen Rechts sein wie die Mehrheit in Deutschland. Ich kann ja verstehen, dass sie auch die Rechte der AfD schützen müssen (da sind sie immerhin zu Neutralität verpflichtet, schützen sie z.B. die Grünen nicht in diesem Maße). Aber eine rechtmäßige Demo gegen eine Verfassungsfeindliche Partei aktiv zu behindern, dass ist unserer Ordnungskräfte nicht würdig. Da frage ich mich nämlich, ob da nicht doch einige Beamte dabei sind, die lieber die AfD an der Macht sähen.

Crawler oder Heuschreckenplage

git.kernel.org hosted git-Repos für den Linux-Kernel, insbesondere auch das Repo des Linux-Kernels. Es gibt auch eine dynamisch gerenderte Website, die z.B. den Inhalt der commits in einem Repo anzeigen kann.

Und diese Seite hat jetzt ein Problem: Web-Crawler laden automatisch alle diese Seiten herunter, um damit LLMs zu trainieren. Das lastet im Schnitt 14 Prozessorkerne komplett aus. Das sind 20 % der Kapazität der Seite (über den Globus verteilt), aber im Durchschnitt. Die Anfragen kommen immer in Spikes. Und üblicherweise sind die Server auch nicht an der Belastungsgrenze, im Schnitt ist also mehr als die Hälfte der Last von Crawlern generiert.

Lest euch den Artikel durch, der ist interessant. Mir sind vor allem zwei Punkte aufgefallen:

  1. Diese Crawler ignorieren die robots.txt. Früher haben sich praktisch alle größeren Crawler (von Suchmaschinen wie Google) an die Anweisungen darin gehalten. Das war so eine Art Abmachung: „Ihr lasst uns euch crawlen, wir nehmen euch dafür in unseren Suchindex auf und versprechen, nicht zu viel Last zu erzeugen.“. Die Crawler für LLMs halten sich nicht an die robots.txt und geben sich auch wirklich Mühe, alle anderen Schutzmaßnahmen zu umgehen. Ob das legal ist, ist fragwürdig.
  2. Die Crawler erzeugen um Größenordnungen mehr Last als notwendig. Sie könnten effizient das git-Repo des Kernels und eventuell noch andere Repos klonen und dann offline durch die commits durchgehen. Das ist sowohl für git.kernel.org viel effizienter, wäre aber auch für die Crawler effizienter, insbesondere weil sie dann nicht mehr Rechenzeit darauf verschwenden müssten, ständig proof-of-work-captchas zu berechnen. Stattdessen werden Millionen bis potentiell Milliarden von HTML-Seiten gecrawled, die alle dynamisch gerendert werden müssen.

Und das ist nicht die einzige Seite, die dieses Problem hat, ich habe das schon von anderen Seiten gelesen. Das kostet alles Strom, Leistung, und geht am Ende auf die Kosten von uns allen, weil Seiten aufgeben, weil Geld in Infrastruktur investiert wird, das man sonst woanders für hätte verwenden können und weil normale Benutzer jetzt bei jedem Besuch von git.kernel.org ein paar Sekunden warten müssen, bis der Browser den proof-of-work erbracht hat, der die Bots abhalten soll.

Und für was? Damit ein paar milliardenschwere Konzerne uns ihre LLMs verkaufen können, die auf die Kosten von freien Projekten trainiert wurden. Ich sehe ja schon, dass LLMs eine Technologie ist, die nicht mehr verschwinden wird. Auf die eine oder andere Art wird diese Technologie bleiben. Die Frage ist nur: auf welche Art wollen wir, dass sie bleibt? Der bisherige Weg ist nicht nachhaltig, weder was das Sammeln von Trainingsdaten angeht, noch welche ökologischen Auswirkungen die Rechenzentren haben, die für den Betrieb gebaut werden, noch was das Geschäftsmodell der Betreiber angeht (die Momentan mit jeder Anfrage Verlust machen).

Momentan kann ich jedenfalls LLMs nicht reinen Gewissens benutzen.