Stranger Than Usual

I also apologize in advance for the lack of metric units in this video. Yes, imperial units are ridiculous, but we're talking about America here so get prepared for feet, gallons and diet coke hamburgers per bald eagle.

Not Just Bikes

Unbelievable Shitshow of America

Es kommt ja gerade wieder Schlag auf Schlag. Nicht nur aus den USA. Ich kann nicht zu jedem Thema etwas schreiben, zu dem ich etwas zu sagen habe und ich habe nicht zu jedem Thema etwas Sinnvolles zu sagen, zu dem ich schreibe. Aber schauen wir uns mal ganz kurz die USA an.

Zum Einen scheint Trump gerade wütend auf Putin zu sein. Hat er es endlich eingesehen? Wenn ich auf Trumps bisheriges Verhalten sehe, dann nein. Trumps aufgeblasenes Ego kann einfach nicht damit ab, dass jemand auf seine Deals nicht eingeht. Das gleiche Verhalten zeigt er auch bei Verhandlungen mit Kanada, Europa, Mexiko und eigentlich allem und jedem. Wenn es nicht genau nach seinem Willen geht verhält er sich wie ein Kleinkind, schreit herum und beleidigt seine Gegner. Das bedeutet nicht, dass er jetzt endlich verstanden hat, worum es in der Ukraine geht. Es wurde einfach nur sein Ego verletzt.

Die beiden anderen Nachrichten sind besorgniserregender: Erstens: Trump schließt nicht aus, Grönland militärisch zu übernehmen. Genauer gesagt: Er ist sich zu 100% sicher, dass er Grönland bekommen wird, diplomatisch wenn möglich, militärisch wenn nötig. Formulieren wir das mal anders: Der Präsident der USA droht Dänemark mit Krieg, wenn die nicht Grönland an ihn abtreten.. Das ist es. Unbeschönigt. Trump droht einem NATO-Bündnispartner mit Krieg, wenn der ihm nicht eine Insel überlässt. Argumentiert das mit Sicherheit, obwohl die USA schon Militärbasen auf Grönland haben.

Die andere Nachricht: Trump spekuliert über Möglichkeiten, eine dritte Amtszeit als Präsident zu bekommen. In den USA dürfen Präsidenten nur zwei Amtszeiten haben (sollten wir bei uns für die Bundeskanzlerin auch mal einführen). Und Trump kokettiert jetzt öffentlich mit dem Gedanken. Zitat: „No, no, I’m not joking. I’m not joking“.

Ich könnte jetzt versuchen, das abzumildern. „Er spielt ja nur mit dem Gedanken“, „Er hat ja nicht gesagt, dass er es macht.“. Ok, dann bringen wir das mal in den Kontext seines Wahlkampfes in 2020: Hier ist er der Frage ausgewichen, ob der eine Wahlniederlage akzeptieren würde. Er hat nie explizit gesagt, dass er eine Wahlniederlage nicht akzeptieren würde. Er hat „nur“ gesagt, dass er nur verlieren kann, wenn die Wahl gefälscht werde, dass die Wahl vor Gerichten entschieden würde oder hat einfach abgelenkt.

Kein einziges Mal hat er gesagt, dass er eine Niederlage nicht akzeptieren würde. Aber genau das ist passiert. Am 6. Januar 2021 hat er seine Anhänger zu einem Sturm auf das Kapitol aufgehetzt um die formelle Bestätigung von Bidens Wahlsieg zu verhindern.

Trump wird Grönland angreifen, wenn ihn niemand davon abhält. Und Trump wird eine dritte Amtszeit anstreben, wenn ihn niemand davon abhält. Das sollten wir und insbesondere unsere Politiker im Kopf haben, wenn wir mit Trump verhandeln.

Scheibenwelt-Webarchäologie

Vor ein paar Jahren habe ich von einem damaligen Kollegen einige alte Scheibenweltbücher übernommen. Der Kollege brauchte Platz, ich ich habe ihm die Bücher abgenommen, die ich noch nicht hatte (obwohl ich sie schon gelesen habe).

Darunter auch eine englische Ausgabe von The Truth aus dem Jahr 2001. Neulich habe ich dieses Buch noch einmal gelesen. Auf der letzten Seite war noch eine Anzeige für „the discworld fanzine The Wizard's Knob“. Das schien ein gedrucktes Werk zu sein, jedenfalls sollte man dafür der Autorin einen Briefumschlag zuschicken.

Viel interessanter ist, dass darunter auch eine Web-Adresse steht: 'http://fly.to/discworld'. Nun, das ist interessant. 2001 war, was das Web anging, eine andere Welt. Die Dotcom-Blase war im Jahr davor geplatzt. Das Web war trotzdem immer noch neu und shiny, und mit der geplatzten Investitionsblase war der Hype-Zyklus vermutlich gerade irgendwo zwischen dem „Tal der Enttäuschung“ und dem „Plateau der Produktivität“. Das Web war nicht mehr komplett jung und unschuldig, aber es war eine Zeit vor den sozialen Medien, bevor große Konzerne den größten Teil des Internets beherrschten (es war auch eine Zeit, in der mit HTTPS gesicherte Verbindung eine absolute Seltenheit waren).

fly.to war damals, so wie es aussieht, ein URL-shortener. http:/fly.to/discworld leitete auf diese GeoCities-Seite weiter.

