Stranger Than Usual

I think programmers have become inured to incidental complexity… when they encounter complexity, they consider it a challenge to overcome, rather than an obstacle to remove. Overcoming complexity isn’t work, it’s waste.

Rich Hickey

Stupid Wednesday

Aus aktuellem Anlass hat tagesschau.de eine Auflistung der größten Börsencrashes seit 1929. Schauen wir uns doch mal polemisch an, was die Ursachen waren.

Börsencrash 1929 (Black Thursday / schwarzer Freitag): Zu viele Leute haben über Jahre zu hohe Kredite aufgenommen, die sie nicht zurückzahlen konnten. Als die Wirtschaft zusammenbrach konnten noch mehr Leute ihre Kredite nicht zurückzahlen.

Börsencrash 1987 (schwarzer Montag): Viele verschiedene Gründe, längerfristige Fehlplanungen, Fehlentscheidungen, verstärkt durch Computerisierung

Börsencrash 2000 (Platzen der Dotcom-Blase): Das Internet wurde gehyped, es hat sich eine Investitionsblase um alle Unternehmen gebildet, die irgendwas mit dem Internet machen, die Unternehmen waren aber bei weitem nicht so viel wert wie für die Aktien bezahlt wurde. Klassische Blase.

Weltfinanzkrise 2008: Banken über den ganzen Globus verteilt haben sich über Jahre hinweg verzockt bis das ganze zusammenbrach.

Wirtschaftskrise 2020/2021 (Covid-19-Pandemie): Globale Pandemie

Börsencrash 2025: Der Weltwirtschaft ging es ganz in Ordnung bis Donald Trump völlig willkürliche Zölle gegenüber praktisch allen bewohnten Ländern (und einigen unbewohnten Inseln) erhob.

Können wir uns darauf einigen, dass der letzte Crash hier dümmste Wirtschaftskrise ist, die wir bisher hatten? Praktisch alle anderen Weltwirtschaftskrisen entstanden, weil entweder zu viele Leute kleine bis mittlere Dummheiten begangen haben oder es einen unerwartete Katastrophe gab (z.B. Covid-19). Diese hier enstand, weil der Präsident der USA den Unterschied zwischen Handelsdefizit und Betrug nicht kennt, keine Ahnung hat wie Zölle funktionieren aber sie trotzdem nach dem Gießkannenprinzip verteilt.

Viele der Wirtschaftskrisen haben so dramatische Namen: „schwarzer Freitag“, „Tulpenmanie“, „Dotcom-Blase“… Ich finde, wir sollten der hier auch einen Namen geben. Angelehnt an John Olivers „Stupid Watergate“ nennen wir die hier „Stupid Wednesday“.

Zwei Studien zum Verkehr

Ich dumpe hier einfach mal Links zu zwei Studien hinein, hauptsächlich, damit ich die wiederfinde, wenn ich die mal zum Argumentieren brauche.

Zum einen ist da diese Pressemitteilung des deutschen Instituts für Urbanistik. Die haben sich einige Studien aus dem In- und Ausland angeschaut und festgestellt:

Die Analyse der empirischen Studien aus dem In- und Ausland zeigt, dass es keinen ursächlichen Zusammenhang zwischen Verkehrsberuhigungsmaßnahmen und einer wirtschaftlichen Schlechterstellung des Einzelhandels gibt.

Die Studien und Praxisberichte zeigen vielmehr: Ein attraktiver öffentlicher Raum zieht Menschen an, lädt zum Bummeln und Verweilen ein und kommt damit auch dem Einzelhandel zugute.

Das ist wichtig. Ich lese nämlich auf der einen Seite immer wieder Berichte, wie Einzelhändler gegen Radwege, Parkplatzabbau vor dem Laden oder ähnliches protestieren und auf der anderen Seite, wie froh Einzelhändler sind, dass diese Maßnahmen gemacht wurden, obwohl sie vorher dagegen waren. Bisher hatte ich da aber immer nur anekdotische Beweise. Jetzt habe ich etwas Konkretes, worauf ich hinweisen kann, wenn ich das nächste Mal von solchen Protesten höre (oder wenn die FDP mal wieder vorschlägt, Fußgängerzonen abzuschaffen).

Das andere ist eine Studie zum Deutschlandticket. Da steht u.a. drin:

  • das Deutschlandticket hat eine Verlagerung vom Autoverkehr auf den ÖPNV bewirkt
  • Deutschland dadurch eine ganze Menge Geld spart (wenn ich das richtig verstehe mehr, als den Staat das Ticket kostet)

Teil des Fazits:

Das Deutschlandticket kann ein wichtiger Impuls für die Verkehrswende sein, es ist aber nicht alleine in der Lage, die Verkehrswende herbeizuführen oder die Klimaziele zu erreichen. Dazu bedarf es weiterer Maßnahmen. Allerdings sind die Potenziale des Tickets noch nicht erschöpft. Der ab 1.1.2025 geltende höhere Preis (58 Euro) und die Unsicherheit über die Zukunft des Tickets unter einer neuen Bundesregierung bringen gleichzeitig das Risiko mit sich, dass die positiven Wirkungen überproportional verloren gehen, umso mehr, wenn eine verlässliche Weiterführung gefährdet erscheint und weiterhin starke Preiserhöhungen in Aussicht gestellt werden.

Mit anderen Worten: schlechte Idee, den Preis zu erhöhen, besser: Ticket langfristig absichern. Ich kann noch hinzufügen: und den ÖPNV verbessern, so dass Leute ihn noch lieber benutzen wollen.

Blogartikel? Nachrichtenwebsite? Bitte nur mit Datum!

An alle, die ein Blog, eine Nachrichtenwebsite oder etwas ähnliches betreiben: Schreibt bitte, bitte, bitte, verdammt noch mal ein Datum an jeden Artikel. Muss nicht einmal die Uhrzeit haben. Tag reicht. Bonuspunkte, wenn es im HTML auch ein <time>-Tag benutzt. Das ist aber zweitrangig.

Wenn ihr die Seite nicht selber gestalten, sondern nur dort posten könnt und die Seite kein Datum vorsieht: Bitte das Datum einfach dazuschreiben.

Es ist nämlich wirklich ätzend, ständig Artikel zu lesen, bei denen kein Datum steht. Bei Nachrichten weiß ich nicht ob es aktuell ist oder von vor vier Jahren. Bei technischen Artikeln kann ich nicht einschätzen, ob der Artikel vielleicht schon wieder veraltet ist. Bitte schreibt ein fucking Datum an eure Artikel!

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.