Die Zukunft des Build Managements

Nicht nur sogenannte Hochsprachen, die den Quelltext in Maschinencode überführen müssen, damit dieser ausführbar ist, benötigen sogenannte Build Werkzeuge. Auch für moderne Scriptsprachen wie Python, Ruby oder PHP sind diese Werkzeuge mittlerweile verfügbar, da deren Verantwortungsbereich stetig wächst. Blickt man in die Anfänge dieser Werkzeugkategorie, stößt man unweigerlich auf make, der erste offizielle Vertreter von dem, was man heute als Build Werkzeug bezeichnet. Die Hauptaufgabe von make war das Erstellen von Maschinencode und das Paketieren der Dateien zu einer Bibliothek oder ausführbaren Datei. Man kann also sagen, das Buildwerkzeuge unter die Kategorie der Automatisierungswerkzeuge fallen. Da liegt es nahe, viele andere immer wiederkehrende Aufgaben, die im Entwickleralltag anfallen, ebenfalls zu übernehmen. So war eine der wichtigsten Innovationen, die für den Erfolg von Maven verantwortlich war, die Verwaltung von Abhängigkeiten zu anderen Programmbibliotheken.

Eine andere Klasse an Automatisierungswerkzeugen, die fast verschwunden ist, sind die sogenannten Installer. Produkte wie Inno SetUp oder Wise Installer wurden verwendet, um den Installationsprozess auf Desktopanwendungen zu automatisieren. Diese Installationsroutinen sind eine spezielle Form des Deployments. Der Deploymentprozess wiederum hängt von verschiedenen Faktoren ab. Zuallererst ist natürlich das verwendete Betriebssystem ein wichtiges Kriterium. Aber auch die Art der Anwendung hat einen erheblichen Einfluss. Handelt es sich etwa um eine Webanwendung, die eine definierte Laufzeitumgebung (Server) benötigt? Wir können hier bereits sehen, dass viele der gestellten Fragen mittlerweile im Themenbereich DevOps angesiedelt sind.

Als Entwickler genügt es nun nicht mehr, nur zu wissen, wie man Programmcode schreibt und Funktionen implementiert. Wer eine Webanwendung bauen möchte, muss zuerst den entsprechenden Server zum Laufen bekommen, auf dem die Applikation ausgeführt wird. Glücklicherweise gibt es mittlerweile viele Lösungen, die das Bereitstellen einer lauffähigen Runtime erheblich vereinfachen. Aber gerade für Anfänger ist es nicht immer so leicht, das ganze Thema zu überblicken. Ich erinnere mich noch an Fragen in einschlägigen Foren, dass man jetzt Java Enterprise heruntergeladen hat, aber nur der Applikationsserver enthalten ist.

Wo Anfang der 2000er noch Automatisierungslösungen fehlten, ist heute eher die Herausforderung, das richtige Werkzeug zu wählen. Auch hier gibt es eine Analogie aus dem Java Universum. Als das Build-Werkzeug Gradle auf dem Markt erschien, stiegen viele Projekte von Maven auf Gradle um. Das Argument war, eine höhere Flexibilität zu erhalten. Oft benötigte man die Möglichkeit, orchestrierte Builds zu definieren. Also die Reihenfolge, in der Teilprojekte erstellt werden. Anstatt sich einzugestehen, dass es sich bei dieser Anforderung um einen Architekturmangel handelt und anstatt diesen zu beheben, wurden komplizierte und kaum überschaubare Build Logiken in Gradle gebaut. Das führte wiederum dazu, dass Anpassungen nur schwer umzusetzen waren und viele Projekte zurück nach Maven migriert wurden.

Aus den DevOps Automatisierungen haben sich mittlerweile sogenannte Pipelines etabliert. Pipelines können auch als Prozess verstanden werden und diese Prozesse lassen sich wiederum standardisieren. Das beste Beispiel für einen standardisierten Prozess, ist der in Maven definierte Build Lifecycle, der auch als Default-Lifecycle bezeichnet wird. In diesem Prozess werden 23 sequenzielle Schritte definiert, die im Groben zusammengefasst folgende Aufgaben abarbeiten:

  • Auflösen und Bereitstellen von Abhängigkeiten
  • Kompilieren der Quelltexte
  • Kompilieren und Ausführen von Komponententests
  • Paketieren der Dateien zu einer Bibliothek oder Anwendung
  • Lokales Bereitstellen des Artefaktes zur Verwendung in anderen lokalen Entwicklungsprojekten
  • Ausführen von Integrationstests
  • Deployen der Artefakte auf einem Remote Repository Server.

Dieser Prozess hat sich über Jahre in unzähligen Javaprojekten bestens bewährt. Führt man diesen Prozess allerdings auf einem CI Server wie Jenkins als Pipeline aus, bekommt man wenig zu sehen. Die einzelnen Schritte des Build Lifecycles bauen aufeinander auf und können nicht einzeln angesteuert werden. Es ist nur möglich, den Lifecycle vorzeitig zu verlassen. Man kann also nach dem Paketieren die nachfolgenden Schritte des lokalen Deployments und das Ausführen der Integrationstests auslassen.

Eine Schwäche des hier beschriebenen Build Prozesses kommt bei der Erstellung von Webapplikationen zutage. Web Frontends enthalten meist CSS und JavaScript Code, der ebenfalls automatisiert optimiert wird. Um in SCSS definierte Variablen in korrektes CSS zu überführen, muss ein SASS Präprozessor verwendet werden. Zudem ist es sehr nützlich, CSS Dateien und JavaScript Dateien möglichst stark zu komprimieren. Dieser Vorgang der Obfuskation optimiert die Ladezeiten von Webanwendungen. Aber auch für CSS und JavaScript gibt es bereits unzählige Bibliotheken, die mit dem Werkzeug NPM verwaltet werden können. NPM wiederum stellt sogenannte Entwicklungsbibliotheken wie Grunt bereit, mit denen wiederum CSS-Prozessierung und -Optimierung möglich sind.

Wir sehen, wie komplex der Buildprozess von modernen Anwendungen werden kann. Das Kompilieren ist nur ein kleiner Teil davon. Ein wichtiges Feature moderner Build Werkzeuge ist das Optimieren des Build Vorgangs. Eine mittlerweile etablierte Lösung dafür ist das Erstellen von inkrementellen Builds. Dies ist eine Variante des Cachings, bei der nur geänderte Dateien kompiliert beziehungsweise prozessiert werden.

Jenkins Pipelines

Was ist aber bei einem Release zu tun? Ein Prozess, der wiederum nur dann benötigt wird, wenn eine Implementierungsphase beendet ist, um das Artefakt für die Verteilung bereitzustellen. Nun könnte man alle Schritte, die ein Release enthalten, ebenfalls in den Build einbauen, was wiederum zu längeren Buildzeiten führt. Längere lokale Buildzeiten stören wiederum den Arbeitsfluss des Entwicklers, weswegen es sinnvoller ist, hierfür einen eigenen Prozess zu definieren.

Bei einem Release sollte eine wichtige Bedingung sein, dass alle verwendeten Bibliotheken ebenfalls als finale Releaseversion vorliegen. Ist dies nicht der Fall, kann nicht sichergestellt werden, dass erneut erstellte Releases dieser Version identisch sind. Aber auch alle Testfälle müssen korrekt durchlaufen werden und ein Fehlschlagen bricht den Vorgang ab. Zudem sollte ein entsprechendes Tag im Source-Control-Repository auf die Revision gesetzt werden. Die fertigen Artefakte sind zu signieren und auch eine API Dokumentation ist zu erstellen. Natürlich sind die hier beschriebenen Regeln nur eine kleine Auswahl und einige der beschriebenen Aufgaben können sogar parallelisiert werden. Nutzt man zudem noch ein raffiniertes Caching, kann das Erstellen eines Releases auch für umfangreiche Monolithen in kurzer Zeit vonstattengehen.

Für Maven wurde beispielsweise kein kompletter Releaseprozess, ähnlich dem Buildprozess, definiert. Hier wurde durch die Community ein spezielles Plug-in entwickelt, mit dem einfache Aufgaben, die während eines Releases anstehen, semiautomatisiert werden können.

Wenn wir das Thema Dokumentation und Reporting ein wenig genauer betrachten, finden wir auch hier genügend Möglichkeiten, einen vollständigen Prozess zu beschreiben. So wäre das Erstellen der API Dokumentation nur ein untergeordneter Punkt. Wesentlich spannender an einem standardisierten Reporting sind die verschiedenen Codeinspektionen, die teilweise auch parallel durchlaufen werden können.

Natürlich darf auch das Deployment nicht fehlen. Aufgrund der Vielfalt, der möglichen Zielumgebungen ist an dieser Stelle eine andere Strategie angebracht. Ein denkbarer Weg wäre eine breite Unterstützung von Konfigurationswerkzeugen wie Ansible, Chef und Puppet. Aber auch Virtualisierungstechnologien wie Docker und LXC Container gehören in Zeiten der Cloud zum Standard. Hauptaufgabe des Deployments wäre dann vor allem die Provisionierung der Zielumgebung und das Einspielen der Artefakte aus einem Repository Server. Mit einer Fülle verschiedener Deployment Templates würde dies eine erhebliche Vereinfachung darstellen.

Wenn wir die hier getroffenen Annahmen konsequent weiterdenken, kommen wir zu dem Schluss, dass es unterschiedliche Projekttypen geben kann. Das wären klassische Entwicklungsprojekte, aus denen dann Artefakte für Bibliotheken und Anwendungen entstehen, Testprojekte, die wiederum die erstellten Artefakte als Abhängigkeit enthalten, und natürlich Deploymentprojekte zur Bereitstellung der Infrastruktur. Der Bereich des automatisierten Deployments findet sich auch in der Idee Infrastructure as a Code und GitOps wieder,die man an dieser Stelle aufgreifen und weiterentwickeln kann.

Wir sehen, dass bei weitem noch nicht alle Innovationen für sogenannte Build Werkzeuge ausgeschöpft sind. Viele der hier besprochenen Ideen sind bereits existierende Konzepte und erfordern lediglich eine Standardisierung. Durch die formalen Beschreibungen eines Prozesses und die flexible Konfiguration einzelner Komponenten in den Prozessschritten wird eine individuelle Anpassung ermöglicht.


Clean Desk – mehr als nur Sicherheit

Als Kind antwortete ich gern meiner Mutter, dass nur ein Genie das Chaos beherrscht, wenn sie mich anhielt, mein Zimmer aufzuräumen. Eine sehr willkommene Ausrede, mich vor meinen Pflichten zu drücken. Als ich nach dem Schulabschluss eine Lehre im Handwerk begonnen habe, war das Erste, worauf mein Lehrmeister achtete: Ordnung halten. Das Werkzeug hatte nach Benutzung zurück in die Werkzeugtasche gelegt zu werden, angefangene Kartons mit gleichen Arbeitsmaterialien wurden wieder aufgefüllt und natürlich galt es auch, mehrmals am Tag den Dreck aufzukehren. Ich kann gleich vorwegnehmen, dass ich diese Dinge nie als Schikane empfunden habe, auch wenn sie uns lästig erschienen sind. Denn rasch haben wir den Nutzen der Devise „Sauberkeit halten“ erfahren.

Werkzeuge, die immer zurück an ihren Platz gebracht werden, verschaffen uns zügig einen Überblick, ob etwas fehlt. Also kann man sich dann auf die Suche machen und die Wahrscheinlichkeit, dass Dinge gestohlen werden, reduziert sich drastisch. Auch bei den Arbeitsmaterialien behält man einen guten Überblick über Dinge, die verbraucht wurden und neu beschafft werden müssen. Fünf leere Kartons mit nur ein oder zwei Teilen darin verbrauchen nicht bloß Platz, sondern führen auch zu falschen Einschätzungen der verfügbaren Ressourcen. Zu guter Letzt gilt natürlich auch, dass man sich im Dreck weniger wohlfühlt und mit Sauberkeit dem Auftraggeber demonstriert, dass man fokussiert und planvoll vorgeht.