GeoCities war damals ein Freehoster, wo man kostenlos (statische) Websites hochladen konnte. Wie gesagt, das war vor Facebook, und auch noch vor Myspace. Wenn man günstig eine eigene Website haben wollte, ging man halt zu GeoCities. Ich weiß, das klingt jetzt ein bisschen romantisierend, aber damals gab es mehr (auch technisch nicht so versierte Leute), die sich einfach mal eine eigene Website gebastelt haben. Heute gehen halt alle zu einem der großen Anbieter, machen sich da einen Account, laden ihren Krams hoch. Das ist bequemer, hat aber nicht den Charme einer selbst zusammengeschusteter Website.

Die Qualität der Websites auf GeoCities war dementsprechend durchwachsen. Ein Klassiker war ein gelb-schwarzes „this site is under construction“-Banner, dass auf vielen Seiten zeitweise (auf manchen auch dauerhaft) zu sehen war. Das Webdesign war… naja, das Webdesign des frühen Internets halt. Und GeoCities halt halt auf den Seiten Werbung eingeblendet, um das ganze zu finanzieren (das war noch die alte Internetwerbung, nicht personalisiert).

Die Scheibenweltseite hat kein „under construction“-Banner. Allerdings ist das Design ziemlich genau das, was man vom Web in dieser Zeit erwarten würde. gekachelte Hintergrundbilder, komisches Layout (schaut es euch an!), eine Landing-page die nicht viel aussagt, aber Terry Pratchett auf einem Motorrad zeigt und ansonsten nur einen Link zum eigentlichen Inhalt anbietet.

Die Seite ist eine umfangreiche Fanpage zur Scheibenwelt im Speziellen und zu Terry Pratchett im Allgemeinen. In mir persönlich weckt sie Nostalgie. Damals habe ich selber gerade angefangen, im Web zu surfen (gefühlt recht spät, muss ich sagen). Das Web war ein anderes damals. Viel davon ist natürlich durch die Nostalgiebrille verklärt, aber es gab wirklich einige Aspekte, die schöner waren. Zum Beispiel viel mehr kleine Fanseiten wie diese (von denen einige auch auf der Seite verlinkt sind). Weniger riesige Techkonzerne, die den größten Teil des Internets kontrollieren.

Davon geblieben ist nicht viel. GeoCities wurde irgendwann eingestellt, die Seiten von damals sind nur noch in Archiven zu finden. 'fly.to' macht heute Werbekampagnen und ist kein URL-Kürzer mehr (PSA: vermeidet URL-Kürzer! Das sorgt nur dafür, dass eure Links irgendwann kaputt gehen, so wie dieses Jahr Googles URL-Kürzer). Alles, was noch auf diese Scheibenwelt-Fansite hinweist ist eine gedruckte URL in einem über zwanzig Jahre alten Buch.

Papier überlebt länger als viele Dinge im Web. Vielleicht sollte uns das zu denken geben, wie viel von unserer Gegenwartskultur für die Nachwelt erhalten bleibt. Papier ist geduldig. Digitale Daten sind auf so vielen Ebenen flüchtiger. Denkt daran, wenn ihr irgendwo Daten hinterlegt, von denen ihr wollt, dass sie erhalten bleiben.

Links und Landkarten

Eigentlich müsste der Titel „Links und eine Weltkarte“ sein, aber ich mag Alliterationen. In der Anfang Februar erschienenen Folge des Podcasts Irmimi (Irgendwas mit Mittelalter) von Katrin Stupp ging es um die Ebstorfer Weltkarte, einer Weltkarte aus dem 13. oder 14. Jahrhundert. Die Karte ist groß (etwa 3,57m Durchmesser), das Original wurde im zweiten Weltkrieg zerstört (es wurden danach Faksimilia angefertigt). Hört euch für mehr Details die Folge an.

Nun ist in den Shownotes der Folge auch eine digitale Ansicht der Karte im Museum Lüneburg. Anfang Februar muss der noch funktioniert haben. Als ich die Folge am 22.3.2025 angehört und mir danach die Karte anschauen wollte, kriegte ich von der Museumsseite einen 404-Fehler. Der Text auf der Website:

Es tut uns leid, die von Ihnen gesuchte Seite ist nicht verfügbar! Derzeit arbeiten wir an unserer neuen Webpräsentation. Seien Sie gespannt!

Ich glaube, den Leuten ist nicht bewusst, was sie alles zerstören, wenn sie ihre URLs ändern. Es ist möglich, eine neue Webpräsenz einzurichten, ohne alle Links zu zerstören, die auf die alte Seite zeigen. Damit macht man das Web kaputt. Die Stärke des Webs sind Links. Wenn man Links unbrauchbar macht, macht man das Netz kaputt. Das erzeugt Frustration bei Benutzern, die den Inhalt, der verlinkt ist, nicht mehr finden, und bei den Websitebetreibern, weil die Nutzer nicht mehr zu ihnen kommen. Wie das W3C schon geschrieben hat: Cool URIs don't change.

Lilith Wittmann vs. Online-Casinos

Meine Lieblingskrawallinfluenzerin/Hackerin Lilith Wittman hat mal wieder zugeschlagen. Sie hat ja ein Talent dafür, ungesicherte Datenschnittstellen zu finden. Dieses Mal hat sie festgestellt, dass die Merkur-AG, die Online-Casinos betreiben, ihre Spielerdaten ungesichert im Netz stehen hatten. Lest es euch selbst durch. Auch auf heise.de hat sie dazu ein Interview gegeben.