Durch diese Prägung in jungen Jahren, habe ich, als vor einigen Jahren das Thema Clean Desk als Sicherheitskonzept in Unternehmen eingeführt wurde, nicht gleich verstanden, was man von mir wollte. Schließlich ist mir das Prinzip Clean Desk bereits in Fleisch und Blut übergegangen, lange bevor ich mein Studium der Informatik abgeschlossen hatte. Aber der Reihe nach. Schauen wir uns erst einmal an, was Clean Desk eigentlich ist und wie man es umsetzt.

Wer sich tiefgehend mit dem Thema Security beschäftigt, lernt als Erstes, dass die meisten erfolgreichen Angriffe nicht über komplizierte technische Manöver durchgeführt werden. Sie verlaufen viel profaner und kommen üblicherweise nicht von außen, sondern von innen. Treu nach dem Motto: Gelegenheit macht Diebe. Kombiniert man diese Tatsache noch mit den Erkenntnissen des Social Engineerings, das vor allem durch den Hacker Kevin Mitnick geprägt wurde, ergibt sich ein neues Bild. Es müssen nicht immer gleich die eigenen Mitarbeiter unter Generalverdacht gestellt werden. In einem Gebäude gibt es externe Putzkräfte, Sicherheitspersonal oder Handwerker, die meist problemlos Zugang zu sensiblen Räumlichkeiten bekommen. Daher gilt stets die Devise: Vertrauen ist gut, Kontrolle ist besser, weswegen man eine Clean Desk Policy einführt.

Die erste Regel lautet: Wer über einen längeren Zeitraum den Arbeitsplatz verlässt, schaltet seine Geräte aus. Das gilt besonders für den Feierabend. Ansonsten ist zumindest der Desktop zu sperren. Das Konzept dahinter ist recht einfach. Von ausgeschalteten Geräten können keine Sicherheitslücken ausgenutzt werden, um sich von außen in das Firmennetzwerk zu hacken. Zudem verringert es den Stromverbrauch und verhindert Brände durch Kurzschlüsse. Damit die Geräte nicht physisch entwendet werden können, sind diese mit speziellen Schlössern am Schreibtisch fixiert. Ich habe es schon selbst erlebt, dass während der Mittagspause Geräte gestohlen wurden.

Da ich selbst sehr viel in Hotels übernachtet habe, ist die Festplatte meines Computers prinzipiell verschlüsselt. Das gilt auch für alle externen Datenträger wie USB Sticks oder externe SSDs. Wird das Gerät gestohlen, kann zumindest niemand auf die darauf befindlichen Daten zugreifen.

Es ist natürlich selbstverständlich, dass eine sichere Verschlüsselung nur mit einem starken Passwort möglich ist. Viele Unternehmen, haben spezielle Regeln, die die Passwörter der Mitarbeiter erfüllen müssen. Zudem ist es üblich, dass alle 30 bis 90 Tage ein neues Passwort vergeben werden muss, das von den letzten drei verwendeten Passwörtern abweichen muss.

Oft wird auch darauf hingewiesen, dass die Passwörter nicht auf einem Post-it stehen, der auf dem Monitor klebt. Das habe ich selbst so nie erlebt. Viel typischer ist, dass Passwörter unter der Tastatur oder dem Mauspad notiert werden.

Ein anderer Aspekt sind Aufzeichnungen, die auf Schreibtischen, Wandkalendern und Whiteboards hinterlassen werden. Auch wenn die Information noch so unbedeutend scheint, kann sie durchaus sehr wertvoll sein. Da es recht schwer ist, zu entscheiden, was wirklich schützenswert ist und was nicht, gilt die allgemeine Regel: Alle Aufzeichnungen sind zum Feierabend für Außenstehende unzugänglich zu verstauen. Das klappt natürlich nur dann, wenn auch verschließbarer Stauraum vorhanden ist. In sensiblen Bereichen wie Banken und Versicherungen geht man sogar so weit, dass auf Wandkalendern keine Urlaube der Kollegen eingetragen werden dürfen.

Natürlich ist bei diesen Überlegungen auch der eigene Papierkorb einzubeziehen. Hier ist sicherzustellen, dass die vertraulichen Dokumente in speziell gesicherten Containern entsorgt werden. Denn sonst führt es ja den ganzen Aufwand der Geheimhaltung wieder ad absurdum, wenn man diese nach Feierabend einfach aus dem Papierkorb ziehen kann.

Aber auch der virtuelle Schreibtisch ist Teil der Clean Desk Policy. Ganz besonders in Zeiten der virtuellen Videokonferenzen und Remote Arbeit können Fremde einen Blick auf den eigenen Schreibtisch erhaschen. Das erinnert mich auch an die Zeit der Vorlesungen, als ein Dozent mehrere Verknüpfungen des Papierkorbes auf seinem Desktop hatte. Wir haben immer gescherzt, dass er recycelt. Eigene Papierkörbe für Word, Excel etc. Dateien.

Die Clean Desk Policy hat allerdings auch andere Auswirkungen. Es ist durchaus mehr als nur ein Sicherheitskonzept. Denn Mitarbeiter, die diese Policy konsequent umsetzen, bringen dadurch auch mehr Ordnung in die eigenen Gedanken und können so Thema für Thema konzentriert abarbeiten, was zu einer besseren Performance führt. Meist erfolgt die persönliche Tagesplanung so, das zum Feierabend auch die begonnenen Aufgaben abgeschlossen werden können. Auch hier finden sich Analogien zum Handwerk. Denn der Handwerker versucht ebenfalls, den Auftrag möglichst bis zum Feierabend zu erledigen, um am nächsten Tag nicht noch einmal für kurze Zeit anrücken zu müssen. Denn auch hier wird einiges an Zeit für Vorbereitungen aufgewendet.

Die Umsetzung einer Clean Desk Policy erfolgt nach den drei P (Plan, Protect & Pick). Zu Beginn des Tages wird sich überlegt, welche Aufgaben erledigt werden sollen (Plan), und die entsprechenden Dokumente und benötigten Materialien werden ausgewählt, um darauf Zugriff zu haben. Am Ende des Tages werden die Dinge wieder sicher verstaut. Während der Arbeitszeit ist ebenfalls sicherzustellen, dass zum Beispiel in den Pausen keine unbefugten Personen Zugriff auf die Informationen haben. Diese tägliche, einfach umzusetzende Routine von Vorbereitung und Nachbereitung wird rasch zur Gewohnheit und die dafür aufzuwendened Zeit lässt sich auf wenige Minuten reduzieren, so dass kaum Arbeitszeit vergeudet wird.

Mit einer Clean Desk Policy verschwinden die erdrückenden Papierberge vom Schreibtisch, und durch die Überlegung, welche Aufgaben am Tag erledigt werden sollen, ist man besser auf diese fokussiert, was die Produktivität erheblich verbessert. Am Ende des Tages kann man nun mental auch einige Punkte von der eigenen Aufgabenliste streichen, was zu einer besseren Zufriedenheit führt.


Frühjahrsputz für Docker

Wer sich für diesen, eigentlich etwas spezialisierten Artikel interessiert, dem muss man nicht mehr erklären, was Docker ist und wofür das Virtualisierungswerkzeug eingesetzt wird. Daher richtet sich dieser Artikel vornehmlich an Systemadministratoren, DevOps und Cloud-Entwickler. Für alle, die bisher nicht ganz so fit mit der Technologie sind, empfehle ich unseren Docker Kurs: From Zero to Hero.

In einem Szenario, in dem wir regelmäßig neue Docker Images erstellen und verschiedene Container instanzieren, wird unsere Festplatte ordentlich gefordert. Images können je nach Komplexität durchaus problemlos einige hundert Megabyte bis Gigabyte erreichen. Damit das Erstellen neuer Images auch nicht gefühlt, wie ein Download einer drei Minuten langen MP3 mit einem 56k Modem dauert, nutzt Docker einen Build-Cache. Ist im Dockerfile wiederum ein Fehler, kann dieser Build-Cache recht lästig werden. Daher ist es eine gute Idee, den Build-Cache durchaus regelmäßig zu entleeren. Aber auch alte Containerinstanzen, die nicht mehr in Verwendung sind können zu komischen Fehlern führen. Wie hält man seine Dockerumgebung also stubenrein?

Sicher kommt man mit mit docker rm <container-nane> und docker rmi <image-id> schon recht weit. In Buildumgebungen wie Jenkins oder Serverclustern kann diese Strategie allerdings zu einer zeitintensiven und mühsamen Beschäftigung werden. Doch verschaffen wir uns zuerst einmal einen Überblick über die Gesamtsituation. Hier hilft uns der Befehl docker system df weiter.

root:/home# docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          15        9         5.07GB    2.626GB (51%)
Containers      9         7         11.05MB   5.683MB (51%)
Local Volumes   226       7         6.258GB   6.129GB (97%)
Build Cache     0         0         0B        0B

Bevor ich gleich in die Details eintauche, noch ein wichtiger Hinweis. Die vorgestellten Befehle sind sehr effizient und löschen unwiderruflich die entsprechenden Bereiche. Daher wendet diese Befehle erst auf einer Übungsumgebung an, bevor ihr damit Produktivsysteme außer Gefecht setzt. Zudem hat es sich für mich bewährt, auch die Befehle zur Instanzierung von Containern in deiner Textdatei unter Versionsverwaltung zu stellen.

Der naheliegendste Schritt bei einem Docker System Cleanup ist das Löschen der nichtbenutzten Container. Im Konkreten bedeute das, dass durch den Löschbefehl alle Instanzen der Docker Container, die nicht laufen (also nicht aktiv sind), unwiederbringlich gelöscht werden. Will man auf einem Jenkins Buildnode vor einem Deployment Tabula Rasa durchführen, kann man zuvor alle auf der Maschine laufenden Container mit einem Befehl beenden.

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.

Der Parameter -f unterdrückt die Nachfrage, ob man diese Aktion wirklich durchführen möchte. Also die ideale Option für automatisierte Skripte. Durch das Löschen der Container erhalten wir vergleichsweise wenig Festplattenplatz zurück. Die Hauptlast findet sich bei den heruntergeladenen Images. Diese lassen sich ebenfalls mit nur einem Befehl entfernen. Damit Images allerdings gelöscht werden können, muss vorher sichergestellt sein, dass diese nicht durch Container (auch inaktive) in Verwendung sind. Das Entfernen ungenutzter Container hat noch einen ganz anderen praktischen Vorteil. Denn beispielsweise durch Container blockierte Ports werden so wieder freigegeben. Schließlich lässt sich ein Port einer Hostumgebung nur exakt einmal an einen Container binden. Das kann stellenweise schnell zu Fehlermeldungen führen. Also erweitern wir unser Skript um den Eintrag, alle nicht durch Container benutzten Docker Images ebenfalls zu löschen.

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.

Eine weitere Konsequenz unserer Bemühungen umfasst die Docker Layers. Hier sollte man aus Performancegründen, besonders in CI Umgebungen Abstand nehmen. Docker Volumes hingegen sind hier weniger problematisch. Beim Entfernen der Volumes, werden nur die Referenzen in Docker entfernt. Die in die Container verlinkten Ordner und Dateien bleiben von der Löschung unberührt. Der Parameter -a löscht alle Docker Volumes.

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.

Ein weiterer Bereich, der von unseren Aufräumarbeiten betroffen ist, ist der Build-Cache. Besonders wenn man gerade ein wenig mit dem Erstellen neuer Dockerfiles experimentiert, kann es durchaus sehr nützlich sein, den Cache hin und wieder manuell zu löschen. Diese Maßnahme verhindert, dass sich falsch erstellte Layer in den Builds erhalten und es später im instanziierten Container zu ungewöhnlichen Fehlern kommt. Der entsprechende Befehl lautet:

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.

Ganz radikal ist die Möglichkeit, alle nicht genutzten Ressourcen wieder freizugeben. Hierfür gibt es ebenfalls ein explizites Kommando für die Shell.

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.

Wir können die gerade vorgestellten Befehle natürlich auch für CI Buildumgebungen wie Jenkins oder GitLab CI nutzen. Allerdings kann es sein, dass dies nicht unbedingt zum gewünschten Ziel führt. Ein bewährter Ansatz für Continuous Integration / Continuous Deployment ist das Aufsetzen einer eigenen Docker-Registry, wohin man selbst erstellte Images deployen kann. Diese Vorgehensweise, ist ein gutes Backup & Chaching System für die genutzten Docker Images. Einmal korrekt erstellte Images lassen sich so bequem über das lokale Netzwerk auf die verschiedenen Serverinstanzen deployen, ohne dass diese ständig lokal neu erstellt werden müssen. Daraus ergibt sich als bewährter Ansatz ein eigens für Docker Images / Container optimierter Buildnode, um die erstellten Images vor der Verwendung optimal zu testen. Auch auf Cloudinstanzen wie Azure und der AWS sollte man auf eine gute Performanz und ressourcenschonendes Arbeiten Wert legen. Schnell können die anfallenden Kosten explodieren und ein stabiles Projekt in massive Schieflage bringen.

In diesem Artikel konnten wir sehen, dass tiefe Kenntnisse der eingesetzten Werkzeuge einige Möglichkeiten zur Kostenersparnis erlauben. Gerade das Motto „Wir machen, weil wir es können“, ist im kommerzeillen Umfeld weniger hilfreich und kann schnell zur teuren Resourcenverschwendung ausarten.


Vibe Coding – eine neue Plage des Internets?

Als ich das erste Mal den Begriff Vibe Coding las, dachte ich erst an Kopfhörer, chillige Musik und den Übertritt in den Flow. Der absolute Zustand der Kreativität dem Programmierer hinterherjagen. Ein Rausch der Produktivität. Aber nein, es wurde mir recht schnell klar, es geht um etwas anderes.

Vibe Coding nennt man das, was man einer KI über den Prompt eingibt, um ein benutzbares Programm zu erhalten. Die Ausgabe des Large Language Models (LLM) ist dann noch nicht gleich das ausführbare Programm, sondern nur der entsprechende Quelltext in der Programmiersprache, die der Vibe Coder vorgibt. Daher braucht der Vibe Coder je nachdem, auf welcher Plattform er unterwegs ist, noch die Fähigkeit, das Ganze zum Laufen zu bringen.

Seitdem ich in der IT aktiv bin, gibt es den Traum der Verkäufer: Man bräuchte keine Programmierer mehr, um Anwendungen für den Kunden zu entwickeln. Bisher waren alle Ansätze dieser Art wenig erfolgreich, denn egal was man auch tat, es gab keine Lösung, die vollständig ohne Programmierer ausgekommen ist. Seit der allgemeinen Verfügbarkeit von KI‑Systemen hat sich einiges geändert und es ist nur eine Frage der Zeit, bis man von den LLM-Systemen wie Copilot etc. auch ausführbare Anwendungen geliefert bekommt.

Die Möglichkeiten, die sich durch Vibe Coding eröffnen, sind durchaus beachtlich, wenn man weiß, was man da tut. Gleich aus Goethes Zauberlehrling, der der Geister, die er rief, nicht mehr Herr geworden ist. Werden Programmierer nun obsolet? Auf absehbare Zeit denke ich nicht, dass der Beruf Programmierer aussterben wird. Es wird sich aber einiges verändern und die Anforderungen werden sehr hoch sein.

Ich kann definitiv sagen, dass ich der KI Unterstützung beim Programmieren offen gegenüberstehe. Allerdings haben mich meine bisherigen Erfahrungen gelehrt, sehr vorsichtig zu sein mit dem, was die LLMs so als Lösung vorschlagen. Möglicherweise liegt es daran, dass meine Fragen sehr konkret und für spezifische Fälle waren. Die Antworten waren durchaus hin und wieder ein Fingerzeig in eine mögliche Richtung, die sich als erfolgreich herausgestellt hat. Aber ohne eigenes Fachwissen und Erfahrung wären alle Antworten der KI nicht nutzbar gewesen. Auch Begründungen oder Erläuterungen sind in diesem Kontext mit Vorsicht zu genießen.

Es gibt mittlerweile diverse Angebote, die den Leuten den Umgang mit künstlicher Intelligenz beibringen wollen. Also in Klartext, wie man einen funktionierenden Prompt formuliert. Ich halte solche Offerten für unseriös, denn die LLM wurden ja dafür entwickelt, natürliche (menschliche) Sprache zu verstehen. Was soll man also lernen, vollständige und verständliche Sätze zu formulieren?

Wer eine ganze Anwendung über Vibe Coding erstellt, muss diese ausgiebig testen. Also sich durch die Funktionen klicken und schauen, ob alles so funktioniert, wie es soll. Das kann durchaus zu einer sehr nervenden Beschäftigung ausarten, die mit jedem Durchlauf lästiger wird.

Auch die Verwendung von Programmen, die durch Vibe Coding erstellt wurden, ist unproblematisch, solange diese lokal auf dem eigenen Computer laufen und nicht als kommerzieller Internetservice frei zugänglich sind. Denn genau hier lauert die Gefahr. Die durch Vibe Coding erstellten Programme sind nicht ausreichend gegen Hackerangriffe gesichert, weswegen man sie nur in geschlossenen Umgebungen betreiben sollte. Ich kann mir auch gut vorstellen, dass künftig in sicherheitskritischen Umgebungen wie Behörden oder Banken die Verwendung von Programmen, die Vibe Coded sind, zu verbieten. Sobald die ersten Cyberattacken auf Unternehmensnetzwerke durch Vibe Coding Programme bekannt werden, sind die Verbote gesetzt.

Neben der Frage zur Sicherheit von Vibe-Coding-Anwendungen werden Anpassungen und Erweiterungen nur mit großem Aufwand umzusetzen sein. Dieses Phänomen ist in der Softwareentwicklung gut bekannt und tritt bei sogenannten Legacy Anwendungen regelmäßig auf. Sobald man hört, dass ist historisch gewachsen ist, man auch schon mitten drin. Fehlende Strukturen und sogenannte technische Schulden lassen ein Projekt über die Zeit so erodieren, dass sich die Auswirkungen von Änderungen nur sehr schwer auf die restlichen Funktionen abschätzen lassen. So ist zu vermuten, dass es in Zukunft sehr viele Migrationsprojekte geben wird, die die KI erstellten Codebasen wieder in saubere Struckturen überführen. Deswegen eignet sich Vibe Coding vor allem für die Erstellung von Prototypen, um Konzepte zu testen.

Mittlerweile gibt es auch Beschwerden in Open Source Projekten, dass es hin und wieder zu Contributions kommt, die nahezu die halbe Codebasis umstellen und fehlerhafte Funktionen hinzufügen. Hier helfen natürlich zum einen der gesunde Menschenverstand und die vielen in der Softwareentwicklung etablierten Standards. Es ist ja nicht so, dass man im Open Source nicht schon früher Erfahrung mit schlechten Code Commits gesammelt hätte. Dadurch kam der Diktaturship-Workflow für Werkzeuge wie Git, das von der Codehosting Plattform GitHub in Pull Request umbenannt wurde.

Wie kann man also schnell schlechten Code erkennen? Mein derzeitiges Rezept ist die Überprüfung der Testabdeckung für hinzugefügten Code. Kein Test, kein Codemerge. Natürlich können auch Testfälle Vibe Coded sein oder es fehlen notwendige Assertions, auch das lässt sich mittlerweile gut automatisiert erkennen. In den vielen Jahren in Softwareentwicklungsprojekten habe ich genügend erlebt, dass mir kein Vibe Coder auch nur annähernd Schweißperlen auf die Stirn treiben kann.

Mein Fazit zum Thema Vibe Coding lautet: Es wird in Zukunft einen Mangel an fähigen Programmierern geben, die Unmengen an schlechtem Produktivcode gerade biegen sollen. Also auf absehbare Zeit noch kein aussterbender Beruf. Dem gegenüber werden durchaus ein paar clevere Leute für das eigene Business sich mit einfachen Informatikkenntnissen ein paar leistungsfähige Insellösungen zusammenscripten, die zu Wettbewerbsvorteilen führen werden. Während wir diese Transformation erleben, wird das Internet weiterhin zugemüllt und die Perlen, von denen Weizenbaum einst gesprochen hat, schwerer zu finden sein.


Der Goldene Schnitt

Wenn wir Bilder betrachten, empfinden wir besonders diejenigen als ästhetisch, deren Elemente einem bestimmten Verhältnis von Strecken und Flächen folgen. Diese Harmonielehre nennt sich der „Goldene Schnitt“ und findet viel Anwendung in der Natur.

Nun könnte man meinen: In Zeiten der durch künstliche Intelligenz gerenderten Grafiken, benötigen wir die vielen Grundlagen des Grafikdesigns nicht mehr. Das ist allerdings zu kurz gedacht, denn einerseits müssen wir aus den Vorschlägen der erstellten Bilder die beste Variante auswählen. Um hier gute Entscheidungen zu treffen, sind Kenntnisse über Proportionen und Ästhetik essenziell. Außerdem müssen wir unseren Wunsch auch klar formulieren können, damit wir ein optimales Ergebnis erzielen. Nur die Dinge die wir wirklich vollständig durchdringen können wir auch klar und unmissverständlich formulieren. Deswegen ist ganz besonders im Umgang mit generativer KI ein fundiertes Fachwissen unverzichtbar.

Geometrisch bedeutet der Goldene Schnitt, dass eine Strecke AB in zwei unterschiedlich lange Streckenabschnitte (a und b) geteilt wird. Setzt man nun a durch b gleich der Summe (a+b) / a, so erhält man φ mit dem Wert 1,618. Übrigens entspricht der exakte Wert von φ der Quadratwurzel aus 5 (√5). Die Streckenverhältnisse betragen ungefähr 3:2. Die nachfolgende Grafik verdeutlicht den Zusammenhang.

Um den „Goldenen Schnitt“ auf Flächen anzuwenden, ist es nicht notwendig, im Abitur den Mathematikleistungskurs erfolgreich abgeschlossen zu haben. Wir benötigen lediglich die Zahl φ. Wenn wir ein Rechteck mit einer Kantenlänge von einem Zentimeter haben und 1 * 1,618 multiplizieren, erhalten wir 1,618. Nun können wir ein Rechteck mit der Kantenlänge a = 1 und b = 1,618 zeichnen. Das hier entstandene Verhältnis ist die perfekte Harmonie und wird als „Goldener Schnitt“ bezeichnet.

Wenn wir in dieses Rechteck unser Quadrat mit der Kantenlänge von einem Zentimeter hineinlegen, erhalten wir eine rechteckige Fläche B, die sich nach dem gleichen Muster aufteilen lässt. Wenn wir diesen Vorgang nun ein paar Mal wiederholen, erhalten wir ein gekacheltes Muster. Tragen wir jetzt in jedes entstandene Quadrat einen Kreisbogen mit dem Radius der Kantenlänge ein, erhalten wir eine Spirale. Die Form aus Abbildung 2 dürfte den meisten bereits bekannt sein und nun wisst ihr auch, wie sie entsteht.

Die soeben beschriebene Spirale findet sich auch in der sogenannten Fibonacci Zahlenfolge wieder. Die Fibonacci Folge ist eine einfache rekursive Addition aus den beiden Vorgängern. Abbildung 3 zeigt, wie schnell sich die Fibonacci Folge berechnen lässt. Wir sehen, es ist dazu kein höheres Studium der Mathematik notwendig.

Wo finden wir den Goldenen Schnitt in der Anwendung? Neben Proportionen in Logos und anderen Grafiken nutzt man den Goldenen Schnitt oft in der Typografie. Die Höhenverhältnisse von kleinen zu großen Buchstaben folgen gern dem Abstand 1:1,618.