Nebenbei hat sie auch herausgefunden, dass Töchter der Merkur-AG illegale Online-Casinos betreiben. Und dass die Schnittstelle für Ein- bzw. Auszahlungen auf Benutzerkonten auch nicht gesichert ist. Eigentlich sollten zumindest AUszahlungen noch einmal manuell geprüft werden, aber auch das wird nicht ordentlich gemacht, und so hat Lilith Wittmann aus Versehen 200€ von einem illegalen Casino abgebucht und weiß jetzt nicht, wie sie die zurückgeben soll.

Auch nicht in Ordnung

Vor ein paar Wochen habe ich einen Artikel geschrieben, in dem es darum ging, dass manche Sachen nicht normal, nicht akzeptabel und nicht in Ordnung sind, auch wenn sie gerade überall passieren, und viele Leute das einfach so hinnehmen.

Die Idee dahinter war, dass wir an dem Gedanken festhalten müssen, dass diese Dinge nicht in Ordnung sind und wir uns nicht daran gewöhnen dürfen.

Die komplette Liste ist leider sehr lang, was dabei hilft, unakzeptable Dinge einfach zu vergessen. Hier nur ein paar aktuelle Dinge zum Thema Gewaltenteilung:

Zusammengefasst: Es ist, sehr milde ausgedrückt, nicht normal und nicht in Ordnung, sämtliche Gewalten außer der Exekutive zu demontieren. So etwas hatten (und haben) wir weltweit genug. Das nennt sich Diktatur.

PS: Hier noch ein paar andere, weniger weltbewegende Sachen, die auch nicht in Ordnung und nicht akzeptabel sind:

  • Menschen mit Visa an der Grenze festzuhalten, zu foltern und auszuweisen
  • Menschen ohne Visa an der Grenze festzuhalten, zu foltern und auszuweisen
  • Menschen in ein auszuweisen, in denen ihnen der Tod droht, sei es aus Hunger order politischer Verfolgung
  • Menschen zu deportieren, die jahrelang in einem Land gelebt haben
  • Geflüchtete wie Menschen zweiter Klasse zu behandeln und sie jahrelang unter schlechtesten Bedingungen in irgendwelche Camps zu sperren
  • und im weitesten Sinne: überhaupt Menschen zu deportieren, auszuweisen oder aufzuhalten, nur weil sie auf der falschen Seite einer imaginären Linie geboren wurden.

Terry Pratchett

Heute vor zehn Jahren ist Terry Pratchett gestorben. Seine Bücher, allen voran die Scheibenweltromane, haben mich sehr geprägt. Ich kann nicht glauben, dass das schon zehn Jahre her ist. Damals hatte ich gerade meinen ersten Vollzeitjob in Hamburg angefangen.

Heute haben einige Fans an GNU Terry Pratchett erinnert. In eigener Sacht möchte ich darauf hinweisen, dass dieses Blog seit fast zehn Jahren GNU Terry Pratchett-kompatibel ist.

Golang

Neulich hat mich ein Vereinskamerad aus dem Kanuklub nach meiner Meinung zur Programmiersprache Go gefragt. Ich habe da nur kurz antworten können, weil ich weg musste, aber mir sind so viele Sachen eingefallen, dass ich hier noch etwas dazu schreiben möchte.

Zunächst erst einmal: Ich habe gemischte Gefühle zu Go, und die Gründe dafür werden sich hier durch den ganzen Blogpost ziehen. Ich habe mich Ende 2014 zum ersten Mal mit Go beschäftigt, und war damals begeistert. Kurze Zeit später wurde Go bei mir aber von Rust verdrängt.

Ich habe seitdem in verschiedenen Programmiersprachen gearbeitet, auch beruflich, und ich kann sagen, dass ich Go immer noch vielen Sprachen vorziehen würde, darunter Java, Javascript, je nach Anwendungsfall Python oder C oder C++ und in jedem Fall PHP (in den meisten Fällen würde ich allerdings dann eher in Rust schreiben als in Go). Aber schlüsseln wir das mal auf.

Die Grundkonzepte

Go ist typsicher und kompiliert, viele Fehler fallen deshalb schon beim kompilieren auf. Go hat einen Garbage Collector und keine externe runtime, dafür sind Go-binaries schnell ein paar Megabyte groß. Go lässt sich gut in Container (z.B. Docker) verpacken, und zwar minimale Container, die nichts enthalten außer der Go-Binary.

Besonders an Go ist, wie selbstverständlich nebenläufige Programmierung in die Sprache eingebettet ist. Goroutinen sind leichtgewichtig zu starten (anders als Threads in den meisten anderen Sprachen), channels ermöglichen Kommunikation zwischen Goroutinen ohne mit Locks herumhantieren zu müssen (die gibt es auch, für Spezialfälle).

Go hat eine umfangreiche Standardbibliothek, so kann man zum Beispiel ohne externe Abhängigkeiten einen Webserver aufsetzen, inklusive HTML-Templates und JSON-Serialisierung/Deserialiserung von und in Go-structs.

Tooling

Go hat schon standardmäßig einiges an Tools. Da ist zum Beispiel gofmt, um Quellcode zu formatieren. gofmt ist opinionated, hat also genaue Vorstellungen davon, wie gut formatierter Code auszusehen hat und lässt sich nur schwer davon abbringen. Ich zähle das als positiven Aspekt. Dadurch hat jedes Go-Projekt die gleiche Formatierung. Klar, die gefällt mir nicht an allen Stellen, aber ich muss keine Energie darauf verschwenden, mir Gedanken darüber zu machen.