Ein typisches Szenario für die Anwendung des Goldenen Schnitts ist auch die Position von Objekten innerhalb einer Grafik. Um eine gute Illusion von Tiefe zu erzielen, benötigen die Objekte ein entsprechendes Verhältnis der Höhen zueinander. Aber auch der Bereich, wie Objekte im Abstand zueinander positioniert werden, lässt ein Bild ruhig und harmonisch oder aufgewühlt und unruhig wirken. Wir haben also zwei Möglichkeiten, durch den Goldenen Schnitt eine Stimmung beim Betrachter zu erzeugen. Durch gezielte Verletzung der Proportionen erreichen wir eine gewisse Unruhe, die durchaus ebenfalls gewünscht sein kann. Eine solche invertierte Strategie kann zum Beispiel in der Werbung eingesetzt werden, um sich aus der Masse abzuheben und so beim Betrachter Aufmerksamkeit zu erregen.


Featureitis

Man muss nicht gleich Softwareentwickler sein, um ein gutes Anwendungsprogramm erkennen zu können. Doch aus eigener Erfahrung ist es mir oft passiert, dass Programme, die zu Beginn vielversprechend und innovativ waren, ab einer ‚gewissen‘ Nutzerzahl zu unhandlichen Boliden mutiert sind. Da ich diese Beobachtung nun schon einige Jahrzehnte regelmäßig aufs Neue mache, habe ich mich gefragt, woran das wohl liegen kann.

Das Phänomen, dass Softwareprogramme oder Lösungen im Allgemeinen mit Details überladen werden, hat Brooks in seinem Klassiker ‚The Mythical Man-Month‘ als Featuritis bezeichnet. Wenn man überlegt, dass die Erstausgabe des Buches im Jahr 1975 erschienen ist, kann man wohl von einem lange bekannten Problem sprechen. Das wohl bekannteste Beispiel für Featuritis ist das Betriebssystem Windows von Microsoft. Natürlich gibt es noch unzählige andere Beispiele für Verschlimmbesserungen.

Windowsnutzer, die bereits Windows XP kannten und dann mit dem tollen Nachfolger Vista konfrontiert wurden, um dann mit Windows 7 wieder besänftigt zu werden, um mit 8 und 8.1 beinahe einen Herzinfarkt erlitten zu haben, sich zu Beginn von Windows 10 wieder beruhigen. Jedenfalls für kurze Zeit, bis der Updatezwang für schnelle Ernüchterung sorgte. Von Windows 11 ganz zu schweigen. Zu Windows hieß es einmal, jede zweite Version ist Schrott, die sollte man überspringen. Nun ja, das stimmt seit Windows 7 schon lange nicht mehr. Für mich war Windows 10 dann der ausschlaggebende Punkt, vollständig auf Microsoft zu verzichten, und ich habe mir wie viele andere auch ein neues Betriebssystem zugelegt. Einige sind zu Apple gewechselt, und wer sich die teure Hardware nicht leisten kann oder will, hat wie ich auf ein Linuxsystem gesetzt. Hier zeigt sich, wie Uneinsichtigkeit schnell zum Verlust signifikante Marktanteile führt. Da Microsoft aus diesen Entwicklungen keine Konsequenzen zieht, scheint dem Unternehmen dieser Umstand weniger wichtig zu sein. Andere Unternehmen wiederum kann so etwas schnell an den Rand der Existenz bringen, und darüber hinaus.

Eine Motivation, immer mehr Funktionen in eine bestehende Anwendung zu bringen, ist der sogenannte Produktlebenszyklus, der durch die BCG Matrix in Abbildung 1 dargestellt wird.

Mit der Einführung ist noch nicht sicher, ob das Produkt vom Markt akzeptiert wird. Wenn es die Nutzer annehmen, steigt es schnell zum Star auf und erreicht seine maximale Marktposition als Cash Cow. Sobald die Sättigung überschritten wurde, degradiert es zum Ladenhüter. Soweit, so gut. Leider herrscht im Management überwiegend die Idee, dass, wenn kein Wachstum zum vorherigen Quartal mehr erzeugt wird, die Sättigung bereits überschritten wurde. So kommt es zu der sinnbefreiten Annahme, den Nutzern müsste jedes Jahr eine aktualisierte Version des Produktes aufgedrängt werden. Die Motivation zu kaufen gelingt natürlich nur, wenn eine dickgefüllte Featureliste an Neuerungen auf die Verpackung gedruckt werden kann.

Da sinnvoll konzipierte Funktionen sich aber nicht wie am Fließband aus dem Ärmel schütteln lassen, kommt auch jedes Mal gleich ein Redesign der grafischen Benutzeroberfläche als Gratis-Schmankerl mit dazu. Schließlich hat man dann das Gefühl, man habe etwas völlig Neues, weil man erst wieder eine Eingewöhnung braucht, um die neue Platzierung alt bekannter Funktionen zu entdecken. Es ist ja nicht so, dass das Redesign in der Benutzung Wege verkürzen würde und die Produktivität erhöht. Die Zusammenstellung der Eingabemasken und Schaltflächen erscheint jedes Mal willkürlich zusammengewürfelt.

Aber keine Sorge, ich will nicht zum Updateboykott aufrufen, sondern einmal darüber sprechen, wie man es besser machen kann. Denn eines sei gewiss: Dank künstlicher Intelligenz wird sich der Markt für Softwareprodukte in wenigen Jahren massiv verändern. Ich erwarte nicht, dass komplexe und spezialisierte Anwendungsprogramme in absehbarer Zeit durch KI-Algorithmen produziert werden. Allerdings erwarte ich, dass in diesen Anwendungsprogrammen genügend KI generierte schlechte Codesequenzen, die der Entwickler nicht versteht, in die Codebasis eingebracht werden, was zu unstabilen Anwendungen führen wird. Diese Überlegung ist für mich ein Grund, wieder über saubere, handgemachte, leitungsfähige und verlässliche Software nachzudenken, denn ich bin mir sicher, dass dafür immer ein Markt bestehen bleiben wird.

Ich möchte einfach keinen Internetbrowser, der zu einer Kommunikationszentrale mutiert ist und neben dem eigentlichen Anzeigen von Internetseiten noch Chat, E-Mail, Kryptobezahlmethoden und was weiß ich noch alles enthält. Ich möchte, dass mein Browser schnell startet, wenn ich irgendetwas klicke, dann schnell reagiert und die Inhalte der Internetseiten korrekt und schnell darstellt. Sollte ich einmal den Wunsch haben, etwas anderes mit meinem Browser zu tun, wäre es nett, wenn ich dies aktiv durch ein Plug-in aktivieren kann.

Nun gibt es zu dieser gerade beschriebenen Problemstellung oft die Argumentation, dass man ja mit den vielen Funktionen einen breiten Nutzerkreis erreichen möchte. Gerade wenn eine Anwendung zu Beginn alle möglichen Optionen auch aktiv eingeschaltet hat, holt das schnell den unkundigen Benutzer ab, der dann nicht erst begreifen muss, wie sein Programm überhaupt funktioniert. Ich kann diese Überlegung durchaus nachvollziehen. Es ist auch völlig in Ordnung, wenn ein Hersteller sich ausschließlich auf unkundige Anwender konzentriert. Es gibt aber einen Mittelweg, der alle Nutzergruppen gleichmäßig berücksichtigt. Diese Lösung ist auch nicht neu und sehr gut bekannt, die sogenannten Produktlinien.

In der Vergangenheit haben Hersteller immer Zielgruppen wie Privatpersonen, Unternehmen und Experten definiert. Diesen Nutzergruppen wurden dann oft Produktbezeichnungen wie Home, Enterprise und Ultimate zugeordnet. Das führte dazu, dass jeder die Ultimate Version wollte. Das Phänomen nennt sich Fear Of Missing Out (FOMO), also etwas zu verpassen. Deswegen sind die Bezeichnungen der Produktgruppen und deren zugeordneten Funktionen psychologisch ungeschickt gewählt. Wie kann man das also besser machen?

Ein Experte konzentriert sich bei seiner Arbeit auf spezielle Basisfunktionen, mit denen er seine Aufgaben schnell und ohne Ablenkung erledigen möchte. Das impliziert für mich Begriffe wie Essentials, Pure oder Core als Produktline.

Wenn das Produkt dann noch im Unternehmen von mehreren Personen verwendet werden soll, benötigt dies oft zusätzliche Funktionen wie zum Beispiel ein externes Benutzermanagement, wie LDAP oder IAM. Diese spezialisierte Produktlinie assoziiert Begriffe wie Enterprise (verbrannt), Company, Business und so weiter.

Das zugemüllte Endergebnis, das eigentlich für NOOPS gedacht ist und alle möglichen Sachen bereits über die Installation aktiviert hat. Wenn den Leuten die Zeit, bis die Anwendung gestartet ist und sie reagiert, egal ist, dann nur zu. Immer in die Vollen. Rein, was rein geht! Hier eignen sich Bezeichnungen wie Ultimate, Full und Maximized Extended als Bezeichnung der Produktlinie. Wichtig ist nur, dass die Profis erkennen, dass es sich um die zugemüllte Variante handelt.

Wer nun geschickt mit diesen Produktlinien spielt und möglichst alle Funktionen über sogenannte Module bereitstellt, die nachinstallierbar sind, ermöglicht eine hohe Flexibilität auch im Expertenmodus, denen durchaus die eine oder andere Zusatzfunktion genehm ist.

Installiert man auf das Modulsystem zuvor noch ein Tracking, um festzustellen, wie professionelle Anwender ihre Version upgraden, dann hat man schon eine gute Idee, was in die neue Version von Essentials hinzugefügt werden könnte. Bei dem Tracking sollte man sich aber nicht auf die Downloads als Entscheidungskriterium stützen. Ich selbst probiere oft Dinge aus und lösche Erweiterungen auch schneller, als der Installationsprozess gedauert hat, wenn ich der Meinung bin, dass diese nutzlos sind.

Ich möchte zu der gerade beschriebenen Problematik ein kleines Beispiel geben, das aus dem DevOps Bereich stammt. Zum einen gibt es das bekannte GitLab, das ursprünglich einmal ein reines Code Repository-Hosting-Projekt gewesen ist. Darauf deutet auch der Name, bis heute. Eine Anwendung, die auf einem Server bereits 8 GB RAM in der Basis-Installation benötigt, um ein Git Repository für andere Entwickler erreichbar zu machen, ist für mich unbrauchbar, denn diese Software wurde über die Zeit zur EierlegendenWollmilchSau. Langsam, unflexibel und mit allem Kram zugemüllt, der über Speziallösungen besser umgesetzt wurde.

GitLab gegenüber steht eine andere Lösung namens SCM-Manager, die weniger bekannt ist und sich ausschließlich auf das Bereitstellen der Code Repositories konzentriert. Ich selbst nutze und empfehle den SCM-Manager, weil er mit der Basis-Installation extrem kompakt ist. Aber dennoch gibt es eine gigantische Funktionsvielfalt, die man über Plug-ins nachrüsten kann.

Für mich sind Lösungen, die eine All In One Solution bereitstellen wollen, eher suspekt. Das ist für mich immer gleich dem Motto: alles und nichts. Es gibt keine EierlegendeWollMilchSau oder wie man in Österreich zu sagen pflegt, keinen Wunderwuzzi!

Wenn ich Programme für meinen Arbeitsprozess auswähle, orientiere ich mich ausschließlich an deren Kernfunktionalität. Sind die Grundeigenschaften, die das Marketing verspricht, wirklich vorhanden und möglichst intuitiv nutzbar? Gibt es eine aussagekräftige Dokumentation, die über ein bloßes ‚Hallo Welt‘ hinausgeht? Konzentriert man sich darauf, die Kernfunktionen stets zu optimieren, und berücksichtigt neue innovative Konzepte? Das sind Fragen, die für mich relevant sind.

Gerade im kommerziellen Umfeld werden oft Programme eingesetzt, die nicht halten, was das Marketing verspricht. Man wählt nicht aus, was man tatsächlich für die Erledigung der Aufgaben benötigt, sondern Anwendungen, deren Beschreibung mit sogenannten Buzzwords vollgestopft ist. Deswegen glaube ich, dass Unternehmen, die sich wieder auf die Kernkompetenzen fokussieren und dazu hoch spezialisierte Anwendungen nutzen, die Gewinner von morgen sind.


Von Missmanagement und Alpha-Geeks

Als ich neulich das Buch „The Manager’s Path“ von Camille Fournier in die Hand bekam, war ich recht schnell an Tom DeMarco erinnert. Dieser hat den Klassiker „Peopleware“ geschrieben und Anfang 2000 das Buch „Adrenalin Junkies und Formular Junkies“ veröffentlicht. Eine Liste an Stereotypen, die man in Softwareprojekten antreffen kann, mit Hinweisen, wie man mit ihnen umgeht. Nach einigen Jahrzehnten im Geschäft kann ich jedes einzelne Wort aus eigener Erfahrung bestätigen. Und es ist auch heute noch immer ein Thema, denn Menschen machen nun einmal Projekte und wir alle haben so unsere Eigenheiten.

Damit Projekte erfolgreich verlaufen, müssen nicht nur technische Herausforderungen gemeistert werden. Auch zwischenmenschliche Beziehungen spielen eine wesentliche Rolle für deren Erfolg. Ein wichtiger Faktor in diesem Zusammenhang, der oft wenig Beachtung findet, ist die Projektleitung. Es gibt Regale voller hervorragender Literatur, wie man ein guter Manager werden kann. Das Problem ist leider, dass nur wenige, die diese Position besetzen, diese nicht ausfüllen und noch weniger Interesse besteht, die eigenen Fertigkeiten weiterzuentwickeln. Das Ergebnis von schlechtem Management sind aufgeriebene und gestresste Teams, extremer Druck im Tagesgeschäft und oft auch Verzug von Lieferterminen. Da braucht man sich auch nicht wundern, wenn dies Auswirkungen auf die Qualität des Produktes hat.

Einer der ersten Sprüche, den ich in meinem Berufsleben gelernt habe, war: Wer glaubt, dass ein Projektleiter Projekte leitet, der glaubt auch, dass ein Zitronefalter Zitronen faltet. Es scheint also eine sehr alte Weisheit zu sein. Was ist aber das wirkliche Problem bei schlechtem Management? Jeder, der eine Stelle für einen Manager zu besetzen hat, ist in der Pflicht, dessen Fertigkeiten und charakterliche Eignung auf Herz und Nieren zu prüfen. Hier lässt man sich schnell von inhaltslosen Floskeln und einer Liste großer Namen in der Branche in der Vita beeindrucken, ohne die tatsächliche Leistung zu hinterfragen. In meiner Erfahrung bin ich vornehmlich auf Projektleiter gestoßen, die oft nicht die notwendigen fachlichen Kenntnisse hatten, um wichtige Entscheidungen zu treffen. Nicht selten wurde ich in IT-Projekten von Managern mit den Worten „Ich bin kein Techniker, macht das unter euch aus.“, abgefertigt. Das ist natürlich fatal, wenn die Person, welche die Entscheidungen treffen soll, diese nicht treffen kann, weil das notwendige Wissen fehlt. Ein Manager im IT-Projekt muss natürlich nicht wissen, welcher Algorithmus schneller terminiert. Hierfür gibt es die Möglichkeit von Evaluierungen, als Grundlage von Entscheidungen. Aber ein Grundverständnis der Programmierung sollte vorhanden sein. Wer nicht weiß, was eine API ist und wieso Module, die später zu einer Software zusammengesetzt werden sollen, durch Versionskompatibilitäten nicht zusammenarbeiten, hat keine Berechtigung, sich als Entscheidungsträger aufzuspielen. Ein Grundverständnis über die Prozesse in der Softwareentwicklung und die verwendeten Programmierparadigmen ist auch für Projektleiter, die nicht am Code arbeiten, unumgänglich.

Ich plädiere daher dafür, dass man nicht nur die Entwickler, die man einstellt, auf ihre Fertigkeiten hin prüft, sondern auch die Manager, die in ein Unternehmen aufgenommen werden sollen. Für mich ist ein absolutes No Go bei der Auswahl meiner Projekte, ein externes Projektmanagement. Das führt in aller Regel nur zu Chaos und Frustration bei allen beteiligten Personen, weswegen ich solche Projekte ablehne. Manager, die nicht ins Unternehmen eingebunden sind und deren Leistung nach dem Erfolg von Projekten bewertet wird, liefern erfahrungsgemäß keine saubere Arbeit ab. Zudem können interne Manager, ebenso wie die Entwickler, durch Mentoring, Trainings und Workshops ihre Fertigkeiten entwickeln und weiter ausbauen. Das Ergebnis sind ein gesundes, entspanntes Arbeitsklima und erfolgreiche Projekte.

Der Titel dieses Artikels weist auf toxische Stereotypen im Projekteschäft hin. Ich bin mir sicher, jeder ist auf den ein oder anderen Stereotypen bereits im beruflichen Umfeld getroffen. Es wird viel diskutiert, wie man mit diesen Zeitgenossen umgehen soll. Ich möchte aber anmerken, dass kaum jemand als „Monster“ geboren wurde. Dass Menschen so sind, wie sie sind, ist das Resultat ihrer Erfahrungen. Lernt ein Kollege, dass er, wenn er gestresst ausschaut und immer hektisch wirkt, als guter Arbeiter wahrgenommen wird, perfektioniert er dieses Verhalten über die Zeit.

Camille Fournier hat es mit dem Begriff „The Alpha Geek“ sehr auf den Punkt gebracht. Jemand, der seine Rolle im Projekt unersetzlich gemacht hat und auf alles eine Antwort hat. Meist verächtlich auf die Kollegen herabschaut, aber nie eine Aufgabe wirklich ohne Nacharbeiten anderer sauber zu Ende bringen kann. Unrealistische Abschätzungen für umfangreiche Aufgaben sind ebenso typisch wie die Relativierung komplexer Sachverhalte. Natürlich ist das der Liebling aller Projektleiter, die sich wünschen, das ganze Team würde aus diesen „Alpha Geeks“ bestehen. Ich bin mir sehr sicher, wenn dieser Traum wahr werden könnte, es die optimale Strafe für die Projektleiter wäre, die solche Menschen erst möglich machen.

Damit man sich im eigenen Unternehmen keine „Alpha Geeks“ züchtet, ist es notwendig, keinen Personenkult zu etablieren und die persönlichen Favoriten gegenüber dem restlichen Team zu überhöhen und auf ein Podest zu stellen. Natürlich ist es auch unabdingbar, stets die Arbeitsergebnisse zu hinterfragen. Wer eine Aufgabe als erledigt markiert und diese Nacharbeiten erfordert, sollte diese Nacharbeiten stets erneut zugewiesen bekommen, bis das Ergebnis zufriedenstellend ist.

Ich persönlich habe die selbe Auffassung wie Tom DeMarco, was die Dynamiken eines Projektes betrifft. Die Produktivität kann man zwar über die Menge der erledigten Aufgaben bewerten, dennoch gibt es auch noch weitere Einflüsse, die eine wichtige Rolle spielen. So habe ich durch meine Erfahrung die Auffassung, dass man, wie bereits erwähnt, sehr viel Wert darauf legen sollte, dass Mitarbeiter die begonnenen Aufgaben sauber und vollständig lösen, bevor sie eine neue Aufgabe annehmen. Kollegen, die eine bestimmte Aufgabe „kleinreden“ und zu geringe, unrealistische Einschätzungen abgeben, genau diese Aufgabe übernehmen. Zudem gibt es auch Kollegen, die zwar einen recht geringen Output haben, dafür aber sehr viel für die Harmonie im Team beitragen.

Wenn ich über Menschen spreche, die ein gesundes Team formen, meine ich damit nicht jeden Tag Süßigkeiten hinzustellen. Es geht um die, die durchaus gute Fähigkeiten haben und diese als Mentor anderen Kollegen beibringen. Meist haben diese Personen einen guten Stand im Team und ihnen wird viel Vertrauen entgegengebracht, weswegen sie auch oft als Mediatoren bei Konflikten gute Ergebnisse erzielen. Es sind nicht die Menschen, die durch falsche Versprechen versuchen, everybodys Darling zu sein, sondern die, die zuhören und sich Zeit nehmen, eine Lösung zu finden. Sie sind oft das Mädchen für alles und haben nicht selten ein ruhiges, unscheinbares Auftreten. Da sie Lösungen haben und oft eine helfende Hand reichen, haben sie selbst eine mittelmäßige Bewertung ihrer Leistung in den typischen Prozessmetriken. Ein guter Manager erkennt diese Personen rasch, weil auf sie in aller Regel Verlass ist. Sie sind ausgeglichen und wirken wenig gestresst, weil sie mit Ruhe und Kontinuität vorgehen.

Natürlich kann man über die Stereotypen in einem Softwareprojekt noch viel mehr sagen, aber ich denke, die bereits getroffenen Ausführungen geben ein gutes Grundverständnis über das, was ich zum Ausdruck bringen möchte. Denn ein erfahrener Projektleiter kann viele der beschriebenen Probleme bereits während ihrer Entstehung wieder abstellen. Dazu gehören natürlich auch solides technisches Wissen und etwas Menschenkenntnis.

Es muss uns natürlich auch bewusst sein, dass erfahrene Projektleiter nicht einfach so da sind. Man muss sie genau wie die Mitglieder eines Teams entwickeln und fördern. Dazu gehört durchaus auch die Rotation durch alle technischen Abteilungen wie Entwicklung, Test und Betrieb. Dazu eignen sich Paradigmen wie Pairprogramming hervorragend. Denn es geht nicht darum, aus einem Manager einen Programmierer oder Tester zu machen, sondern ihm oder ihr ein Verständnis der täglichen Abläufe zu verschaffen. Das stärkt auch das Vertrauen in die Fertigkeiten des gesamten Teams, und Mentalitäten wie: Man müsse die faulen und unfähigen Programmierer kontrollieren und antreiben, damit sie einen Finger rühren, kommen gar nicht erst auf. In Projekten, die regelmäßig gute Qualität abliefern und ihre Termine einhalten, kommt selten der Wunsch auf, alle möglichen Prozessmetriken einzuführen.


Blockchain – eine Einführung

Das Konzept Blockchain ist grundlegender Bestandteil der verschiedenen Kryptobezahlmethoden wie Bitcoin und Ethereum. Was hat es aber mit der Technologie Blockchain auf sich und wozu kann man dieses Konzept noch anwenden? Grundlegend kann man sagen, dass Blockchain wie die Datenstruktur der rückwärtsverketteten Liste aufgebaut ist. Jedes Element der Liste zeigt auf den Vorgänger. Was macht die Blockchain aber nun so besonders?

Blockchain erweitert das Konzept der Liste um verschiedene Rahmenbedingungen. Eine dieser Rahmenbedingungen ist, sicherzustellen, dass kein Element der Liste verändert oder entfernt werden kann. Das lässt sich recht einfach bewerkstelligen. Hierzu verwendet man eine Hashfunktion. Wir codieren über einen Hashalgorithmus den Inhalt eines jeden Elements in der Liste zu einem Hash. Es gibt mittlerweile ein breites Angebot an Hashfunktionen, von denen ein aktueller Standard SHA-512 ist. In nahezu jeder Programmiersprache ist dieser Hashalgorithmus in der Standardbibliothek bereits implementiert und man kann ihn einfach verwenden. Im Konkreten bedeutet es, dass über die gesamten Daten eines Blockes der Hash SHA‑512 gebildet wird. Dieser Hash ist stets eineindeutig und kommt nicht noch einmal vor. Somit dient der Hash als Identifier (ID), um einen Block zu finden. Ein Eintrag in dem Block ist der Verweis auf seine Vorgänger. Dieser Verweis ist der Hashwert des Vorgängers, also seine ID. Bei der Implementierung einer Blockchain ist es essenziell, dass der Hashwert des Vorgängers Bestandteil der Berechnung des Hashwertes des aktuellen Blockes ist. Dieses Detail sorgt dafür, dass die in der Blockchain geänderten Elemente nur sehr aufwendig geändert werden können. Man muss sozusagen für das Element, das man manipulieren möchte, alle nachfolgenden Elemente ebenfalls ändern. Bei der umfangreichen Blockchain mit sehr vielen Blöcken bedeutet so ein Vorhaben einen enormen Rechenaufwand, der nur sehr schwer bis überhaupt nicht zu leisten ist.