Go hat keinen eigenen Paketmanager. Abhängigkeiten werden üblicherweise über Git-Repos geladen. Lange hatte Go auch keine Möglichkeit, explizit Abhänigkeiten anzugeben, man musste alle zum Projekt gehörigen Sachen in einem Pfad haben, den man durch die Umgebungsvariable $GOPATH definiert hatte. Das war umständlich und fehleranfällig. Seit einigen Jahren gibt es Modules, die den Umgang mit Projekten, Abhängigkeiten und deren Versionen vereinfachen.

Tools für automatische Tests (insbesondere unit tests) sind auch von Haus aus mitgeliefert und bieten ein paar Komfortfunktionen, es gibt also keine Ausrede, keine Tests zu schreiben.

Error-Handling

Go hat kein System von Exceptions. Jede Funktion kann mehrere Rückgabewerte haben, Funktionen, die Fehler erzeugen können, geben einfach neben dem eigentlichen Rückgabewert noch einen Fehlertyp zurück. Wenn es keinen Fehler gab, ist der nil.

Dadurch vermeidet man eine ganze Reihe von Problemen, die man mit Exceptions hat. Insbesondere kann man direkt sehen, in welcher aufgerufenen Funktion ein Fehler auftreten kann und wie damit umgegangen wird.

Der Nachteil ist, dass Errorhandling in Go sehr verbose ist. Man hat praktisch immer ein

a, err := foo
if err != nil {
    return err
}
// [Erfolgsfall]

In Rust zum Beispiel gibt es für dieses Konstrukt ein Kürzel. Außerdem ist es in Go recht einfach, den Fehlerfall aus Versehen zu übergehen und mit dem anderen Rückgabewert weiterzuarbeiten. In dem steht aber im Fehlerfall üblicherweise nur Müll. Das kann zu den lustigsten Fehlern führen. Alles schon erlebt.

Eine weitere Schwäche hier ist, dass man üblicherweise nur den Typ error zurückgibt. Das ist alles was ein error-Interface implementiert. Man kann also nur sehr umständlich herausfinden, welcher Error jetzt speziell gerade zurückgegeben wurde. Wenn man je nach Fehlertyp unterschiedlich handeln will, muss man eine Menge Extracode schreiben.

Für schwerwiegende Fehler, mit denen das Programm nicht umgehen kann (z.B. Division durch 0) gibt es auch noch panic. Das funktioniert ähnlich wie in rust und ist prinzipiell erst einmal nicht recoverable. Man sollte also vermeiden, dass es ein panic gibt.

Typsystem

Das Typsystem von Go ist erst einmal nicht schlecht. Man hat strikte Typisierung, einen Haufen grundlegender Typen und kann mithilfe von struct neue Typen definieren. Vererbung, virtuelle Funktionen und dergleichen gibt es nicht. Das verbuche ich auch positiv. Interfaces gibt es schon, also kann man wenn nötig eine gewisse, nützliche aber harmlose Art von Polymorphie haben.

Aber es gibt eine ganze Menge an Dingen, die ich an dem Typsystem auszusetzen habe.

The Billion Dollar Mistake

Es gibt in Go auch pointer (die immerhin memory-safe sind). Aber diese Pointer können auch nil sein (null oder None in anderen Sprachen). Es gibt keine nonnull-pointer. Mit anderen Worten: Überall, wo man Pointer verwendet (manchmal kommt man nicht darum herum) muss man überprüfen, ob der Pointer nil ist.

Außerdem werden hier zwei semantische Konzepte vermischt: Auf der einen Seite das Konzept der Referenz: Ein Wert, der auf einen anderen Wert verweist. Auf der anderen Seite das Konzept der Optionalität: Ein Wert, der entweder da ist oder eben nicht. Vielleicht möchte ich auch ein nicht-Referenz, die Optional ist. Oder eine Referenz, die nicht optional ist. Geht nicht.

Erschwerend kommt noch hinzu, dass nicht alle nil-Werte gleich sind und man beim Vergleichen zweier nil-Werte ein false bekommt.

Oh, aufgrund einiger komischer Zusammenhänge (s.u. unter „Nerviges“) ist nil eine leere slice und man kann Sachen dranhägen. Für Wörterbücher gibt das hingegen einen Fehler.

Default-Werte

Uninitialisiere Variablen sind gefährlich, also hat Go sich das Konzept der Defaultwerte ausgedacht. Das ist z.B. 0 für Integer-Typen, false für boolean, der leere String für Strings usw. Structs werden per default mit den Defaultwerten ihrer Member initialisiert.

Das führt dann zu Problemen, wenn man einem struct einen neuen Member hinzufügt. Wenn man dann nicht alle Stellen anpasst, an denen dieses Struct initialisiert wird, wird einen der Compiler nicht warnen und stattdessen dort einfach den Defaultwert reinschreiben. Versucht mal, den Fehler zu finden.

Array-Slices werden per default mit nil initialisiert, aber das ist eigentlich kein Problem, weil man trotzdem noch Sachen dranhängen oder die Länge abfragen kann. Lustigerweise gilt das für map (ein Wörtberbuch) aber nicht: Das wird standardmäßig mit nil initialisiert und jede Interaktion damit führt zu einer panic.

Ein weiterer Punkt, wo die Default-Werte nervig sind, ist beim Deserialisieren von JSON: Wenn ein Feld in dem Struct, in das deserialisiert wird, nichtim JSON vorkommt, wird es einfach auf den Defaultwert gesetzt. Ich habe da schon die lustigsten Probleme mit gehabt:

Fall 1: Wert ist verpflichtend, Aufrufer vergisst ihn

In diesem Fall wird einfach angenommen, der Aufrufer hätte eine 0 oder so angegeben. Besser wäre hier, dem Aufrufer einen Fehler zurückzugeben.

Fall 2: Wert ist optional, ist aber im struct nicht als pointer definiert

In diesem Fall muss man hoffen, dass der Defaultwert kein gültiger Wert ist. Ich habe schon einmal Code gesehen, der immer eine leere Liste zurückgegeben hat, weil der optionale Wert so etwas wie max_results war, mit dem man angeben konnte, ob die Anzahl der Ergebnisse beschränkt sein soll.

Wenn der Defaultwert kein gültiger Wert ist, kann man natürlich einfach dagegen testen. Schön ist das aber nicht

Fall 3: Wert ist optional, ist im struct als pointer definiert

Für die Schnittstelle ist hier alles fein. Fehlt der Wert im JSON, ist der Wert im struct nil und man weiß, dass er nicht da ist.

Lustig wird es, wenn man in einem Struct einen Pointer auf einen primitiven Typ hat und dann versucht, das Struct zu initialisieren. Geht nicht ohne weiteres, weil man keinen Pointer auf z.B. ein uint32-Literal machen kann. Man muss zuerst eine gesonderte Variable anlegen und kann dann per Pointer darauf verweisen.

Meiner Meinung nach schaden Default-Werte also mehr als sie nützen und sind insbesondere in der Kombination mit nil-Werten bzw. mit den fehlenden Optional-Typen nervig.

Immutability

Es gibt keine gute Möglichkeit, Werte in Go immutable zu machen. Man kann immer alles überschreiben. Die einzige Lösung wäre, in einem Struct alle Member private zu machen und jede Menge Get-Funktionen zu schreiben. Macht aber keiner, weil es jede Menge Boilerplate erzeugt und wir ja gerade von Java wegwollen.

Generics

Lange Zeit gab es in Go keine Generics. Die Begründung war immer, dass man die ja nicht so dringend braucht. Auch mein ehemaliger Chef, ein großer Go-Fan, fragte immer: „Wann habt ihr das letzte mal etwas geschrieben, wo ihr Generics gebraucht habt?“.

Klingt nach einem fairen Punkt, verfehlt aber das Problem: Wenn man Anwendungen schreibt, braucht man meist keine Generics. Wenn man Bibliotheken schreibt sind sie hingegen oft sehr, sehr nützlich. Ein anderes Team in meiner alten Firma hatte dann eine Bibliothek benutzt, die einen fucking Code Generator dabei hatte, um typisierte Go-Dateien zu erzeugen. Lächerlich.

Und die Bibliotheken wird man früher oder später brauchen, wenn einem auffällt, dass man mit Arrays und Wörtberbüchern zwar sehr weit kommt, es aber immer Fälle geben wird, in denen man Containertypen braucht, die nicht in der Standardbibliothek drin sind (außer in Rust, an dieser Front ist Rust wesentlich besser aufgestellt als Go).

Nerviges

Ein paar Dinge sind keine große Sache, nerven mich aber doch ein bisschen. Da wäre zunächst:

Privacy

Wie manche andere Sprache auch hat Go ein Konzept von privaten Werten und Funktionen. An sich finde ich die Implementierung ganz nett: Innerhalb eines Moduls kann man auf alles zugreifen, was dort definiert ist, außerhalb nur auf die öffentlichen Sachen.

Was mich ein bisschen nervt ist, wie private Werte deklariert werden: Großbuchstabe am Anfang? Public. Kleinbuchstabe? Private.

Datums-/Zeitformatierung

Die meisten Sprachen bzw. Datumsbibliotheken von Sprachen haben eine Funktion, mit der man ein Datum in ein Textformat bringen kann. Die haben dann abstrakte Platzhalter, z.B. %m für den Monat. Golang hat einen anderen Weg genommen. In Golang gibt es ein Referenzdatum (in einem sehr ungewöhnlichen Format noch dazu): 01/02 03:04:05PM '06 -0700".

Ein Datumsformatstring muss dann die richtigen Zahlen aus diesem Datum zusammenpicken, ggf. noch auf eine 24-Stundenanzeige umrechenen und eingeben. Ein RFC3339-Datum sähe dann zum Beispiel so aus: 2006-01-02T15:04:05Z07:00.

Ich kann mir denken, was der Gedanke dahinter war: Hey, dann kann man direkt sehen wie das Datum am Ende aussieht. Praktisch gesehen ist das aber nicht der Fall. Wie soll ich mir merken können, ob 01 jetzt der Monat oder der Tag ist? Wie soll ich mir die ganzen anderen Zahlen merken können. Ich muss jedes Mal nachschauen, was denn jetzt das Referenzdatum ist.

arrays und slices

Go hat Arrays, die eine feste größe haben und slices, die auf einen Ausschnitt eines Arrays zeigen und Funktionen haben, mit denen man sie wachsen lassen kann. Für ein slice s kann ich also folgendes machen:

s = append(s, 4)

So wird der Wert 4 an das Slice angehängt. Leicht ungewöhnliche Syntax, aber daran könnte ich mich gewöhnen, wenn es wenigstens konsistent mit irgendeinem anderen Kontrukt in der Sprache wäre.

Wirklich fies wird es aber erst, wenn man mehrere Referenzen auf die slice hat. Sollte bei append das der Slice zugrundeliegende Array nicht groß genug sein, wird ein neues allokiert, die Daten aus dem alten rüberkopiert und der neue Wert hinzugefügt. Ansonsten wird nur der neue Wert hinzugefügt.

Preisfrage: Wenn man jetzt mehrere Referenzen hat, was passiert dann mit der alten Slice? Wenn ich in der jetzt etwas ändere (ein Feld ander zuweise), ändert sich dann die neue slice auch?

Die Antwort ist: Kann man nicht sagen. Das hängt davon ab, ob ein neues Array allokiert wurde. Wenn nein, dann ändert man auch die neue slice. Wenn doch, dann bleibt das neue slice unbehelligt.

Die einzige Lösung ist also: auf keinen Fall mehrere Referenzen auf dieselbe slice.

Kein map/filter/reduce

Was ich in Rust ja sehr schön finde ist die umfangreiche Sammlung von Funktionen, die man auf Iteratoren durchführen kann. Golang hat so etwas nicht. Keine map()- Funktion, kein filter(), kein reduce(). Aber hey, vielleicht kann man das ja per Bibliothek dazuladen?

Mittlerweile vielleicht. Lange Zeit ging das nicht oder nur mit erhöhtem Aufwand, denn es gab ja keine Generics.

Tiefe Kopien

Es gibt keine einfache Möglichkeit in Go, tiefe Kopien von etwas zu erstellen. Das habe ich schon on Java gehasst. In C++ geht es immerhin halbwegs einfach (mit ein bisschen Handarbeit in manchen Fällen), in Rust ist es trivial.

Unicode-Handling

Go-Quellcodedateien sind strikt UTF-8. Strings in Go… sind eigentlich nur unveränderbare uint8-Arrays. Man kann praktisch jeden Müll dort hereinschreiben. Klar, es gibt Funktionen um auf gültiges UTF-8 zu testen. Die meisten anderen Entwickler nutzen sie nur nicht und sind sich nicht einmal des Problems bewusst.

The Ugly

An meinem ehemaligen Job gab es im Slack im #Go-Channel immer ein schönes Spiel. Irgendein Kollege hat ein Stück Go-Code geposted, das ganz harmlos aussah und gefragt: „Was gibt dieser Code hier aus?“.

Worauf ich hinaus will: Go hat einige wirklich fiese Gotchas. Keine Speicherkorruption, so weit sind wir hier nicht, aber einige Sachen, die in Rust definitiv nicht möglich sind, aber auch in vielen anderen Sprachen wie z.B. Java oder Python. Hier ein Beispiel (für Go-Versionen vor 1.22):

func main() {
	f := make([]func(), 5)
    for i := 0; i < 5; i++ {
        f[i] = func() {
            fmt.Println(i)
        }
    }
    for _, f := range f {
        f()
    }
}

Was gibt der Code aus? 55555. Warum? Nun, die Variable i wird in der closure eingefangen. In der for-Schleife wird sie aber weiter hochgezählt. In den meisten Sprachen würde man davon ausgehen, dass hier der Wert in die Closure kopiert wird. Wird er aber nicht. Es wird die Variable eingefangen. Wenn die Closures dann nach Ablauf der Schleife ausgeführt werden, ist i überall auf 5.

Das Verhalten wurde glücklicherweise in Version 1.22 geändert (was ich bis vorhin nicht wusste). Bis dahin mussten wir uns immer auf zusätzliche Linter verlassen, die uns davor gewarnt haben.

Unglücklicherweise habe ich keinen Zugriff mehr auf die ganzen anderen Gotchas aus dem Slack-Channel. Ich vermute mal, dass einige andere auch durch diese Änderung behoben wurden. Trotzdem… dass es so lange gebraucht hat dafür, ist ein schlechtes Zeichen.

Fazit

Ich bevorzuge Rust gegenüber Go in fast allen Fällen. Die Sicherheiten, die mir Rust bietet, vermisse ich in Go einfach zu sehr. Trotzdem würde ich weitaus lieber in Go schreiben als zurück zu Java zu gehen. Und ich kann nicht leugnen, dass es in Go viel einfacher ist, einen kleinen Webserver aufzusetzen als in Rust. Für Rust muss man einen Haufen Abhängigkeiten installieren. Für Go… nichts.

Support zum Kundenverjagen

Gestern habe ich eine Werbepostkarte von der deutschen Bahn bekommen. Ich will keine Werbung bekommen, also wollte ich die mal eben abbestellen. Glücklicherweise ist der Weg dazu auf der Postkarte aufgedruckt:

Wenn Sie künftig unsere Informationen und Angebote nicht mehr per Post erhalten möchten, kontaktieren Sie uns bitte über das Kontaktformular auf bahn.de/kontaktformular

Also bin ich auf bahn.de/kontaktformular gegangen und wurde direkt weitergeleitet zu bahn.de/hilfe#. Die Überschrift ist „Hilfe & Kontakt“, die Unterberschrift „Hier finden Sie Informationen, Links zu unseren Self-Services und Kontaktformulare.“