Durch diese Verkettung erhalten wir eine lückenlose Transaktionshistorie. Dieser Umstand erklärt auch, weswegen Kryptobezahlmethoden nicht anonym sind. Auch wenn der Aufwand, einen Transaktionsteilnehmer eindeutig zu identifizieren, enorm werden kann. Nutzt dieser Transaktionsteilnehmer zudem noch verschiedene Verschleierungsmöglichkeiten mit unterschiedlichen und nicht durch weitere Transaktionen verknüpften Wallets, steigt der Aufwand exponentiell an.

Natürlich hat der gerade beschriebene Mechanismus noch erhebliche Schwachstellen. Denn Transaktionen, also das Hinzufügen neuer Blöcke, können erst als verifiziert und sicher eingestuft werden, wenn genügend Nachfolger in der Blockchain hinzugekommen sind, die sicherstellen, dass Änderungen wieder schwerer zu bewerkstelligen sind. Für Bitcoin und Co. gilt eine Transaktion als sicher, wenn fünf Nachfolgetransaktionen sind.

Damit es nun nicht nur eine Instanz gibt, die die Transaktionshistorie, also alle Blöcke der Blockchain, aufbewahrt, kommt ein dezentraler Ansatz ins Spiel. Es gibt also keinen zentralen Server, der als Vermittler agiert. Ein solcher zentraler Server könnte durch den Betreiber manipuliert werden. Man hätte so die Möglichkeit, mit genügend Rechenleistung auch sehr umfangreiche Blockchains neu aufzubauen. Im Kontext von Kryptowährungen spricht man hier von einer Reorganisation der Chain. Dies ist auch die Kritik an vielen Kryptowährungen. Außer Bitcoin existiert keine andere dezentrale und unabhängige Kryptowährung. Wenn die Blockchain mit allen ihren enthaltenen Elementen öffentlich gemacht wird und jeder Nutzer eine eigene Instanz dieser Blockchain lokal auf seinem Rechner besitzt und dort Elemente hinzufügen kann, die dann mit allen anderen Instanzen der Blockchain synchronisiert werden, haben wir einen dezentralen Ansatz.

Die Technologie zur dezentralen Kommunikation ohne einen Vermittler nennt sich Peer to Peer (P2P). P2P Netzwerke sind besonders in ihren Entstehungsphasen, also wenn nur wenige Teilnehmer im Netzwerk sind, schwach und angreifbar. Man könnte einfach mit sehr viel Rechenleistung eine große Anzahl von sogenannten Zomi Peers erstellen, die das Verhalten des Netzes beeinflussen. Gerade in Zeiten, in denen das Cloud-Computing mit AWS und der Google Cloud Platform als Anbieter, für vergleichsweise wenig Geld schier endlose Ressourcen bereitstellen kann, ist dies ein nicht zu unterschätzendes Problem. Besonders wenn es einen sehr hohen finanziellen Anreiz für Betrüger gibt, darf man diesen Punkt auf keinen Fall vernachlässigen.

Auch bei P2P gibt es verschiedene Konzepte, die miteinander konkurrieren. Um eine stabile und sichere Blockchain zu implementieren, ist es notwendig, nur auf Lösungen zurückzugreifen, die ohne unterstützende Backbone Server auskommen. Es soll vermieden werden, dass sich eine Master Chain etablieren kann. Daher müssen Fragen geklärt werden, wie sich die einzelnen Peers finden können und mit welchem Protokoll sie ihre Daten synchronisieren. Als Protokoll verstehen wir ein Regelwerk, also ein festes Schema, wie die Interaktion zwischen den Peers geregelt wird. Da bereits dieser Punkt sehr umfangreich ist, verweise ich zum Einstieg in das Thema auf meinen Vortrag 2022.

Eine weitere Eigenschaft von Blockchain‑Blöcken ist, dass sich diese problemlos und mit wenig Mühe auf Gültigkeit hin verifizieren lassen. Hierzu muss lediglich über die gesamten Inhalte eines Blocks der SHA-512 Hash erzeugt werden. Stimmt dieser mit der ID überein, ist der Block gültig. Aber auch zeitrelevante beziehungsweise zeitkritische Transaktionen, wie sie bei Bezahlsystemen relevant sind, lassen sich mit wenig Aufwand erstellen. Dazu werden auch keine komplexen Zeitserver als Vermittler benötigt. Jeder Block wird um einen Zeitstempel erweitert. Dieser Zeitstempel muss allerdings den Ort, an dem er erstellt wird, berücksichtigen, also die Zeitzone mit angeben. Um den Standort der Transaktionsteilnehmer zu verschleiern, können auch alle Uhrzeiten der verschiedenen Zeitzonen auf die aktuelle UTC 0 umgerechnet werden.

Um sicherzustellen, dass die Uhrzeit auch korrekt auf dem System eingestellt ist, kann man einen Zeitserver für die aktuelle Uhrzeit beim Start der Software abfragen und bei Abweichungen einen Hinweis zur Korrektur ausgeben.

Natürlich sind zeitkritische Transaktionen mit einer Reihe von Problemen behaftet. Es muss sichergestellt werden, dass eine Transaktion in einem festgelegten Zeitfenster durchgeführt wurde. Ein Problem, mit dem sich sogenannte Echtzeitsysteme auseinandersetzen müssen. Aber auch das Double Spending Problem muss verhindert werden. Also, dass derselbe Betrag zweimal an unterschiedliche Empfänger gesendet werden kann. Was in einem dezentralisierten Netzwerk die Bestätigung der Transaktion von mehreren Teilnehmern erfordert. Aber auch klassische Race Conditions können ein Problem darstellen. Race Conditions lassen sich durch die Anwendung des Immutable-Entwurfsmusters auf die Block-Elemente beherrschen.

Damit die Blockchain nun nicht durch Spam-Attacken gestört wird, benötigen wir eine Lösung, die das Erstellen eines einzelnen Blocks in der Masse teuer macht. Das erreichen wir, indem wir die Rechenleistung einbeziehen. Hierzu muss der Teilnehmer, der einen Block erstellt, ein Puzzle lösen, das eine ‚gewisse‘ Rechenzeit beansprucht. Wenn ein Spammer das Netzwerk mit vielen Blöcken fluten möchte, steigt seine Rechenleistung exorbitant an und es ist ihm unmöglich, in kurzer Zeit beliebig viele Blöcke zu erzeugen. Dieses kryptografische Puzzle nennt man Nonce, was für „number used only once“ steht. Der Mechanismus Nonce in der Blockchain wird auch oft als Proof of Work (POW) bezeichnet und dient bei Bitcoin zur Verifizierung der Blöcke durch die Miner.

Die Nonce ist eine (pseudo) zufällige Zahl, zu der ein Hash generiert werden muss. Dieser Hash muss dann ‚bestimmte‘ Kriterien erfüllen. Das können zum Beispiel zwei oder drei führende Nullen im Hash sein. Damit man nun keinen beliebigen Hash in den Block einfügt, wird die Zufallszahl, die das Rätsel löst, direkt abgespeichert. Eine bereits genutzte Nounce darf kein weiteres Mal verwendet werden, da sonst das Rätsel umgangen werden kann. Erzeugt man nun aus der Nonce den Hash, muss dieser die Vorgaben z. B. führende Nullen erfüllen, um akzeptiert zu werden.

Da je mehr Blöcke in einer Blockchain enthalten sind, es immer schwieriger wird, eine gültige Nonce zu finden, ist es notwendig, die Regeln für so eine Nonce zyklisch, beispielsweise alle 2048 Blöcke, zu verändern. Das bedeute aber auch, dass die Regeln für eine gültige Nonce ebenfalls den entsprechenden Blöcken zugeordnet werden müssen. Ein solches Regelwerk für die Nonce lässt sich problemlos über eine RegEx formulieren.

Mittlerweile haben wir auch eine beachtliche Menge an Regelwerk für eine Blockchain kennengelernt. Sodass es nun an der Zeit ist, sich ein wenig Gedanken über die Performance zu machen. Würden wir alle einzelnen Blöcke der Blockchain einfach in einer Liste abspeichern, würde uns recht bald der Arbeitsspeicher ausgehen. Jetzt könnte man die Blöcke auch in einer lokalen Datenbank speichern, was auch bei einer Embedded-Lösung wie SQLlite durchaus negative Auswirkungen auf die Geschwindigkeit der Blockchain haben würde. Eine einfache Lösung wäre hier, die Blockchain in gleichlange Teile zu zerlegen, sogenannte Chunks. Ein Chunk hätte sozusagen eine feste Länge von 2048 validen Blöcken und der erste Block eines neuen Chunk zeigt auf den letzten Block des vorhergehenden Chunk. In jedem Chunk kann man auch eine zentrale Regel für die Nonce hinterlegen und mögliche Metadaten wie beispielsweise Min- und Max-Zeitstempel abspeichern.

Wenn wir unseren aktuellen Stand des Blockchain-Regelwerks kurz rekapitulieren, kommen wir aktuell auf drei verschiedene Ebenen. Die größte Ebene ist die Blockchain selbst, welche grundlegende Metainformationen und Konfigurationen enthält. Solche Konfigurationen sind etwa der verwendete Hash Algorithmus. Die zweite Ebene stellen die sogenannten Chunks dar, die eine festgelegte Menge an Block-Elementen enthalten. Wie bereits erwähnt enthalten die Chunks auch Metadaten und Konfigurationen. Das kleinste Element der Blockchain ist der Block selbst, der aus einer ID, den beschriebenen Zusatzinformationen wie Zeitstempel und Nonce und dem Payload besteht. Der Payload ist eine allgemeine Bezeichnung für jedes beliebige Datenobjekt, das durch die Blockchain überprüfbar gemacht werden soll. Für Bitcoin und andere Kryptowährungen ist der Payload die Information, welcher Betrag von Wallet A (Quelle) an Wallet B (Ziel) transferiert wird.

Die Blockchain-Technologie eignet sich aber auch für viele andere Anwendungszenarien. So könnten beispielsweise die Hashwerte von Open-Source-Software Artefakten in einer Blockchain gespeichert werden. Damit könnte man auch Binärdateien aus unsicheren Quellen herunterladen und gegen die entsprechende Blockchain verifizieren. Das gleiche Prinzip wäre auf für die Signaturen von Antivirenprogrammen denkbar. Aber auch im behördlichen Umfeld könnten Anträge und andere Dokumente rechtssicher übermittelt werden. Die Blockchain würde hier als ‚Posteingangsstempel‘ funktionieren. Aber auch Buchhaltung inklusive aller Belege der Warenwirtschaft aus dem Einkauf und der verkauften Artikel und Dienstleistungen sind denkbare Szenarien.

Eine Erweiterung der Blockchain wäre je nach Anwendungsfall die eindeutige Signierung eines Blocks durch den Ersteller. Hierzu käme das klassische PKI Verfahren mit dem öffentlichen und privaten Schlüssel zum Einsatz. Der Unterzeichner speichert in Block seinen öffentlichen Schlüssel, erstellt mittels seines geheimen Schlüssels über den Payload eine Signatur, die als Signatur ebenfalls im Block mitgespeichert wird.