Einen DRECK habe ich gefunden. Es gab einige Unterthemen zu Hilfe mit jeweils einigen Unterunterthemen. Keins davon hatte in irgendeiner Weise mit unerwünschter Werbung zu tun. Es gab kein einziges Kontaktformular irgendeiner Art.

Es gab ein Suchfenster. Die Suche ergab auch keine hilfreichen Ergebnisse, die meisten Ergebnisse hatten nicht einmal mit Hilfethemen zu tun.

Darunter war ein Link zu einer Seite mit Telefonnummern. Ich habe also die Supportnummer angerufen. Dort wurden mir erst zwei Mal sämtliche Optionen vorgelesen , von denen keine zu dem passte, was ich wollte. Dann kam die Ansage, dass ich fünf Minuten warten müsse (immerhin keine 15 Minuten). Dann kam die Durchsage, dass einige dieser Anrufe aus Qualitätssicherungsgründen aufgezeichnet werden. Diese Ansage wurde unterbrochen von einer anderen Ansage, dass einige dieser Anrufe aus Qualitätssicherungsgründen aufgezeichnet würden und ich die 1 pressen soll, um das zu bestätigen. ALLES WÄHREND ABSOLUT NERVIGE, KLIRRENDE WARTEMUSIK GESPIELT WURDE. Dann kam ein Mensch in die Leitung.

Dem habe ich mein Anliegen erklärt. Der konnte mir nicht helfen, hat mir aber eine E-Mail-Adresse genannt, an die ich mich wenden soll: fahrkartenservice@bahn.de. Das habe ich dann gemacht. WARUM MAN DIESE ADRESSE NICHT DIREKT AUF DER HILFESEITE ANGEBEN KANN IST MIR UNKLAR.

Und das wirklich Schlimme ist: Das ist nicht das erste Mal, dass mir das passiert. Es ist bei größeren Unternehmen eher der Regelfall. Es ist nicht nur die Bahn. Microsoft zum Beispiel macht es auch so. Es wird dem Kunden möglichst schwer gemacht, irgendeinen Menschen zu kontaktieren, der dem Kunden dann das geben kann, was ihm von Recht aus zusteht. ICH HABE DIE SCHNAUZE VOLL!

Update 6.3.2025

Ich habe eine Antwort bekommen:

[…] vielen Dank für Ihre E-Mail.

Wir können Ihr Anliegen nicht bearbeiten.

Bitte wenden Sie sich an die Kollegen unter Telefonnummer: 0621 30 983-199

Mo.-Fr. 09:00 - 17:00 Uhr(außer 24.12., 31.12. und an Feiertagen)

oder per E-Mail: bahnshop@mycybergroup.com […]

Wollt ihr mich eigentlich verarschen? Euer eigener Support hat mir die Mailadresse geschickt. Könnt ihr das nicht wenigstens intern weiterleiten?

Nein, können sie natürlich nicht. Stattdessen soll ich mich an eine Mailadresse senden, die mycybergroup.com als Domain hat. Klingt total seriös und überhaupt nicht nach einem unterfinanzierten Startup, an das nervige Kunden abgewimmelt werden.

Passend zum Thema habe ich übrigens diesen sehr treffenden Comic gefunden.

Update 9.3.2025

mycybergroup.com hat sich gemeldet und mir nach ein paar Nachfragen gesagt, dass sie dafür nicht zuständig sind. Klingt plausibel. Das ist ja nicht die deutsche Bahn (anscheinend machen sie nur den Merchandise-Shop der DB). Als Ansprechpartner haben sie mir die Telefonnummer der DB angegeben, die ich ursprünglich angerufen habe wo mich die Person an fahrkartenservice@bahn.de verwiesen hat.

Also habe ich noch einmal diese E-Mail-Adresse angeschrieben und denen gesagt, dass mycybergroup nicht zuständig sei. Das war am Freitagvormittag, also vor zwei Tagen. Bisher keine Antwort.

Update 23.3.2025: Die Sache ist endlich geklärt

Nachdem ich eine Woche lang keine Antwort bekommen habe, habe ich die Mail am 16.3.2025 noch einmal abgeschickt. Vorgestern (21.3.2025) hat sich endlich etwas getan. Ich habe eine E-Mail von p.d-datenschutz@deutschebahn.com bekommen. An die wurde meine Anfrage intern weitergeleitet. Die haben mir gesagt, dass sie die Sache erledigt haben. Endlich. Für den Support würde ich die Schulnote 5 geben. Eine 6 ist es nur deswegen nicht geworden, weil ich am Ende doch noch zu meinem Recht gekommen bin.

Skype

Microsoft stellt Skype im Mai 2025 ein. Siehe dazu auch den Nachruf auf heise online.

Ich schaue da mit gemischten Gefühlen drauf. Auf der einen Seite habe ich selber Skype schon seit Jahren nicht mehr gestartet (aber immer noch installiert). Es ist, und war immer keine freie Software. Es wurde schlussendlich an Microsoft verkauft, und ich hatte damals Sorge, dass darunter der Linux-Client leiden würde.

Auf der anderen Seite war Skype halt einer der ersten verbreiteten Dienste, mit denen man einfach Audio- und Videocalls am Computer machen konnte. Und es hatte auch eine Instant-Messaging-Funktion. Als ich angefangen habe, Skype zu benutzen, lief die Popularität von ICQ langsam aus, also hatte ich viele Online-Kontakte über Skype. Es war einfach zu bedienen, und das Verb „skypen“ hat es sogar in den allgemeinen Wortschatz geschafft, so beherrschend war die Marktstellung.