Bisher gibt es zwei frei verfügbare Implementierungen der Blockchain, BitcoinJ und für Ethereum Web3j. Natürlich ist es möglich, mit den gerade beschriebenen Prinzipien auch eine eigene allgemeingültige Blockchain-Implementierung zu erstellen. Hier liegen die Stolperfallen natürlich in den Details, von denen ich in diesem Artikel bereits einige angesprochen habe. Grundsätzlich ist Blockchain aber auch keine Raketentechnologie und für erfahrene Entwickler gut beherrschbar. Wer mit dem Gedanken spielt, sich an einer eigenen Implementierung zu versuchen, hat nun genügend Grundwissen, um sich mit dem notwendigen Detailwissen in den verschiedenen zum Einsatz kommenden Technologien tiefer vertraut zu machen.


Privatsphäre

Immer wieder begegne ich Aussagen wie, „Ich nutze Apple wegen des Datenschutzes.“ oder „Unter Linux gibt es keine Viren.“ und so weiter und so fort. Im richtigen Leben schmunzle ich dann in mich hinein und verkneife mir eine Antwort. Diese Menschen sind meist Jünger einer bestimmten Marke, die sie abgöttisch anbeten und sogar mit ihrem Leben verteidigen würden. Daher spare ich meine Energie für sinnvolleres auf, wie zum Beispiel diesen Artikel hier zu verfassen.

Mein Bestreben, ist, möglichst wenig technische Details beziehungsweise auch wenig Fachsprache zu verwenden, damit auch die Menschen ohne entsprechenden Hintergrund Zugang zu diesem Thema finden. Sicher mag der ein oder andere Skeptiker nach Beweisen meiner Aussagen rufen, die meine Behauptungen zu belegen. Diesen Personen sei gesagt, dass es für die einzelnen Aussagen genügend Stichworte gibt, mit denen man sich selbst auf die Suche machen kann, und entsprechend genügend Primärquellen findet, die abseits von KI und Wikipedia existieren.

Wenn man darüber sinniert, was Freiheit eigentlich bedeutet, stößt man oft auf Aussagen wie: „Freiheit ist, das zu tun, worauf man Lust hat, ohne dabei die Freiheit anderer Menschen zu beeinträchtigen.“ Diese Definition beinhaltet auch, die Tatsache, dass vertrauliche Aussagen auch vertraulich bleiben. Hier gibt es allerdings schon Bestrebungen, lange vor der Verfügbarkeit von elektronischen Geräten zur Kommunikation. Nicht umsonst gibt es eine jahrtausendealte Kunst namens Kryptografie, mit der Nachrichten, die auf unsicheren Wegen übermittelt werden, für Uneingeweihte unverständlich bleiben. Dass die Begehrlichkeiten, die Gedanken anderer Menschen zu erfahren, sehr alt sind, besagt auch der Spruch, dass die beiden ältesten Gewerbe der Menschheit die käufliche Liebe und die Spionage sind. Daher kann man sich die Frage stellen: Wieso sollte dies nun im Zeitalter der Kommunikation anders sein?

Besonders unbedachte Zeitgenossen begegnen dem Thema mit der Einstellung, sie hätten ohnehin nichts zu verbergen, wozu sollten sie dann auf die eigene Privatsphäre bedacht sein? Ich persönlich gehöre zu der Gruppe Menschen, die diese Einstellung für sehr gefährlich halten, da sie machthungrigen Gruppierungen Tür und Tor für den Missbrauch öffnet. Jeder Mensch hat Bereiche in seinem Leben, die er nicht in die Öffentlichkeit gezerrt bekommen möchte. Hier kann es sich um spezielle sexuelle Vorlieben handeln, Untreue dem Partner gegenüber oder eine Vorliebe für das Glücksspiel, also Dinge, die eine perfekte Fassade von moralischer Integrität schnell bröckeln lässt.

In der DDR glaubten viele Menschen, das sie selbst zu unbedeutend waren, als dass der berüchtigte Inlandsgeheimdienst STASI an ihnen Interesse haben könnte. Wie sehr sie mit ihrer Einschätzung danebenlagen, zeigte die Öffnung der STASI‑Unterlagen nach der deutschen Wiedervereinigung. In diesem Zusammenhang möchte ich nur auf die gültige Gesetzeslage in der EU hinweisen, die Errungenschaften wie Hatespeech, Chatkontrolle und Vorratsdatenspeicherung vorweisen kann. Auch die Privatwirtschaft hat genügend Gründe, mehr über jeden einzelnen Menschen zu erfahren. Denn so lässt sich dieser optimal manipulieren und zum Kauf von Dienstleistungen und Produkten animieren. Eine Zielstellung von Unternehmen ist, den optimalen Preis ihrer Angebote ermitteln zu können, also den größtmöglichen Gewinn zu erzielen. Das erreicht man durch Methoden der Psychologie. Oder glauben Sie wirklich, dass Produkte wie ein Telefon, mit dem man fotografieren kann, wirklich den Preis wert sind, der dafür verlangt wird? Wir sehen also: Es gibt genügend Gründe, wieso personenbezogene Daten durchaus einen hohen Wert haben können. Betrachten wir uns daher einmal die vielen technologischen Halbwahrheiten an, die in der breiten Öffentlichkeit so kursieren. Viele dieser Halbwahrheiten habe ich auch bei Technologieprofis vernommen, die selbst viele Dinge nicht hinterfragt haben.

Bevor ich aber in die Details einsteige, möchte ich noch eine essenzielle Aussage voranstellen. Es gibt keine sichere und private Kommunikation, wenn elektronische Geräte involviert sind. Wer ein absolut vertrauliches Gespräch führen möchte, geht bei starkem Wind auf ein freies Feld, mit einem Sichtradius von mindestens 100 Metern und verdeckt beim Sprechen seinen Mund. Natürlich ist mir klar, dass auch dort Mikrofone versteckt sein könnten. Diese Aussage ist eher demonstrativ und zeigt, wie schwer es ist, eine vertrauliche Umgebung zu schaffen.

Beginnen wir mit der beliebten Marke Apple. Viele der Apple-Nutzer glauben, ihre Geräte wären besonders sicher. Das stimmt nur so weit, dass durchaus Fremde, die versuchen, sich unautorisierten Zugriff auf die Geräte zu verschaffen, große Hürden überwinden müssen. Dafür sind viele Mechanismen in den Betriebssystemen enthalten, die es erlauben, zum Beispiel auf den Telefonen Anwendungen und Inhalte zu blockieren.

Das Unternehmen Microsoft, steht dem in nichts nach und geht noch einige Schritte weiter. Seitdem das Internet für die breite Masse verfügbar ist, rätselt man darüber, welche Telemetriedaten der Nutzer Windows an den Mutterkonzern sendet. Windows 11 treibt alles noch viel mehr auf die Spitze und speichert jeden Tastenanschlag und macht alle paar Sekunden einen Screenshot vom Bildschirm. Angeblich werden diese Daten nur lokal auf dem Computer gespeichert. Das kann man natürlich gern glauben, und selbst wenn es so wäre, handelt es sich hier um eine enorme Sicherheitslücke. Denn jeder Hacker, der einen Windows 11 Rechner kompromittiert, kann dann diese Daten auch auslesen und hat Zugriff auf Onlinebanking und alle möglichen Accounts.

Zudem verweigert Windows 11 seinen Dienst bei angeblich veralteten Prozessoren. Dass Windows schon immer sehr ressourcenhungrig war, ist keine Neuheit. Der Grund der Restriktion auf alte CPUs hat aber einen anderen Grund. CPUs der neuen Generation haben ein sogenanntes Sicherheitsfeature, mit dem sich der Computer eindeutig identifizieren und über das Internet deaktivieren lässt. Das Stichwort, um das es hier geht, lautet Pluton Security Processor mit dem Trusted Platform Module (TPM 2.0).

Wie sehr die Begehrlichkeiten von Microsoft sind, alle möglichen Informationen über die eigenen User abzugreifen, zeigen auch die Änderungen der AGB um das Jahr 2022. Diese bekamen einen neuen Abschnitt, der Microsoft die Erlaubnis erteilt, alle durch ihre Produkte erlangten Daten zum Trainieren von künstlicher Intelligenz verwenden zu dürfen. Zudem behält man sich das Recht vor, bei erkannter Hatespeech den Nutzer von allen Microsoft Produkten auszuschließen.

Aber keine Sorge, nicht nur Microsoft hat solche Disclaimers in den eigenen AGB. Auch Social Media Platformen wie Meta, besser bekannt unter den Produkten Facebook und WhatsApp, oder die Kommunikationsplattform Zoom agieren so. Die Liste solcher Anwendungen ist natürlich weitaus länger. Es ist jeder Einzelne dazu eingeladen, sich vorzustellen, welche Möglichkeiten die bereits beschriebenen Dinge eröffnen.

Ich habe ja bereits Apple als problematisch im Bereich Sicherheit und Privatsphäre erwähnt. Aber auch Android, das Betriebssystem von Google für SMART‑Fernseher und Telefone, gibt enormen Raum für Kritik. Nicht ganz ohne Grund kann man aus den Telefonen die Akkus nicht mehr entfernen. Denn Android verhält sich genauso wie Windows und sendet alle möglichen Telemetriedaten an den Mutterkonzern. Hierzu kommt noch der 2025 bekannt gewordene Skandal des Herstellers Samsung. Dieser hat ein israelisches, verstecktes Programm namens AppCloud auf seinen Geräten, von dem sich nur erahnen lässt, welchen Zweck es erfüllt. Vielleicht hilft auch die Erinnerung, als im Jahr 2023 bei vielen Palästinensern und anderen von Israel erklärten Feinden die Pager explodiert sind. In der Securityszene ist es kein Geheimnis, dass Israel im Bereich Cybersecurity und Cyberattacken an einsamer Spitze steht.

Ein anderes Thema bei Telefonen ist die Verwendung sogenannter Messenger. Neben den bekannten wie WhatsApp und Telegram gibt es auch ein paar Nischenlösungen wie Signal und Session. Alle diese Anwendungen sprechen von einer Ende zu Ende Verschlüsselung für sichere Kommunikation. Es ist schon richtig, dass Hacker hier so ihre Schwierigkeiten haben, um an die Informationen zu kommen, wenn sie nur den Netzwerkverkehr mitschneiden. Was aber nach erfolgreicher Übertragung und der Entschlüsselung auf dem Zielgerät dann mit der Nachricht passiert, steht auf einem anderen Blatt. Wie sonst sollten sich die Meta AGB mit den bereits enthaltenen Passagen erklären lassen?

Wenn man alle die bereits erwähnten Tatsachen zusammen nimmt, muss man sich nicht wundern, wieso viele Geräte wie Apple, Windows und Android erzwungene Updates etabliert haben. Natürlich dient nicht alles der totalen Kontrolle. Auch das Thema Resilienz, welches Geräte vorzeitig altern lässt, um diese durch Neue zu ersetzen, ist ein Grund.

Nun gibt es natürlich auch genügend Angebote, die ihren Nutzern enorme Sicherheit versprechen. An erster Stelle sei das freie Open Source Betriebsystem Linux erwähnt. Es gibt viele verschiedene Linux-Derivate und nicht alle behandeln das Thema Security und Privatsphäre mit der gleichen Priorität. Die von der Firma Canonical veröffentlichte Distribution Ubuntu, erhält regelmäßig Kritik. So war um das Jahr 2013 das Unity Desktop voll mit Werbung, was viel Ablehnung erfahren hat. Auch dass es unter Linux keine Viren gäbe, ist ein Mythos. Sie gibt es durchaus und der Virenscanner unter Linux heißt ClamAV, nur ist deren Verbreitung aufgrund der geringen Privatinstallationen im Vergleich zu Windows weniger verbreitet. Außerdem gelten bisher Linuxnutzer als ein wenig nerdig und klicken nicht so schnell auf verdächtige Links. Wer aber dann unter Linux all die tollen Anwendungen wie Skype, Dropbox, KI Agenten und so weiter installiert hat, hat gegenüber der Big Tech Industrie keine verbesserte Sicherheit.

Ähnlich verhält es sich auch mit sogenannten „degoggeled“ Smart­phones. Auch hier ist ein Problem, die verfügbare Hardware, die sehr reguliert ist. Aber auch die Alltagstauglichkeit zeigt oft Grenzen auf. Diese Grenzen finden sich bereits im familiären Umfeld und bei Freunden, die sich kaum von WhatsApp und Co. abbringen lassen. Aber auch Onlinebanking kann hier einem erhebliche Schwierigkeiten bereiten, denn Banken bieten ihre Apps aus Sicherheitsgründen nur über den verifizierten Google Play Store an.

Wir sehen, das Thema ist sehr umfangreich und ich habe nicht einmal alle Punkte aufgezählt, noch bin ich sehr in die Tiefe gegangen. Ich hoffe, ich konnte dennoch ein wenig Sensibilisierung erreichen, dass zumindest das Smartphone nicht überall mitgenommen und auch mehr Zeit ohne die ganzen technischen Geräte wieder in der Wirklichkeit mit anderen Menschen verbracht wird.

Zähl auf mich – Java Enums

Eigentlich denkt man als erfahrener Entwickler oft, dass reine CORE Java Themen eher was für Anfänger sind. Das muss aber nicht unbedingt so sein. Ein Grund ist natürlich die Betriebsblindheit, die sich bei ‚Profis‘ mit der Zeit einstellt. Dieser Betriebsblindheit kann man nur entgegenwirken, wenn man sich gelegentlich auch mit vermeintlich vertrauten Themen erneut beschäftigt. Aufzählungen in Java sind leider zu Unrecht etwas unbeachtet und finden viel zu wenig Anwendung. Ein möglicher Grund für diese stiefmütterliche Behandlung können auch die vielen im Netz verfügbaren Tutorials zu Enums sein, die lediglich eine triviale Verwendung demonstrieren. Fangen wir zuallererst also damit an, wo Enums in Java ihre Verwendung finden.

Gehen wir einmal von ein paar einfachen Szenarien aus, die uns im Entwickleralltag begegnen. Stellen wir uns vor, wir müssen eine Hashfunktion implementieren, die mehrere Hash-Algorithmen wie MD5 und SHA-1 unterstützen kann. Als Einstiegspunkt haben wir auf Benutzerebene dann oft eine Funktion, die so oder ähnlich ausschauen kann: String hash(String text, String algorithm); – eine technisch korrekte Lösung.

Ein anderes Beispiel kann das Logging sein. Um einen Logeintrag zu schreiben, könnte die Methode wie folgt aussehen: void log(String message, String logLevel); und so lassen sich die Beispiele in diesem Stil beliebig fortführen.

Das Problem dieser Variante sind freie Parameter wie logLevel und algorithm, die für den korrekten Gebrauch nur eine sehr begrenzte Anzahl von Möglichkeiten gestatten. Das Risiko, dass Entwickler im Projektstress diesen Parameter falsch befüllen, ist recht hoch. Tippfehler, Variationen in Groß- und Kleinschreibung und so weiter sind mögliche Fehlerquellen. In der Java API gibt es durchaus einige solcher verbesserungswürdigen Designentscheidungen.

Um die Verwendung der API, also der nach außen genutzten Funktionen, zu verbessern, führen wie so oft viele Wege nach Rom. Ein Weg, der durchaus öfter zu sehen ist, ist die Verwendung von Konstanten. Um die Lösung ein wenig besser zu verdeutlichen, greife ich das Beispiel der Hash-Funktionalität auf. Es sollen die beiden Hash-Algorithmen MD5 und SHA-1 in der Klasse Hash unterstützt werden.

void Hash {
	
	public final static MD5 = "1";
	public final static SHA-1 = "2";

	/**
	 * Creates a hash from text by using the chosen algorithm.
	 */
	public String calculateHash(String text, String algorithm) {
		String hash = "";

		if(algorithm.equals(MD5)) {
			hash = MD5.hash(text);
		}
		if(algorithm.equals(SHA-1)) {
			hash = SHA-1.hash(text);
		}
		return hash;
	}
}

// Call
calculateHash("myHashValue", Hash.MD5);

In der Klasse Hash werden die beiden Konstanten MD5 und SHA-1 definiert, um anzuzeigen, welche Werte für den Parameter algorithem gültige Werte darstellen. Entwickler mit etwas Erfahrung erkennen diese Konstellation recht schnell und verwenden sie auch korrekt. Auch hier ist die Lösung technisch gesehen absolut korrekt. Aber auch wenn Dinge syntaktisch richtig sind, heißt es nicht, dass sie im semantischen Kontext bereits eine optimale Lösung darstellen. Die hier vorgestellte Strategie missachtet nämlich die Entwurfskriterien für objektorientierte Programmierung. Obwohl wir bereits durch die Konstanten gültige Eingabewerte für den Parameter algorithm bereitstellen, gibt es keinen Mechanismus, der die Verwendung der Konstanten erzwingt.

Nun könnte man argumentieren, das ist doch nicht wichtig, solange die Methode mit einem gültigen Parameter aufgerufen wird. Dem ist aber nicht so. Denn jeder Aufruf der Methode calculateHash ohne die Verwendung der Konstanten führt bei Refactorings zu möglichen Problemen. Will man aus Vereinheitlichung beispielweise den Wert “2“ in sha1 ändern, wird das überall da zu Fehlern führen, wo die Konstanten nicht zum Einsatz kommen. Wie können wir es also besser machen? Die bevorzugte Lösung sollte die Verwendung von Enums sein.

Alle in Java definierten Enums sind von der Klasse java.lang.Enum [2] abgeleitet. Eine Auswahl der Methoden ist:

  • name() gibt den Namen dieser Enum-Konstante genau so zurück, wie er in ihrer Enum-Deklaration angegeben ist.
  • ordinal() gibt die Ordnungszahl dieser Enum-Konstante zurück (ihre Position in der Enum-Deklaration, wobei der ersten Konstante die Ordnungszahl Null zugewiesen wird).
  • toString() gibt den Namen dieser Enum-Konstante so zurück, wie er in der Deklaration enthalten ist.

Enums gehören in Java von Anfang an zum Sprachkern und sind recht intuitiv zu benutzen. Für den Parameter algorithm erzeugen wir mit den beiden Werten MD5 und SHA1 die Enumklasse HashAlgorithm.

public enum HashAlgorithm {
MD5, SHA1
}

Dies ist die einfachste Variante, wie man ein Enum definieren kann. Eine einfache Aufzählung der gültigen Werte als Konstanten. In dieser Notation sind Konstantenname und Konstantenwert identisch. Wichtig beim Umgang mit Enums ist sich bewusst zu sein das die Namenkonventionen für Konstanten gelten.

Die Namen von als Klassenkonstanten deklarierten Variablen und von ANSI-Konstanten sollten ausschließlich in Großbuchstaben geschrieben und die Wörter durch Unterstriche („_“) getrennt werden. (ANSI-Konstanten sollten zur Vereinfachung der Fehlersuche vermieden werden.) Bsp.: static final int GET_THE_CPU = 1;

[1] Oracle Dokumentation

Diese Eigenschaft führt uns zum ersten Problem bei der vereinfachten Definition von Enums. Wenn wir aus irgendeinem Grund anstatt SHA-1 anstatt SHA1 definieren wollen, wird das zu einem Fehler führen, da “-“ nicht der Konvention für Konstanten entspricht. Daher findet sich für die Definition von Enums meist folgendes Konstrukt:

public enum HashAlgorithm {

    MD5("MD5"),
    SHA1("SHA-1");

    private String value;

    HashAlgorithm(final String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }
}


In diesem Beispiel wird die Konstante SHA1 um einen String Wert “SHA-1“ erweitert. Um an diesen Wert zu gelangen, ist es notwendig, einen Zugriff dafür zu implementieren. Dieser Zugriff erfolgt über die Variable value, welche den zugehörigen Getter getValue() besitzt. Damit die Variable value auch befüllt wird, benötigen wir noch einen zugehörigen Konstruktor. Wie die verschiedenen Zugriffe auf den Eintrag SHA1 mit den entsprechenden Ausgaben zeigt der nachfolgende Testfall.

public class HashAlgorithmTest {

    @Test
    void enumNames() {
        assertEquals("SHA1",
                HashAlgorithm.SHA1.name());
    }

    @Test
    void enumToString() {
        assertEquals("SHA1",
                HashAlgorithm.SHA1.toString());
    }
    
    @Test
    void enumValues() {
        assertEquals("SHA-1",
                HashAlgorithm.SHA1.getValue());
    }


    @Test
    void enumOrdinals() {
        assertEquals(1,
                HashAlgorithm.SHA1.ordinal());
    }
}


Zuerst greifen wir auf den Namen der Konstante zu, der für unser Beispiel SHA1 lautet. Das gleiche Ergebnis erhalten wir mit der toString() Methode. Den Inhalt von SHA1, also den Wert SHA-1 erhalten wir über den Aufruf unserer definierten Methode getValue(). Zusätzlich kann noch die Position von SHA1 in der Enum abgefragt werden. Dies ist für unser Beispiel die zweite Stelle, an der SHA1 vorkommt, und hat dadurch den Wert 1. Schauen wir uns für die Implementierung der Hash-Klasse aus Listing 1 die Änderung für Enums an.

public String calculateHash(String text, HashAlgorithm algorithm) {
    String hash = "";
    switch (algorithm) {
        case MD5:
		hash = MD5.hash(text);
            break;
        case SHA1:
		hash = SHA1.hash(text);
            break;
    }
    return hash;
}

//CaLL
calculateHash(“text2hash“, HashAlgorithm.MD5);

Wir sehen in diesem Beispiel eine deutliche Vereinfachung der Implementierung und erreichen zudem eine sichere Verwendung für den Parameter algorithm, der nun durch die Enum bestimmt wird. Sicher gibt es einige Kritiker, die möglicherweise die Menge des zu schreibenden Codes bemängeln und darauf verweisen, dass dies viel kompakter möglich wäre. Solche Argumente kommen eher von Personen, die keine Erfahrung mit großen Projekten von mehreren Millionen Zeilen Quelltext konfrontiert wurden oder nicht in einem Team mit mehreren Programmierern zusammenarbeiten. Im objektorientierten Entwurf geht es nicht darum, möglichst jedes überflüssige Zeichen zu vermeiden, sondern lesbaren, fehlertoleranten, ausdruckstarken und leicht änderbaren Code zu schreiben. Alle diese Attribute haben wir in diesem Beispiel mit Enums abgedeckt.

Laut dem Tutorial von Oracle für Java Enums [3] sind noch viel komplexere Konstrukte möglich. Enums verhalten sich wie Java Klassen und können auch mit Logik angereichert werden. Die Spezifikation sieht hier vor allem die Methoden compare() und equals() vor, was Vergleichen und Sortieren ermöglicht. Für das Beispiel der Hashalgorithmen würde diese Funktionalität keinen Mehrwert bringen. Auch sollte man grundsätzlich davon Abstand nehmen, weitere Funktionalität beziehungsweise Logik in Enums unterzubringen, da diese ähnlich wie reine Datenklassen behandelt werden sollten.

Dass Enums durchaus ein wichtiges Thema in der Java Entwicklung darstellen, zeigt auch der Umstand, dass J. Bloch in seinem Buch “Effective Java“ dazu ein ganzes Kapitel mit knapp 30 Seiten gewidmet hat.

Damit haben wir ein ausführliches Beispiel über die korrekte Verwendung von Enums durchgearbeitet und vor allem auch erfahren, wo dieses Sprachkonstrukt in Java eine sinnvolle Anwendung findet.

Ressourcen

Abonnement / Subscription

[English] This content is only available to subscribers.

[Deutsch] Diese Inhalte sind nur für Abonnenten verfügbar.