Nach und nach haben andere Dienste Skype verdrängt, wie z.B. WhatsApp (benutzt es nicht!) oder Signal, oder Discord. Andere haben es versucht, aber nie geschafft (z.B. Jabber für Instant Messaging).

Was bleibt sind also einige Erinnerungen und einige Kuriositäten. So hatte z.B. Rupert Murdoch Skype verklagt, weil er meinte, das Markenrecht auf das Wort „Sky“ zu haben (dazu habe ich damals auch geschrieben. Die Ruhr-Universität Bochum hatte zu meiner Studienzeit die Anweisung herausgegeben, Skype auf Rechnern im Uninetz nicht immer im Hintergrund laufen zu lassen, sondern nur zweckgebunden zu starten, weil Skype-Instanzen, die länger liefen sich zu einer Art Hub entwickelten und eine Menge Traffic versursachten.

Am Ende bin ich froh, dass Sype weg ist, auch wenn ich einige Kontakte nur über Skype gepflegt habe. Leider ist nicht jeder Ersatz freie Software, am beliebtesten ist momentan Discord, und da kommt man an vielen Stellen leider nicht drum herum.

Nicht akzeptabel, nicht in Ordnung

Menschliche Wesen sind ungeheuer anpassungsfähig, und bis zur Mittagszeit hatte sich das Leben um Arthur Dents Haus herum bereits wieder normalisiert. Es war Arthurs allseits anerkannte Rolle, platschend im Matsch zu liegen […]; es war Mr. Prossers allseits anerkannte Rolle, Arthur ab und zu mit neuen Finten zu attackieren […].

Dieses Zitat stammt aus dem bemerkenswerten Buch Per Anhalter durch die Galaxis. Arthur Dent, der Protagonist, liegt vor seinem Haus im Matsch um einen Bulldozer daran zu hindern, sein Haus abzureißen. Eine außergewöhnliche Situation, aber wie das Zitat oben beschreibt, gewöhnen sich alle recht schnell daran.

Worauf will ich hinaus? Wir befinden uns politisch in den letzten Jahren auch in so einer Situation, in der Dinge normal werden, die vor ein paar Jahren noch undenkbar gewesen sind. Beispielsweise gab es vor einem Jahr noch riesige Demonstrationen gegen die AfD und andere rechte Akteure, weil sie eine Konferenz abgehalten haben, auf der sie die Abschiebung von Millionen von Deutschen forderten, die ihnen in irgendeiner Weise nicht deutsch genug waren. Dieses Jahr forderte Friedrich fucking Merz den Entzug der Staatsbürgerschaft für Straffällige.

Ich möchte hier daran erinnern, dass so etwas nur dadurch, dass es immer wiederholt wird und man sich langsam daran gewöhnt, nicht richtig wird. Und egal wie „normal“ etwas geworden ist, es ist weiterhin nicht aktzeptabel und nicht in Ordnung, z.B.

  • als Spitzenpolitiker Menschen das Demonstrationsrecht abzusprechen
  • als demokratisch gewähltes Staatsoberhaupt einer rechtsextremen (d.h. demokratiefeindlichen) Partei zu gratulieren, bei der Wahl im Nachbarland zweitstärkste Kraft geworden zu sein
  • der Hitlergruß zu zeigen, schon gar nicht auf einer öffentlichen Veranstaltung und erst recht nicht, wenn man der reichste Mensch der Welt ist
  • Menschen im Mittelmeer ertrinken lassen
  • die Zerstörung rechtsstaatlicher Institutionen als „Bürokratieabbau“ zu bezeichnen
  • die Existenz von Transmenschen zu leugnen

Das sind nur ein paar Beispiele aus den letzten Tagen. Es ist sehr wichtig, dass wir nicht vergessen, dass so etwas vor Kurzem noch nicht normal war, und dass es nur dadurch, dass es „normal“ geworden ist nicht richtiger oder akzeptabler wird.

Denn was wir hier beobachten ist eine Baseline, die verschoben wird. Das ist jetzt das neue Normal. Wir alle verwechseln „normal“ gerne mit „akzeptabel“ und „in Ordnung“. Gegen diese schleichende Akzeptanz müssen wir kämpfen. Und zwar, indem wir widersprechen, wenn jemand etwas nicht Akzeptables sagt. Indem wir diese neue Baseline zurückweisen, in unserem Kopf, aber auch nach außen hin. Wir lassen uns nicht stillschweigend in eine schlechtere, unmenschlichere und intolerantere Welt verschieben! Wir kämpfen dagegen!

Denn diese shifting baseline kann auch für gute Zwecke eingesetzt werden. Vor zwanzig Jahren waren Transgenderpersonen noch etwas ganz Unnormales. Vor zehn Jahren konnte man erkennen, wie die Gesellschaft langsam anfing, umzudenken. Heute sind Transmenschen normal, auch wenn einige reaktive Elemente versuchen das wieder zurückzudrehen.

Kämpfen wir also, indem wir gute, menschenfreundliche Gedanken laut aussprechen und menschenfeindlichen, demokratiefeindlichen Gedanken offen widersprechen. Sorgen wir dafür, dass wir ein „normal“ haben, in dem wir und wohl und sicher fühlen können!