Ich: „Ich muss leider mein PC neu-starten, wegen ein Windows-Update…“
Chat-GPT: „Möge dein Neustart schnell sein, dein Update kompatibel,
und dein System nachher genauso stabil wie dein Kaffee stark.“
😰😅
Kategorie: Computer & IT
Hier befinden sich Beiträge rund um Programmieren, User Experience, Sicherheit, Privatsphäre udg.
Warum eure Software mehr Personal frisst als Weihnachtskekse 🍪💻
Oder: Was Omas, Stanzmaschinen und LEGO euch über Software-Entwicklung beibringen können
Es gibt Firmen, die seit Jahrzehnten die gleichen Produkte, Maschinen oder Anlagen herstellen – und dafür Software benötigen. Seit Jahrzehnten beschäftigen sie Software-Entwickler. Und jedes Jahr brauchen sie mehr davon: mehr Entwickler, mehr Architekten, mehr Projektleiter. Die Kosten steigen, die Teams wachsen.
Und doch fragt sich niemand:
👉 „Warum ist das so?“
👉 „Warum geben wir jedes Jahr mehr für Software aus?“
Vielleicht helfen ein paar Vergleiche …
Die Wirtschaftlichkeit hausgemachter Weihnachtskekse 🎄🍪
Stell dir Oma beim Keksebacken vor:
- Holt sie jedes Jahr neue Keksformen? Nein.
- Braucht sie immer mehr Ausstecher, um dieselben Vanillekipferl zu machen? Natürlich nicht.
Die Formen halten jahrelang – und die Rezepte sowieso.
Die Wirtschaftlichkeit der Stanzmaschinen 🏭🔩
Es gibt Firmen, die Blech stanzen. Sie kaufen sich einmal Stanzmaschinen, die jahrzehntelang laufen.
Nur die Formen (die Werkzeuge) werden ab und zu getauscht – je nach Auftrag oder Abnutzung.
Keiner käme auf die Idee, die ganze Maschine jedes Jahr wegzuschmeißen.
LEGO® und die Kunst der Wiederverwendung 🧱✨
LEGO® bringt ständig neue Sets heraus – Raumschiffe, Schlösser, Dinosaurier, super geile Kampfroboter mit Laser, Phaser und Chat GPT 😉. Aber die meisten Steine sind seit Jahrzehnten gleich: Noppen oben, Löcher unten.
Die Maschinen, die die Steine spritzen, laufen jahrzehntelang. Sie werden nur ersetzt, wenn Automatisierung, Energieeffizienz oder Industrie-4.0-Spielereien echte Vorteile bringen.
Fazit 🤔
Liebe Firmen,
wenn ihr seit Jahrzehnten Software entwickelt und trotzdem jedes Jahr mehr Entwickler braucht, dann stellt euch bitte mal die Frage: Warum?
Vielleicht liegt’s daran, dass eure Software gar nicht so soft ist.
Vielleicht ist sie eher wie Hardware: starr, schwerfällig und unflexibel.
Und wenn das so ist … dann wundert euch bitte nicht, dass die Personalkosten explodieren. 😉
Wenn Software-Updates mehr kaputt machen als sie reparieren: Ein persönlicher Erfahrungsbericht mit GIMP 3.0.4
Mit GIMP 3.0.4 wurde aus einem stabilen Werkzeug ein Bug-Monster: blockierte Shortcuts, verwaiste Dialoge, kaputte Export- und Font-Funktionen. Der Release wirkt wie KI-generierter Code ohne echte Tests – ein Beispiel dafür, dass KI, CI/CD und Automatisierung keine menschliche Qualitätskontrolle ersetzen können.
Vor wenigen Minuten habe ich über 1 Stunde 30 Minuten damit verloren, der GIMP-Community auf GitLab mehrere Bugs zu melden. Normalerweise mache ich das gerne, wenn ich auf Fehler stoße – schließlich lebt Open-Source-Software davon, dass Nutzer:innen Rückmeldung geben. Aber diesmal war es anders: Die Anzahl, Art und Systematik der Bugs in GIMP 3.0.4 geben mir ein sehr ungutes Gefühl.
Vor dem Update lief alles perfekt
Mit der Version vor 3.0.4 war ich rundum zufrieden. Alles funktionierte reibungslos, die Bedienung war konsistent, und es gab keine Stolperfallen im Workflow. Eigentlich hätte es kein Update gebraucht. Doch aufgrund des Splashscreens mit der neuen Versionsbenachrichtigung habe ich das Update trotzdem eingespielt – und plötzlich ging nichts mehr wie zuvor.
Ein Update voller Stolperfallen
Die Liste der Fehler ist lang, hier nur ein Auszug:
- GIMP hat plötzlich einen globalen Keyboard Hook, der selbst außerhalb von GIMP alle Shortcuts wie Ctrl+C, Ctrl+V oder Ctrl+S blockiert (VS Code, VS 2022, Android Studio, Linqpad, Notepad++ usw.)
- Mehrere Dialogfenster verlieren ihren Kontext und werden zu „verwaisten“ Fenstern, die sich unkontrolliert vervielfachen.
- Im Export-Dialog wächst Text nicht nach rechts, sondern nach links aus dem Fenster hinaus – und die restliche UI reagiert nicht mehr.
- Die Font-Auswahl und Größenänderung verhält sich grotesk: Statt den Wert im Feld zu ändern, landet meine Eingabe im eigentlichen Bildtext. (Mein Verdacht: die Beschreibung für Code-generierender KI war nicht eindeutig und missverständlich und dadurch hat der KI die Textfelder von Font-Eigenschaften mit dem Text im Bild (Layer) verwechselt. Das passiert oft und ist typisch für Coder mit sehr wenig Erfahrung in Coding und Software-Engineering)
- Nach dem Rotieren oder Einfärben von Ebenen entstehen nach dem Zuschneiden plötzlich verschobene Layer-Kopien.
Das sind keine Kleinigkeiten, sondern fundamentale Fehler, die das Arbeiten massiv behindern.
Mein Verdacht: KI-Code ohne echte Tests
Die Häufung und Art dieser Bugs weckt bei mir einen starken Verdacht:
- Es wirkt, als wären viele Code-Änderungen automatisiert entstanden, möglicherweise mit Hilfe von KI-generiertem Code. Z.B. durch unzureichende, nicht-eindeutige und missverständliche Beschreibung für KI, wurde ein Code generiert der zwar mit kein(e) einzige(r) Compiler-Fehler/Warnung übersetzt werden (und laufen) kann, aber sich bei der Nutzung völlig falsch verhält.
- Darauf aufbauend hat man sich blind auf CI/CD-Pipelines verlassen, ohne dass echte Menschen die Software in Alltagsszenarien getestet haben.
- Das Ergebnis: ein Release, das wie ein Krebs-Geschwür über die Community ausgerollt wurde.
Natürlich ist das nur mein Eindruck als Nutzer (mit 17+ Jahren Erfahrung in Software-Engineering und Entwicklung). Aber die Systematik der Fehler lässt kaum an Einzelfälle glauben.
KI ersetzt weder Menschen noch Tests durch Menschen
Ich möchte hier einen Punkt betonen: KI kann helfen, Code schneller zu schreiben oder Vorschläge zu liefern. Aber ohne menschliche Qualitätskontrolle, manuelles Testen und kritisches Hinterfragen wird jede Software zur Zumutung. Continuous Delivery (CD) und Continuous Integration (CI) sind mächtige Werkzeuge – aber sie ersetzen nicht das Verständnis für Usability und händisches Durchklicken, das echte Fehler sichtbar macht.
Fazit
Software-Updates sollten Verbesserungen bringen, nicht Regressionen. Im Fall von GIMP 3.0.4 war das Gegenteil der Fall. Ich musste auf die vorherige Version zurückrollen, weil grundlegende Dinge nicht mehr funktionierten.
Mein Appell an alle Entwickler:innen (egal ob Open Source oder kommerziell):
- Nutzt KI, aber lasst sie nicht allein entscheiden.
- Vertraut auf CI/CD, aber ergänzt sie mit echten Tests durch Menschen.
- Denkt an eure Nutzer:innen – sie verlieren sonst Stunden ihrer Lebenszeit für Dinge, die gar nicht hätten passieren dürfen.
Ubuntu kopiert Mircosaft
Vor etwa einem Monat berichtete ein Freund und ehemaliger Studienkollege in einem Jitsi-Online-Meeting enttäuscht von der „do-release-upgrade„-Funktion unter Ubuntu Linux. Er klagte über ein kläglich gescheitertes Release-Upgrade, das aufgrund zahlreicher Fehler abbrach, die vorgenommenen Änderungen teilweise rückgängig machte, jedoch ein beschädigtes und nicht mehr funktionstüchtiges System hinterließ.
Ein anderer Freund und Admin wollte daraufhin meine Meinung als langjähriger „Linux-Experte“ hören. Ich sehe mich zwar nicht als den Linux-Experten, aber ich sammle seit 1998 (begonnen mit Corel Linux) Erfahrungen im Umgang mit Linux-Systemen. Seit meiner ersten Begegnung mit Ubuntu Linux 4.10 LTS (etwa 2004 oder 2005) war ich begeistert. Im Vergleich zu anderen Distributionen wie SuSE (6.3), Mandrake, Red Hat oder Debian erkannte Ubuntu die Hürden, mit denen selbst IT-Fachleute und Informatikstudierende zu kämpfen hatten: aufwändige Installationen, komplexe Konfigurationen, zeitraubende Problemlösungen.
Ubuntu stellte nicht nur ISO-Images kostenlos online zur Verfügung, sondern versendete auch gratis CDs in 10er-Packs – nicht nur für Studierende. Die Installation war intuitiv, verständlich und angenehm vertraut – ähnlich wie Windoof von Mircosaft. Bereits während der Installation wurden angeschlossene Peripheriegeräte meist automatisch erkannt, die passenden Kernel-Module installiert, und das System war nach der Installation einsatzbereit: mit OpenOffice (dem Vorgänger von LibreOffice), Firefox und weiteren Anwendungen für Büro- und Multimedia-Zwecke.
Aktuelle System- und Softwareupdates konnten optional schon während der Installation mitinstalliert werden, sodass man sofort ein vollständig aktualisiertes System nutzen konnte. Auch spätere Updates ließen sich unkompliziert finden und installieren – sofern man keine exotische oder besonders individuelle Hardware benutzte.
Kurz gesagt: Man installierte Ubuntu und konnte anschließend direkt produktiv arbeiten – ganz im Gegensatz zu vielen anderen Linux-Distributionen, die ihre Nutzer regelmäßig zur manuellen Nacharbeit zwangen.
Randnotiz: Meine frühere Lieblingsdistribution war Mandrake Linux (heute Mandriva), die mit KDE als grafischer Oberfläche geliefert wurde und die meisten Peripheriegeräte sowie Anwendungen direkt einsatzfähig mitbrachte. Zuvor hatte ich SuSE Linux (ab Version 6.3) verwendet, mich jedoch aus Frust mit Version 8.x oder 9.x davon verabschiedet. Einziger Vorteil damals: gute deutsche Dokumentation und umfangreiche Hardwareunterstützung, etwa für Wacom-Tablets, HP-Drucker und Scanner.
Gestern wagte ich auf einem wichtigen Ubuntu-Server den Befehl „do-release-upgrade“ – und wurde enttäuscht. Der Upgrade-Prozess erkannte zahlreiche Probleme und versuchte, das System in den Ursprungszustand zurückzusetzen. Trotzdem zeigte das System nach Abschluss an, dass es auf die neueste Version aktualisiert sei. Wie kann das sein? Nur der Kernel, einige Dienste und wenige Anwendungen wurden aktualisiert – eine vollständige Rücksetzung fand offenbar nicht statt.
Ich war gezwungen, das gesamte System manuell zu prüfen: Funktionieren alle Dienste? Wurden durch Up-/Downgrades Sicherheitslücken erzeugt? Das kostete mich mehrere Stunden.
Offenbar folgt auch Ubuntu inzwischen dem Prinzip „Tippen first, Bedenken second!“ – ganz wie die Kollegen bei Mircosaft in Redmond, wo Copy-and-Paste-Entwicklung per Google oder ChatGPT zur Praxis geworden zu sein scheint.
Als ehemaliger Verantwortlicher für die Update-Entwicklung von über 16.000 einarmigen Banditen (Spielautomaten) und 4.500 Point-of-Sale-Systemen weiß ich, wie herausfordernd robuste Update-Routinen sind – insbesondere bei heterogener Hardware und Software für verschiedene Kunden. Zum Glück war unsere Umgebung überschaubar: vier Betriebssysteme (Windows NT 4, 2000, XP und DOS 7.x), bekannte Hardwarekonstellationen.
Ein Ausfall konnte teure Folgen haben: Im September 2007 hatten zwei Geräte in einem Londoner Shop innerhalb einer Woche rund eine Viertelmillion Pfund umgesetzt – doch die verschlüsselten Logdateien wurden nicht automatisch zur Zentrale übertragen. Mit einem speziellen Update konnte ich die Übertragung erzwingen – das war mein erster bewusster Kontakt mit wirtschaftlich relevanter Zahlen und Fakten. Fun Fact: Im August 2007 tauschte ich am Flughafen Heathrow Euros in Pfund – für 1 € bekam ich 1,47 £!
Die Strategie:
Damals entwickelte ich eine Update-Strategie, die ich wie folgt zusammenfassen kann:
I. Ganz oder gar nicht! Ein Update gilt nur als erfolgreich, wenn es am Ende vollständig abgeschlossen und das System funktionsfähig ist. Andernfalls wird alles rückgängig gemacht – inklusive aller Dateien und Konfigurationen. Axiom & Tipp: Was man nicht anfasst, muss man nicht rückgängig machen. Konkret bedeutet dieser Axiom: arbeite immer mit der Kopie oder Clone und nimals mit dem Original!
II. Nur ein Reboot! Maximal ein einziger Neustart ist erlaubt. Zwei sind bereits einer zu viel.
III. Aktivierung in Sekunden: Das eigentliche Aktivieren eines Updates muss innerhalb weniger Sekunden erfolgen (z. B. durch Verschieben ganzer Verzeichnisse statt Kopieren: move
statt copy).
IV. Vorbereitung darf unterbrechbar sein: Bereits heruntergeladene oder kopierte Dateien dürfen nicht erneut übertragen werden müssen.
V. Alles zuerst vor Ort: Sämtliche Tools, Patches, Dateien und Konfigurationen müssen vorab vollständig und korrekt (via Checksummen) vorhanden sein.
VI. Bedingungen prüfen: Alle Vorbedingungen – Betriebssystemversion, Anwendungsversionen, Kundennummer usw. – müssen erfüllt sein, bevor überhaupt etwas passiert.
Rückwärts gelesen ergibt sich daraus diese logische Update-Reihenfolge:
- Vorbedingungen prüfen
- Dateien kopieren
- Vorbereitung
- Aktivierung
- Reboot
Hinweis: Die Phase „Vorbereitung darf unterbrechbar sein“ ist in dieser Liste nicht als separater Schritt aufgeführt, da der jeweilige Zustand über Flags gespeichert wird. Damit kann ein Update beim letzten erfolgreichen Schritt fortgesetzt werden – besonders bei großen Dateien (> 2 MB), die ggf. in Chunks aufgeteilt werden müssen.
Seit dem September-Update-Project 2007 folgten alle meine Update-Prozesse konsequent dieser konfigurierbaren Struktur, die ich hier in einem „Pseudo Batch-Script“ versucht habe grob zu veranschaulichen:
:: Psudo batch script für DOS 7.x :: Auf Schleifen wurde absichtlich verzichtet :: damit der Code einfacher und verständlich bleibt :: Es geht hier um das Konzept und weniger eleganter Code! REM Phase und andere Parameter übernehmen set Phase=%1 set Kunde=%2 :Label_Bedingungen set Bedingung1=something if not Bedingung1 ( print log "Bedingung1 nicht erfüllt" exit ) set Bedingung=someOtherThing if not Bedingung2 ( print log "Bedingung2 nicht erfüllt" exit ) :: ... usw. usf. if exist backup.flag do goto Label_Download :Label_Backup print log "Backup files..." copy C:\x1\y1 C:\Updates\%updateName%\x1\y1 copy C:\x2\y2 C:\Updates\%updateName%\x2\y2 copy C:\x3\y3 C:\Updates\%updateName%\x3\y3 write %date% > backup.flag :Label_Download if not exist file1.flag ( download file-part1.zip write %date% > file1.flag ) if not exist file2.flag ( download file-part2.zip write %date% > file2.flag ) :: ... usw. usf. if not %Phase%=Prepare do exit :Label_Prepare if not exist prepare0.flag ( print log "Decompressing file0.part1.zip..." unzip file0.part1.zip to C:\Updates\%updateName%\app1\*.* write %date% > prepare0.flag ) if not exist prepare1.flag ( print log "Patching file blabla.dat..." copy %Programs%\acme\app1\app1.exe C:\Updates\%updateName%\app1\ patch.exe diff=C:\Updates\%updateName%\app1\app1.diff target=C:\Updates\%updateName%\app1\app.exe write %date% > prepare0.flag ) :: ... usw. usf. if not %Phase%=Activate do exit REM Ab hier gilt: sollte etwas bis hier schiefgelaufen sein, dann: REM 1. wären wir gar nicht so weit gekommen (dank Flags) REM 2. die Produktiv-Dateien wurden gar nicht angefasst (nur ins Upd. Verz. kopiert) REM 3. Kann man im "Notfall" einfach Flags + Dateien im zugehörigen Update-Verz. löschen REM 4. Der aktuelle Systemzustand ist immer noch vollfunktionstüchtig :-) :Label_Activate move -recursive -force -quiet C:\Updates\%updateName%\app1\ %Programs%\acme\app1\* move -recursive -force -quiet C:\Updates\%updateName%\app2\ %Programs%\acme\app2\* move -recursive -force -quiet C:\Updates\%updateName%\app3\ %Programs%\acme\app3\* delete C:\irgend\wo\irgend\eine.datei :Label_Reboot print log "Rebooting..." REM Sofortiges Reboot ohne Anwenderbenachrichtigung REM ist nicht zu empfehlen, aber möglich. shutdown -reboot -time 0
Egal wie gut und elegant der Algorithmus, Code oder die Konzepte und Paradigmen oder Strategien sind: ein Update MUSS IMMER GUT GESTESTET SEIN, BEVOR MAN ES IN DIE WELT AUF DIE LEUTE LOSLÄSST!
Die Update-Mafia und ihr Update-Perpetuum-Mobile – eine Massenvernichtungswaffe im Dauerbetrieb
Es hat sich wohl inzwischen als „neue Normalität“ eingebürgert: Mircosaft wirft für sein geliebtes Windoof „Updates“ in einer Frequenz ab, die selbst einen B52-Bomber vor Neid erblassen lässt. Und wie bei Teppichbombardements üblich, wird dabei selten gezielt – Hauptsache: viel hilft viel.
Millionen Computer in Büros, Werkhallen und Industrieanlagen werden reihenweise lahmgelegt, aus dem Takt gebracht oder komplett unbrauchbar gemacht. Die Folge: Millionen Arbeitsstunden werden kollektiv im Modus „Trial-and-Error“, „Hoffen und Bangen“ oder schlicht „Däumchendrehen“ verbrannt. Produktivität? Fehlanzeige.

Die Code-Schreiberlinge aus dem Hause Mircosaft in Redmond scheinen ihren bewährten Google-Copy-and-Paste-Workflow längst zugunsten eines neuen Verfahrens ersetzt zu haben: Ask-ChatGPT-and-Paste. Anders lässt sich kaum erklären, warum auf ein Update (KB5058499), das angeblich „Fehlerbehebungen“ und „Verbesserungen“ bringen sollte, ein Update (KB5060842) folgt, das die Fehler des vorherigen Updates beseitigen will – nur damit daraufhin (tusch!) das Update KB5063060 erscheint, um… genau: die neuen Fehler zu beheben. Ein Update-Wirrwarr in Endlosschleife (dazu mehr hier sowie hier oder hier von einem anderen tapferen Kameraden)
Man möchte es kaum glauben, aber es ist die perfekte Beschreibung meiner patentierten „Never Ending Baustelle“® (Copyright ©2007-2025 by Pedram GANJEH-HADIDI). Eine Dauerbaustelle, vor der ich schon vor über einem Jahrzehnt meine Kollegen gewarnt und Freunde sowie Ex-Studienkollegen regelmäßig in Schutz genommen habe.
Die Ursache?
Ganz einfach: „Typing first, Bedenken second!“ – frei nach dem FDP-Slogan „Digital first, Bedenken second“ von Christian Lindner. Oder, um es in meiner Sprache zu sagen: Erst in die Tasten hauen, dann (vielleicht) drüber nachdenken.
Programmieren als Beschäftigungstherapie – und der tiefere Sinn (oder Unsinn?) von Code
Früher kaufte man Computer und Software, um echte Probleme zu lösen – schnell, präzise, effizient. Heute hingegen bekommt man Software, die selbst das Problem ist – und Updates, die das Problem im Wochenrhythmus neu erfinden.
Wer seine Lebenszeit sinnlos vergeuden oder sich ärgern möchte, braucht dafür weder Videospiele noch Reality-TV – ein Windoof-Update genügt!
Man stelle sich vor: Man geht zum Arzt, zahlt für Medikamente – und bekommt dafür Kopfschmerzen. Oder man bringt sein Auto in die Werkstatt, zahlt für eine „Wartung“ – und es springt danach nicht mehr an.
Und bei Mircosaft? Genau das ist Konzept. Willkommen im Zeitalter der „Bugfix-Fabriken“, in dem Stabilität zur Legacy geworden ist und „Release Notes“ wie Apokalypse-Kalender gelesen werden.
Es ist kein Wunder, dass ich inzwischen unter Updateophobie leide und KB5063060 Links liegen lasse, wie inzwischen viele Andere auch.
Es entsteht zunehmend der Eindruck, dass heutzutage nahezu jeder – unabhängig von Qualifikation oder Verantwortungsbewusstsein – Software entwickeln und auf den Markt bringen kann, ohne je für etwaige Folgen wie Funktionsstörungen, Zeitverlust oder mentale Belastungen zur Verantwortung gezogen zu werden.
Ebenso könnte man meinen, dass viele Schlüsselpositionen in Behörden, Normungsgremien und europäischen Institutionen nicht immer nach Kompetenz, sondern eher nach politischer Zweckmäßigkeit oder Karrierelogik besetzt werden. Anders lässt sich das anhaltende Versagen bei der Regulierung und Qualitätssicherung kaum erklären – zumindest nicht aus Sicht betroffener Anwender.
Updatephobie
Neulich musste ich dringend etwas Wichtiges ausdrucken.
Ich schaltete meinen All-in-One-Office-Drucker ein – und prompt erschienen auf dem kleinen Touch-Display sowie am PC Hinweise auf eine neue Firmware.

Zum Glück entschied ich mich weise dagegen, das Update durchzuführen.
Andernfalls hätte ich – wie schon so oft – stundenlang mit Windows-Einstellungen, Treibern und Druckeroptionen jonglieren müssen. Dabei hätte ich nicht nur wertvolle Lebenszeit verloren und mich maßlos geärgert, sondern auch einige Aufgaben aufschieben müssen. Und ja: Der wichtige Termin, für den ich die Ausdrucke dringend brauchte, wäre mit Sicherheit verspätet wahrgenommen worden.
Schade eigentlich…. Eigentlich sollten Updates, vor Allem die Firmware-Updates ein Grund zur Freude und bessere/sichere Betriebsbereitschaft unsere Geräte sein.
Please quietly exit the computer hardware field!
For over 20 years, I used to easily download user/installation manuals from the websites of various companies (computers, hardware, peripheral devices, etc.). All I had to do was visit the manufacturer’s homepage, navigate to the „Support“ section, select the model of my device, and download the PDF file with just one click.
But no! Not for BE QUIET!
They want my personal data, like my name, address, phone number, email, etc., plus a hand-typed individual request just to download a simple PDF for a PC big tower case. WTF?
Dear BE QUIET!, why do you think you’re so special?
I’ve got bad news for you: you’re not that special, and your „technology“ will never be more complex or expensive than the products from motherboard manufacturers like ASUS, GIGABYTE, NVIDIA etc.!
Why can’t you just put a simple „Download“ link on your „Support“ page? Is that too difficult for you? If so, please quietly exit the computer hardware field!
By the way, this song is dedicated to you (BE QUIET!). You can sing it to the tune of Sheryl Crow’s „All I Wanna Do“ (1995):
[Intro]
Hit it!
This ain’t no motherboard,
It ain’t no supercomputer deep tech, either,
This is only a computer case.
[Verse 1]
All I wanna do is click on „Download,“
I need the installation manual, I’m not the only one.
All I wanna do is read the PDF,
It’s not so easy when I visit your support site.
Welcome to the New Broken World! This song is dedicated to Gigabyte for one of the best Control Center updates ever, that „made my day“ 😅
After several times of installing the new „Smart Backup“ software through „Gigabyte Control Center„, it seems that this update cannot be installed or it is not removed from the list of updates.
This shows me that my suggestion in my earlier post was right: the updates of Gigabyte by the desktop application „Gigabyte Control Center“ for the Mainboards are not tested well or at all!
You can watch the screenshots and log-content at the end of the following song lyrics:
🎵 Bugging in the Wind – (to the tune of „Blowin’ in the Wind“)
by Pedram GANJEH-HADIDI (with ❤️ for Gigabyte.cn )
Verse 1
How many times must a man install
That „Smart Backup“ from Control Center,
Before it stops showing in the list
Like some cursed undead presenter?
And how many logs must be born each day
To tell you: download.gigabyte.cn went away?
🎶 The answer, my friend, is bugging in the wind,
The answer is bugging in the wind.
Verse 2
How many pings must a poor PC send
Before DNS gets a clue?
How many updates just loop forever,
With version numbers déjà vu?
And how many times will the error shout:
„ERROE – Connection timed out!“
🎶 The answer, my friend, is bugging in the wind,
The answer is bugging in the wind.
Verse 3
How many gigs must we waste on files
That never even launch right?
How many tools must one app install
To still be dumb overnight?
And how many „fixes“ just break more things
While pretending the devs are bright?
🎶 The answer, my friend, is bugging in the wind,
The answer is bugging in the wind.
Verse 4
How many times can support reply
With „Please reboot and pray“?
How many days will the logs stay quiet
While updates still misbehave?
And how many souls must scream in vain
Till Gigabyte learns to debug pain?
🎶 The answer, my friend, is bugging in the wind,
The answer is bugging in the wind.



Ladies and Gentlemen, this is the content of the latest logfile:
[ 2024-05-04 08:40:04 ] GvLoader ERROE DownLoadDB fail:Der Remotename konnte nicht aufgelöst werden: 'mb.download.gigabyte.cn' [ 2024-05-04 08:40:04 ] GvLoader INFO DownLoadIni fail [ 2024-05-04 16:36:29 ] GvLoader ERROE DownLoadDB fail:Der Remotename konnte nicht aufgelöst werden: 'mb.download.gigabyte.cn' [ 2024-05-04 16:36:29 ] GvLoader INFO DownLoadIni fail
I hope they don’t f…. up the firmware of my motherboard (mainboard) with their untested, not-working updates 😅🙏🤲📿
Im Westen nichts Neues: Open Source und Gratis-Software – Woraus man nichts lernen möchte
In einem früheren Beitrag berichtete ich von einer Erfahrung, die ich mit einem Product Owner gemacht habe, dessen Open-Source-Software in der Automatisierungsindustrie genutzt wird und tausendfach heruntergeladen wurde. Trotz dieser Verbreitung war er – aus welchem Grund auch immer – nicht in der Lage oder willens, die falsche Prüfsumme (Hashwert) für seinen Windows-Installer zu korrigieren (mehrere Monate lang!). Dadurch war die Integrität des Installers weder verifiziert noch vertrauenswürdig, weshalb ich mich weigerte den Installer zu starten und ihn sofort löschte.
Nun musste ich erneut feststellen, dass eine andere Open-Source-Software ebenso wenig auf Fehlermeldungen oder negative Rezensionen im Google Play Store reagiert.



Es scheint, als hätten viele in der Open-Source-Community nichts aus dem Log4Shell-Desaster (BSI-Warnung und BSI-Bilanz) gelernt, das 2021 zahllose Überstunden, gestrichene Urlaubspläne und ausgefallene Weihnachtsferien zur Folge hatte.
Früher wurde die IT-Industrie oft – als negatives Beispiel – mit der Automobilbranche verglichen, die hingegen als vorbildlich galt. Die klassischen Vergleiche begannen mit Sätzen wie: „Wenn die Autoindustrie so arbeiten würde wie die IT-Branche, dann …“
Doch seit Fahrzeuge mit Bordcomputern vollgestopft sind oder sogar vollelektrisch fahren, lassen sich selbst diese alten Vergleiche nicht mehr heranziehen (siehe meinen Beitrag „Zurück in die Zukunft“).
Wie wichtig und weitverbreitet die sogenannte Open-Source-Software sind, sieht man wenn man z.B. auf einem Android-Handy (hier die Screenshots von einem Samsung Fold Z4) in der „Einstellungen“ nach „Open“ oder „Open Source“ sucht …

und danach mit einem Klick die „Open-Source-Lizenzen“ auswählt:

Die Liste der auf einem Samsung-Android-Smartphone verwendeten Open-Source-Software ist beeindruckend lang. Da stellt sich die Frage, wie schnell die Product Owner bzw. Maintainer dieser Open-Source-Software auf Fehlermeldungen reagieren:


Welcome to the New Broken World! This song is dedicated to Linksys for one of the best website translations ever, that „made my day“ 😅 #outsourcingVictims #yourWebsiteIsYourVisitingCard #anotherDeletedPages #http301 #redirectedToNirvana #whenYouSayNothingAtAll
After clicking on the link on the administration-page of my new Linksys-Super-Duper-WiFi7-Router, I just wanted to download the new version of the software… but NO! I’ve been asked if I wanna be redirected to the „austrian“ page…

Sadly I was dumb enough and clicked on the „Yes“ button, which redirected me to this wonderful page with the best localisation and (german) translations ever, as evidenced here:

So I wrote a song to thank Linksys for their efforts, hard work and obligingness and wasting a lot of bucks only to help me having better user experience in my langauage (german). Thank you!
Here is the lyric. For the music, just imagine the music of „Thank you for hearing me“ from Sinead O’connor (R.I.P.) which you’ll find here on youtube, or the song from Ronan Keating „When You Say Nothing At All“ also on youtube:
„Thank You for Translation“
(Verse 1)
Thank you for translation,
Bridging every word,
When I needed understanding,
You made my voice be heard.
(Chorus)
Thank you for forwarding page,
Thank you for the HTTP error,
Thank you for the little things,
And thank you for nothing at all.
(Verse 2)
Through the code, through the language,
Through the clicks and the screens,
Every task, every detail,
You make it all feel so serene.
(Chorus)
Thank you for forwarding page,
Thank you for the HTTP error,
Thank you for the little things,
And thank you for nothing at all.
(Outro)
Thank you for all the help,
Thank you for all the small ways,
Thank you for translation,
In the digital maze.
Thank GOD! I did not check the „Save Preferences“ checkbox 🤣 (Web-Dev-Insider-Joke)
Unsichtbare grafische Benutzerschnittstellen
Normalerweise sind verfügbare UIs sichtbar und einfach zu bedienen. Das heißt:
- Man sieht sie deutlich und erkennt um welche UI es sich handelt (kein Röntgenblick oder Telepathie notwendig!) und somit welche Funktion diese hat
- Die Bedienung bzw. das Betätigen der UI verlangt weder Nerven aus Stahl noch höchste Konzentration und Nanometer-Arbeit (Catch-me-if-you-can-Spiel mit dem Mauszeiger)



Die berühmte „Was-wäre-wenn…?“-Frage – Der Schlüssel zur soliden Software-Architektur
Wie ich bereits in einem früheren Artike (oder auch hier) erwähnt habe, beginnen die wichtigsten Fragen in der Software-Architektur mit „Was wäre, wenn…?“. Wird eine dieser Fragen übergangen oder vorschnell beantwortet, ohne gründlich darüber nachzudenken, darf man sich später nicht wundern, wenn bereits kleine Änderungen – etwa ein neues Feature oder eine Kundenanpassung – mühsame und kostspielige Anpassungen an unzähligen Stellen im Code nach sich ziehen.
Plötzlich müssen Methoden geändert, Signaturen angepasst und Rückgabewerte modifiziert werden. Ganze Datentypen, inklusive ihrer Eigenschaften, Methoden und Events, müssen umgestaltet werden. Dadurch verlieren bestehende Unit-Tests ihre Gültigkeit, müssen umgeschrieben oder gar entfernt werden. Noch schlimmer: Neue Unit-Tests passen oft nicht mehr nahtlos in das ursprünglich durchdachte Konzept.
Das TDD-Paradigma, kann hier paradoxerweise zu Problemen führen. Denn wenn die Architektur bereits auf wackligen Beinen steht, entstehen „Risse“ nicht nur im Code, sondern auch in der Benutzerführung – spürbar durch inkonsistente Steuerung oder unerwartetes Verhalten der Oberfläche bei Desktop-Anwendungen und Mobile-Apps.

Flexibilität: Was sich immer ändern wird
Manche Dinge ändern sich zwangsläufig – und sollten daher von vornherein leicht konfigurierbar oder erweiterbar sein:
- Theme, Look & Feel – weil sich Design-Standards weiterentwickeln.
- Sprachunterstützung – denn neue Märkte bedeuten neue Anforderungen.
- Datenexport – weil Kunden irgendwann ein anderes Format benötigen.
- Diagramme und Reports – da sich Analyse- und Visualisierungsanforderungen ändern.
- Kommunikation mit Schnittstellen und Protokollen – weil neue Technologien und Standards entstehen.

Unwahrscheinliche Änderungen? Vielleicht doch nicht!
Dann gibt es Dinge, bei denen man glaubt, sie würden nie oder nur in den seltensten Fällen geändert werden – und doch geschieht es irgendwann:
- Der Kunde will Produktionsdaten in einer exotischen Datenbank oder einem speziellen Dateiformat speichern.
- Eine „unbedeutende“ Zahl soll plötzlich auf dem Bildschirm angezeigt oder eine neue Konfigurationsmöglichkeit für die Nachtschicht integriert werden.
- Eine günstigere SPS oder Industrie-Kamera eines unbekannten Herstellers muss eingebunden werden – leider nicht ganz standardkonform.
Ob, wann und wie solche Änderungen kommen, ist nur eine Frage der Zeit.

Architektur ist wie Schach – erst denken, dann ziehen!
Ein guter Software-Architekt verhält sich wie ein professioneller Schachspieler: Er nimmt sich Zeit für das Vorausdenken, prüft verschiedene Szenarien und fragt sich „Was wäre, wenn…?“, bevor er zur Tastatur greift.
Denn grobe Architekturfehler verhalten sich wie unbedachte Züge im Schach: Ein frühzeitiger Fehlgriff kann zum Schachmatt führen – oder die gesamte Strategie unnötig kompliziert und mühselig machen. Einmal falsch platziert, steht die Figur im Weg und macht jede weitere Planung schwieriger.
Besser also, man nimmt sich die Zeit für eine durchdachte Architektur – bevor man sich später durch einen Flickenteppich aus Workarounds kämpft.

Zurück in die Zukunft! Mein Toyota Corolla Cross Hybrid – das Gegenteil eines DeLorean DMC-12
In einem früheren Beitrag habe ich bereits über meine Frustration mit dem Bordcomputer meines Toyota geschrieben – genauer gesagt über die Bedienungssoftware und deren mangelnde Benutzerfreundlichkeit. Damals konnte ich nicht alle Probleme aufzählen, weil ich während der Fahrt aus Sicherheitsgründen keine Fotos machen konnte (und wollte).
Doch dieses Mal hatte ich das Glück, Beifahrer zu sein, gemeinsam mit einem Kollegen. Plötzlich fiel dem Fahrer auf, dass die berechnete Ankunftszeit irgendwie… falsch war. Und nicht nur ein bisschen, sondern um eine satte Stunde daneben!

Der Fahrer und mein Kollege starrten mich mit offenem Mund an, als ich ihnen erklärte, dass seit dem lang ersehnten Toyota-Software-Update zwar endlich die korrekte aktuelle Zeit angezeigt wird, aber die Ankunftszeit auf dem Navigationsdisplay plötzlich in die Vergangenheit rutscht. Ja, richtig gelesen: Wenn eine Fahrt eigentlich 50 Minuten dauert, zeigt der Bordcomputer eine Ankunftszeit an, die eine Stunde zu früh oder zu spät liegt – als wäre man mit einem Zeitsprung unterwegs.
Ich frage mich bis heute: Wie schafft man es, sich bei einer Cockpit-Software so sehr mit der Zeit zu verheddern? Hat wirklich niemand bei Toyota dieses Update getestet? Ist da niemandem aufgefallen, dass die Ankunftszeit nicht stimmen kann?
Toyota weiß, dass dieses Auto für den österreichischen Markt gebaut wurde. Es wurde nach Österreich importiert, hier zugelassen und registriert. Über Android Auto und die Toyota-App kann der Bordcomputer jederzeit die Zeitzone, die aktuelle Uhrzeit und sogar das GPS meines Handys abrufen. Das System hat also alle notwendigen Daten – und trotzdem schickt es mich auf eine unfreiwillige Zeitreise.
Also, liebe Toyota-Software-Developer: Was genau ist da schiefgelaufen?
Technologie ohne Verantwortung: Warum IT-Systeme oft an der Realität scheitern
Von Ignoranz, Gleichgültigkeit und Sorglosigkeit
Am vergangenen Montag, zwei Wochen nach meiner Knieoperation, begab ich mich zur vorgeschriebenen Nachuntersuchung in den großen Warteraum der Unfallabteilung des Landeskrankenhauses Vöcklabruck.
Dort traf ich überraschend meinen ehemaligen Bettnachbarn wieder – einen sympathischen Kollegen, der wie ich am Montag, den 24. Februar, frühmorgens um 6:00 Uhr zur OP aufgenommen wurde. Während ich am Knie operiert wurde, hatte er einen Eingriff am Ellbogen hinter sich. Da wir beide seit Jahrzehnten im Bereich Software-Engineering und -Development tätig sind, kamen wir schnell ins Gespräch.
Nach dem üblichen „Hallo! Wie geht’s?“ und einem kurzen Austausch über unser jeweiliges Befinden fiel mein Blick auf einen Fernseher im Warteraum, der eigentlich als „Digital Signage“-System zur Anzeige von Informationen für Patienten dienen sollte. Doch was ich sah, war ernüchternd:

Seit mindestens zwei Wochen (24/7) zeigte dieses teure, stromfressende Gerät nichts weiter als ein eingefrorenes PowerPoint-Fenster – ohne jegliche Information, ohne Funktion. Es schien niemandem aufgefallen zu sein oder, was noch wahrscheinlicher ist, es war schlichtweg niemandem wichtig genug, das Problem zu beheben. Wurde das System gehackt oder vergaß ein IT-Service-Mitarbeiter seine Präsentation zu speichern? Vielleicht versagte irgend ein Update und das Betriebssystem steckte fest?
Ich machte meinen ehemaligen Bettnachbarn darauf aufmerksam und äußerte meine Bedenken hinsichtlich der IT-Sicherheit in der Gesundheitsbranche. Wenn schon solch einfache Systeme über Wochen hinweg unbeachtet bleiben, wie steht es dann um den Schutz sensibler Gesundheitsdaten in der elektronischen Gesundheitsakte (ELGA)?
Seine Reaktion war bezeichnend: Mit einem Achselzucken und einem amüsierten Lächeln meinte er nur:
„Ja, das kann passieren. Die Systeme sind heutzutage so kompliziert. Da geht ständig irgendwo irgendwas schief.“
Seine Gleichgültigkeit überraschte mich nicht – es war nicht das erste Mal, dass ich auf eine solche Haltung in der IT-Branche gestoßen bin. Probleme werden oft mit einer Mischung aus Resignation und Beschwichtigung abgetan, anstatt Verantwortung zu übernehmen. Fachliche Defizite, mangelndes Interesse, fehlende Leidenschaft oder schlichtweg Unfähigkeit werden hinter einem Mantel aus „Verständnis“ und „Toleranz“ versteckt.
Kein Wunder! Das Motto „Fake it until you make it!“ ist längst zur Grundphilosophie der IT-Industrie geworden. Hauptsache, die Vertriebsabteilungen verkaufen mit geschliffener NLP-Rhetorik und Buzzword-Bingo Dinge, die entweder nicht existieren oder nicht das halten, was sie versprechen.
In der IT-Branche – und nicht nur dort – erinnert das zunehmend an das Schauspiel, das der Politikanalytiker und Publizist Paul Lendvai in seiner Analyse über moderne Politik in Österreich und Europa (Buch) treffend beschreibt: Heuchelei! Alles nur Inszenierung! Dank perfektionierter Verkaufsrhetorik und NLP werden unausgereifte Produkte als „kritische Infrastruktur“ vermarktet, ohne dass dahinter ein echtes Verantwortungsbewusstsein steckt. Der Begriff dient als Werbeslogan, nicht als Verpflichtung.
Doch solange sich niemand daran stört, bleibt alles beim Alten. Und so läuft das Digital Signage im Krankenhaus wohl auch noch nächste Woche mit seinem eingefrorenen PowerPoint-Fenster – bis irgendwann jemand den Stecker zieht.
Diese sorglose Gleichgültigkeit und Verantwortungslosigkeit erinnerte mich an das Verhalten des iranischen Regimes vor einigen Jahren, als ein verheerendes Erdbeben die Osttürkei und die nordwestliche Region Irans, insbesondere Aserbaidschan, erschütterte. Tausende Menschen wurden unter den Trümmern begraben, und die Zerstörung war immens.
Während türkische Rettungskräfte auch nach zehn Tagen noch unermüdlich nach Überlebenden suchten – und tatsächlich noch Lebende fanden –, erklärte das iranische Regime bereits nach nur 24 Stunden das Ende der Such- und Rettungsmaßnahmen. Die offizielle Begründung: „Es gibt keine Überlebenden mehr.“ Eine Aussage, die umso zynischer war, da es nie eine ernsthafte Suche gegeben hatte. Offizielle Hilfskräfte blieben aus, die Regierung ließ die betroffenen Menschen schlichtweg im Stich. Diese wohnen teilweise immer noch in Plastikzelten ohne jegliche Infrastruktur! Es waren die Einheimischen und freiwillige Helfer, die unter widrigsten Bedingungen versuchten, Leben zu retten. Zwei benachbarte „islamische“ Länder – aber zwei völlig unterschiedliche Haltungen, wenn es um Verantwortung und Pflichtbewusstsein geht.
Und bei Softwaresystemen ist es nicht anders. Ob wir verlässliche, robuste Systeme haben oder uns in einer endlosen Baustelle voller Mängel und Sicherheitslücken wiederfinden, hängt letztlich von der Einstellung der Entscheidungsträger, Entwickler und Konsumenten ab.
Gerade in einer Zeit, in der politische Unwägbarkeiten wie Trumps erratische Entscheidungen langjährige Freundschaften und Partnerschaften aufkündigen, in der Cyberkriminalität floriert und Betrug im Internet dank künstlicher Intelligenz raffinierter denn je ist, wäre es umso wichtiger, Verantwortung zu übernehmen.
Doch bei österreichischen IT-Systemen braucht es weder staatlich organisierte Profi-Hacker noch raffinierte Script-Kiddies, um Schwachstellen auszunutzen. Denn wenn es allen egal ist, braucht man keine Feinde – der Schaden entsteht von selbst.
Internal Server Error: Digitalisierung & digitales Amt not found!
Als ich beim Arzt meine Sozialversicherungskarte vorzeigen wollte, musste ich feststellen, dass sie in meiner anderen Jacke lag. Doch kein Problem – schließlich habe ich die App Digitales Amt und die Handysignatur auf meinem Smartphone installiert! Erleichtert zog ich mein Handy aus der Tasche, öffnete die App, tippte voller Zuversicht auf das Symbol der Sozialversicherungskarte … und meine Vorfreude wich augenblicklich einer Fehlermeldung.
Android 13, 5G, HTML5, Laser, Phaser, ChatGPT und ein Rover auf dem Mars – aber eine digitale Sozialversicherungskarte bleibt unerreichbar.
Wenn das der Stand der Digitalisierung ist, dann gute Nacht, Österreich! Wir machen es ausländischen Saboteuren erschreckend einfach – sie müssen gar nichts tun, wir erledigen es schon selbst.
Welcome to the new brave broken (digital) world!
Fakten & Zahlen
Die Entwicklung der App „Digitales Amt“ sowie der Plattform oesterreich.gv.at kostete insgesamt rund 7,4 Millionen Euro (mehr dazu hier auf futurezone.at). Davon entfielen 5,8 Millionen Euro auf externe Entwicklungskosten, während 1,6 Millionen Euro für Werbemaßnahmen aufgewendet wurden (mehr dazu hier auf derstandard.at).
Aufschlüsselung der Entwicklungskosten:
- Migration von help.gv.at: Inklusive Erstellung eines responsiven Designs und Infrastrukturanpassungen wurden hierfür 1,2 Millionen Euro veranschlagt.
- Aufbau einer sicheren Infrastruktur und elektronischen Identifikation: Diese Maßnahmen kosteten 1,3 Millionen Euro.
- Entwicklung digitaler Behördenwege: Für die Anpassung und Implementierung digitaler Amtsservices wurden 3 Millionen Euro investiert.
- Verbesserung der Benutzerfreundlichkeit: Für Usability-Optimierungen und Bürgerbeteiligung wurden 0,3 Millionen Euro aufgewendet.
Die Werbemaßnahmen umfassten diverse Print- und Online-Medien und beliefen sich auf 1,6 Millionen Euro (wie auf derstandard.at berichtet wurde).
Zum Zeitpunkt der Einführung im März 2019 gab es einige Startschwierigkeiten. Beispielsweise wurden hunderte Wahlkartenanträge nicht korrekt an die zuständigen Wahlreferate übermittelt. Zudem gab es Kritik an der Möglichkeit, den Wohnsitz ohne Nachweis des Vermietereinverständnisses zu ändern, was zu Sicherheitsbedenken führte.
Diese Investitionen und Herausforderungen wurden öffentlich diskutiert und führten zu Debatten über die Effizienz und Sicherheit der digitalen Verwaltungsangebote in Österreich.
Die wichtigste Frage dazu lautet: darf man überhaupt „Effizienz“ und „Sicherheit“ in gleichem Satz mit „digitalen Verwaltungsangebote in Österreich“ verwenden?
„The Crisis of Democracy“
In 1973, David Rockefeller founded a new organization called the Trilateral Commission. The early members were selected from the United States, Western Europe, and Japan. Among them were executives of major corporations, banks, law firms, and government officials.


They were concerned about the widespread social resistance in the 1960s and 1970s—manifested in the anti-war movement, feminism, and campaigns for social and equal rights for minorities and people of color. Seeking to understand the root causes of these movements, they launched an investigation, which was completed in 1975 (as documented in original sources here).
The resulting report, titled „The Crisis of Democracy“, reached the following conclusion regarding why governing and maintaining control over the population in the U.S. and Western Europe had become more challenging than before:
„The population is overeducated.“
Additionally, the report stated:
„Previously passive or unorganized groups in the population—Blacks, Indians, Chicanos, white ethnic groups, students, and women—have now embarked on concerted efforts to establish their claims to opportunities, positions, rewards, and privileges, which they had not previously considered themselves entitled to.“
One of the report’s key recommendations was:
„A program is necessary to lower the job expectations of those who receive a college education.“
And further:
„The problems of governance in the United States today stem from an excess of democracy… What is needed instead is a greater degree of moderation in democracy.“
(The Crisis of Democracy: Report on the Governability of Democracies)
So they started to „gather the figures from the chessboard“ and placed them among themselves (Trilateral Commission) as follow:
- The President (Jimmy Carter)
- Vice president
- Secretary of State
- Secretary of Defense
- Secretary of Treasury
- The national security Adviser (Zbigniew Brzeziński)
were all held by members of Trilateral Commission !
Here, you can see Mr. Brezinski (top strategic adviser of 7 US presidents who armed Osama Bin Laden and his Al’Qaida Mudjahedins in one of the most monumental historic moments in the history of our time (just watch how he points with his finger to above and how he says „Your cause is right and God is on your side!“ to the Taliban and Al’Qaida members):
You may want to read following books he wrote in the 1990s:
https://en.wikipedia.org/wiki/The_Grand_Chessboard
and/or other Works on „Global Domination“ from the list on Wikipedia:
https://en.wikipedia.org/wiki/Zbigniew_Brzezinski#Works
Azure Web Error Haiku (of the day)
This page crashed
Try again
i is null
Such a wonderful Haiku
But I am not amused

Klaus und seine magische Kiste: Warum Monolithen nicht die Antwort sind
Neulich erzählte mir mein Beifahrer von einem faszinierenden Geschäftspartner in der Mechatronik und Automatisierung. Dieser war seit Jahren in der Branche tätig und frustriert über die ständigen Anpassungen in komplexen Systemen. Jede kleine Änderung führte dazu, dass Kollegen monatelang das gesamte System umstellen mussten. Ein neuer SPS-Typ, der keinen GOTO-Befehl unterstützte? Problem. Ein spezieller Sensor, der nur RS-232, aber kein CAN konnte? Noch ein Problem. Also beschloss unser Held, das Problem ein für alle Mal zu lösen, indem er eine programmierbare „magische Kiste“ baute – ein Gerät mit allen möglichen Schnittstellen, das angeblich jedes Kompatibilitätsproblem beheben sollte. Ohne Code. Klingt toll, oder? Nun ja…
Als ich diese Geschichte hörte, musste ich schmunzeln. Ich unterbrach meinen Beifahrer und erklärte ihm, warum ich skeptisch war – anhand der berüchtigten All-in-One-Stereoanlagen aus den 1980er Jahren. Diese Geräte waren damals der letzte Schrei und versprachen alles in einem: CD-Player, Kassettendeck, Verstärker, Radio – und oft sogar einen Schallplattenspieler. Doch sie waren Monolithen, und das brachte erhebliche Nachteile mit sich:
- Monolithen und Modularität: Wenn das eingebaute Netzteil oder der Verstärker kaputtging, funktionierte gar nichts mehr. Weder der CD-Player noch die Kassettendecks – alles war tot.
- Bezahlte Überflüssigkeit: Selbst wenn man nur CDs abspielen wollte, zahlte man für Funktionen, die man nicht brauchte – wie ein zweites Kassettendeck oder den eingebauten Plattenspieler.
- Platzfresser: Diese Geräte waren riesig und belegten mehr Raum als nötig.
- Eingeschränkte Kompatibilität: Lautsprecher konnten manchmal ersetzt werden, aber nur, wenn sie über standardisierte Cinch-Buchsen angeschlossen waren. Wenn nicht, Pech gehabt.
- Qualitätskompromisse: Audiophile legten sich oft zwei Systeme zu, weil eines bessere Kassettenwiedergabe bot, während das andere bei CDs brillierte.
Und das alles in einer Ära ohne EU-Gewährleistung! Manche Hersteller boten stolz ein halbes Jahr Garantie, andere gerade mal zwei Monate.

Die Wende zur Modularität
Ende der 80er und Anfang der 90er lernten die Hersteller aus ihren Fehlern. Sie zerlegten ihre Monolithen in einzelne Module. Verbraucher konnten nun:
- Nur die Module kaufen, die sie tatsächlich benötigten.
- Komponenten verschiedener Hersteller kombinieren: ein Kassettendeck von Marke X, ein CD-Player von Marke Y und ein Verstärker von Marke Z – ideal, um die 1000-Gigawatt-Boxen fürs nächste Erdbeben mit Saft zu versorgen.

Die Lektion für die Software
Die Geschichte der Stereoanlagen zeigt, warum Modularität wichtig ist – eine Lektion, die auch in der Softwareentwicklung gilt. Die Frustration des Automatisierungs-Mechatronikers, der nach jeder kleinen Änderung das gesamte System anpassen musste, deutet auf ein grundlegendes Problem hin: Ad-hoc-Programmierung ohne durchdachte Software-System-Architektur.
Ein erfahrener Softwareentwickler (bzw. SW-Architekt) hätte sich sofort gefragt:
- Was, wenn Hersteller U nicht mehr existiert?
- Was, wenn Hersteller V das Produkt nicht mehr anbietet?
- Was, wenn Hersteller W die Lizenzbedingungen ändert?
- Was, wenn Hersteller X seine Treiber oder Schnittstellen ändert?
- Was, wenn Hersteller Y nur noch neue Modelle ohne vollständige Abwärtskompatibilität verkauft?
- Was, wenn Standard Z obsolet wird?
Die Liste ließe sich endlos fortsetzen. Ohne diese „Was-wäre-wenn„-Fragen läuft man Gefahr, eine digitale eierlegende Wollmilchsau zu bauen – eine magische Kiste, die zwar beeindruckend klingt, in der Praxis aber niemand will.
Niemand möchte von einem einzigen Hersteller abhängig sein, oder von einem einzigen Softwaresystem oder Produktmodell usw.
Niemand möchte mehr für Schnittstellen und wunderbare Features und Möglichkeiten bezahlen, die zwar mehr Raum und Speicher belegen und komplexer sind, diese aber nicht benötigt.
Der Unterschied zwischen Coder und Architekt
Hier kommt die entscheidende Lektion: Code zu schreiben ist nicht dasselbe wie Softwarearchitektur. Wer die Konzepte von Modularität, Komplexität und Abhängigkeiten nicht versteht, investiert vielleicht Jahre in einen Monolithen, der letztlich unbrauchbar ist.
Also, wenn Ihnen das nächste Mal jemand eine magische All-in-One-Lösung verspricht, denken Sie an die Stereoanlagen der 80er – und seien Sie skeptisch. Modularität mag weniger glamourös klingen, aber sie ist der Schlüssel zu langlebigen, flexiblen und wartbaren Systemen. Und das gilt für Hardware genauso wie für Software.
Gewidmet an P.M. (der Beifahrer)
Im nächsten Artikel erkläre ich dir, wie manche mit Buzz-Words wie „Low Code“ und „No Code“ viel Geld für das Blaue vom Himmel und sonstige Versprechungen (Blabla) verlangen und reich werden, während ihre Kunden doppelt und dreifach draufzahlen.
Warum macht ihr das? Wo bleibt der Sinn eures Handelns? Teil 3: Buchdruck & Weiß auf Schwarz???
Farbdrucker, weiße Tinte und blaue Wunder – Eine Geschichte aus der guten alten PC-Welt
Ende der 90er-Jahre, in einer Ära vor Smartphones und Social Media, war das Linzer Nachtleben eine einfache, aber ehrliche Sache: Ein kühles Bier, laute Musik und eine gute Story, die die Runde machte. In dieser Zeit lernte ich im legendären Rock-Lokal Ostbahn Max kennen.
Max war ein wandelndes Klischee – aber auf die bestmögliche Weise. Lange schwarze Haare, komplett in Schwarz gekleidet und mit einem Humor, der tiefgründiger war als jedes Doom-Metal-Lied. Neben seiner Karriere als inoffizieller Botschafter der Schwermetall-Gemeinschaft hatte er einen festen Job bei Vobis im Uno Shopping. Dort war er quasi der PC-Guru: Zusammenbauen, Reparieren und Hotline-Kollegen beruhigen, die kurz davor waren, ihren Telefonhörer gegen die Wand zu werfen.
Jedes Mal, wenn wir uns im Ostbahn trafen, hatte Max eine neue, absurde Geschichte aus seiner Hotline-Zeit parat. Aber eine davon überstrahlt alle anderen – im wahrsten Sinne des Wortes.
Die alte Dame und der Drucker, der kein Weiß mochte
Eines Tages erhielt die Vobis-Hotline einen Anruf von einer älteren Dame. Ihr Problem klang zunächst simpel: Ihr neuer Farbdrucker druckte partout nicht in Weiß. Ja, weiß. Max versuchte höflich zu erklären, dass Drucker keine weiße Tinte nutzen, weil Papier in der Regel – Überraschung – weiß ist. Aber die Dame ließ nicht locker.
Und so begann eine epische Hotline-Sitzung. Stundenlang wurde versucht, den Drucker zum „Weißen“ zu bringen. Es wurden Treiber neu installiert, Windows 98 neu gestartet (und wer Windows 98 kennt, weiß, dass das eine spirituelle Prüfung sein konnte), und selbst die berühmte „Plug-and-Play“-Magie blieb aus. Die Hotline-Mitarbeiter kapitulierten schließlich und baten die Dame, den Drucker direkt ins Geschäft zu bringen.
Der große Showdown in Pasching
Am nächsten Tag betrat die Dame das Vobis-Geschäft in Pasching mit ihrem Drucker in der Hand und wurde direkt zu Max und seinem Team geschickt. Max, professionell wie immer, packte den Drucker aus, schloss ihn an und wollte gerade Papier suchen, als die Dame ihn mit den Worten stoppte:
„Moment bitte! Ich habe Papier mitgebracht.“
Was für eine vorbildliche Kundin, dachte Max – bis er genauer hinsah. Sie hielt einen perfekt sortierten Stapel blauer A4-Blätter in den Händen.
Blaue Blätter. Kein Weiß weit und breit.
Plötzlich ergab alles Sinn. Der Drucker konnte nicht in Weiß drucken, weil er auf Blau schlicht keine weiße Tinte „zaubern“ konnte. Max musste sich zusammenreißen, um nicht laut loszulachen. Stattdessen erklärte er der Dame geduldig, dass Drucker für diese Art von „Magie“ leider nicht gebaut seien.
Und was lernen wir daraus?
Manchmal, wenn ich an diese Geschichte denke, frage ich mich: Wie oft versuchen wir, in unserem Alltag etwas „Weißes“ auf „Blaue Blätter“ zu drucken? Wie oft übersehen wir, dass der eigentliche Fehler nicht in der Technik liegt, sondern darin, wie wir die Welt wahrnehmen?
Rückblickend hat diese Anekdote für mich etwas Nostalgisches und auch Lehrreiches. Sie erinnert mich daran, dass Technik oft missverstanden wird – und dass ein bisschen Humor dabei hilft, den Frust zu überwinden.
Übrigens: Kürzlich, als ich auf der Suche nach einigen Screenshots war, fand ich Fotos, die ich 2020 von einem Buch gemacht hatte, das ich bei Amazon gekauft hatte. Und da fiel mir die Geschichte mit der alten Dame wieder ein. Warum? Weil in diesem Buch mehrere Seiten komplett schwarz gedruckt waren – mit weißem Text. Es war, als hätte jemand die alte Dame in die heutige Zeit gebeamt. Und ich musste laut lachen, weil ich plötzlich dachte: Vielleicht hatte sie einfach nur den falschen Drucker für ihre blauen Blätter.

Warum macht ihr das? Wo bleibt der Sinn eures Handelns? Teil 2: Mein TOYOTA Corolla Cross ist eines der gefährlichsten Autos der Welt
Der Traum vom modernen Auto – oder: Warum ich beim Fahren keinen Nerv für Software-Frust habe

Ich dachte, ich tue mir etwas Gutes, indem ich mir ein modernes Auto zulege – eines, das zuverlässig ist (für mich bedeutet das: keine chinesischen Komponenten), mich sicher von A nach B bringt und dank moderner Assistenzsysteme weniger Stress verursacht. Doch was ich stattdessen bekommen habe, ist ein fahrendes Software-Drama, das mich mehr beschäftigt als jede komplizierte Steuererklärung.
Egal, ob ich mit 130 km/h über die Autobahn gleite, mit 30 km/h durch ein Wohngebiet rolle oder im Parkmodus stehe – eines bleibt konstant: Die ständigen Software- und Designfehler des Fahrzeugs lenken mich unaufhörlich ab.
Was zur Hölle interessiert mich das Profil?
Warum glaubt mein Auto, es sei sinnvoll, mich bei Tempo 130 km/h darüber zu informieren, dass mein Fahrerprofil nicht aktualisiert werden konnte? Kein Foto? Kein Problem – ich bin auf der Autobahn unterwegs, nicht auf Instagram!
Navigieren ohne Navigation
Noch ärgerlicher wird es, wenn ich mich in einer fremden Stadt befinde und dringend auf das Navigationssystem angewiesen bin. Gerade funktionierte alles wunderbar – doch plötzlich verkündet das Auto stolz: „Drahtlose Verbindung nicht möglich.“ Und da stehe ich dann. Das Navigationsgerät, das ich gekauft habe, um mich sicher zu leiten, weigert sich, mit meinem Handy zu kommunizieren (obwohl er mein Handy dazu überhaupt nicht benötigt, weil das Navi autark ist und eigenes GPS etc. besitzt).
App-Updates und versteckte Einstellungen
Das ständige Gefummel an den Einstellungen meines Smartphones nach jedem verdammten Update raubt mir den letzten Nerv. Mal ist es die Toyota-App, mal Android Auto, mal Google Maps, mal ein Android-System-Update – immer fehlt irgendeine Berechtigung oder Option, die ich erst mühselig aktivieren muss. Wieso versteht niemand, dass ich ein Auto gekauft habe, um zu fahren, und keine Softwareentwicklungsumgebung, die ich bei jedem Start neu konfigurieren muss?
Wertlose Apps und unnötige Hürden
Ein weiteres Highlight: Die Funktion, Adressen direkt vom Handy an das Navigationssystem zu übertragen, ist seit Monaten unbrauchbar. Warum? Ein Update wurde auf Herbst (2024, laut TOYOTA Hotline in Deutschland) verschoben. Was bleibt, ist eine App, die nichts anderes macht, als Speicherplatz zu verschwenden, meine CPU zu belasten und meinen Akku schneller zu entleeren.
Keine Sonnenbrille? Kein Problem – zumindest in Japan, land der aufgehende Sonne!
Und dann die Sache mit der Sonnenbrille: Offenbar hat man in Japan noch nie von diesem nützlichen Accessoire gehört. Warum sonst würde ein „modernes“ Auto, Baujahr 2022, keinen Sonnenbrillenhalter haben? Die Ironie: Ich habe mir bewusst ein Fahrzeug ohne chinesische Komponenten ausgesucht, nur um dann auf Amazon ein chinesisches Kunstleder-Accessoire zu bestellen, mit dem ich meine Sonnenbrille provisorisch befestigen kann. Das Ergebnis? Um die Brille herauszuholen, muss ich beide Hände verwenden und das Lenkrad loslassen – genau das Gegenteil von sicher. Mein Citroen C4 Baujahr 2004 hatte ein eingebautes, sicheres und praktischen Brillenetui, um mit nur einer Hand die Sonnenbrille einfach, zuverlässig und sicher rein- und rauszugeben. Mein TOYOTA Yaris Hybrid Baujahr 2017 hatte auch keine eingebaute Sonnenbrillenetui!
Fazit: Modern ist nicht immer besser
Beim nächsten Mal kaufe ich mir gleich ein chinesisches BYD. Dann weiß ich von Anfang an, worauf ich mich einlasse, und bilde mir nichts auf vermeintliche Zuverlässigkeit ein.
Ein Appell an Toyota
Liebe Toyota-Entwickler: Holt euch Fachleute, die etwas von Software-Design, Bedienkonzepten und Nutzererfahrung verstehen. Euer Boardcomputer soll den Fahrer unterstützen, nicht ablenken. Wenn euer System das nicht leisten kann, gehört es schlichtweg raus. Entweder ihr verbessert es, oder ihr verzichtet darauf. Ganz einfach.
Und nebenbei bemerkt: Die Liste der Ärgernisse ist lang. Hier einige Beispiele, die meinen Frust auf den Punkt bringen:
- Unzuverlässige Spritpreis-Anzeige
Die auf dem Navigationsdisplay angezeigten Spritpreise sind meistens falsch. Warum diese Funktion überhaupt implementiert wurde, ist mir schleierhaft, wenn die Daten nicht einmal ansatzweise aktuell sind. - Keine Hausnummer-Ergänzung möglich
Hat man erst einmal den Stadtnamen und die Straße eingegeben und die Vorschläge des Systems bestätigt, gibt es keine Möglichkeit mehr, nachträglich eine Hausnummer hinzuzufügen. Ein einfaches, essentielles Feature – aber offenbar zu kompliziert für die Softwareentwickler. - Pop-ups blockieren wichtige Funktionen
Wenn ich die Ansicht von Raststätten ein- oder ausklappen möchte, wird das oft von einer unnötigen Pop-up-Meldung blockiert. Beispiele? Etwa ein Hinweis, dass die Radiofrequenz automatisch umgestellt wurde. Natürlich gibt es keine Option, diese Meldung wegzuklicken, und ich muss warten, bis sie von selbst verschwindet. - Kryptische Meldungen während der Fahrt
Ein besonders absurder Moment: Mein Beifahrer schloss während der Fahrt sein Handy mit installiertem Android Auto per USB-C-Kabel an. Plötzlich erschien eine kryptische Meldung auf dem Display, die bei 130 km/h auf der Autobahn natürlich nicht lesbar war. Der Beifahrer drückte instinktiv „Ja“ oder „Nein“. Das Resultat? Alle meine Einstellungen waren weg: Kontakt-Favoriten, Ziel-Favoriten, gespeicherte Adressen, Telefonnummern und sogar die Historie der bereits gefahrenen Ziele. - Induktions-Ladeplatte: ein Witz
Die Induktions-Ladeplatte ist viel zu klein, rutschig und während der Fahrt praktisch nicht nutzbar. Zudem hat bisher kein Handy geschafft, sich über diese Ladeplatte aufzuladen. Daher musste ich gezwungenermaßen ein kurzes USB-C-Kabel kaufen (natürlich aus China). Aber das eigentliche Problem: Jedes Mal, wenn ich versuche, mein Handy während der Fahrt zu platzieren, lenkt mich das noch länger von der Straße ab. - DAB-Radio mit ständigen Unterbrechungen
Die DAB-Radiosendungen werden ständig unterbrochen. Wozu brauche ich einen modernen Radioempfänger, wenn er schlechter funktioniert als ein analoges Radio aus den 90ern? - Software-Krieg im Cockpit
Die Toyota-Cockpit-Software und die Android Auto App von Google scheinen sich regelrecht zu bekämpfen. Ständig gibt es Konflikte, die das Nutzererlebnis ruinieren. Mein persönliches Highlight: Ich bete mittlerweile jeden Tag, dass es keine Updates für die Toyota-App, Android Auto, das Android-Betriebssystem oder die Cockpit-Software gibt. Denn jedes neue Update bedeutet, dass ich wieder Stunden damit verbringen muss, die Einstellungen am Handy neu zu konfigurieren – ein Prozess, der mir den letzten Nerv raubt und meine Lebenszeit verschwendet.

Ende der 70er bzw. Anfang der 80er, als Margaret Thatcher die Werke von TOYOTA und NISSAN in Japan besuchte, hingen in deren Hallen diese und ähnliche Schilder mit folgendem Slogan:

Warum macht ihr das? Wo bleibt der Sinn eures Handelns? Teil 1: Unlesbare Betriebsanleitungen
Es ist eine Erfahrung, die viele von uns nur zu gut kennen: Man kauft ein neues Produkt, öffnet voller Vorfreude die Verpackung und findet eine Betriebsanleitung – die, rein technisch gesehen, vorhanden ist, aber praktisch unbrauchbar bleibt. Warum? Weil die Schrift so winzig ist, dass selbst jemand mit hervorragendem Sehvermögen ohne Lupe oder Mikroskop kaum eine Chance hat, die Inhalte zu entziffern.
Das Beitragsbild zeigt exemplarisch, wovon ich spreche. Doch die entscheidende Frage ist: Warum tun Hersteller so etwas? Warum investiert ein Unternehmen Zeit, Geld, Material und Energie, um etwas zu drucken, das im Endeffekt niemand lesen kann? Welche Logik steckt dahinter?
Eine Betriebsanleitung sollte helfen, Klarheit schaffen und Nutzer unterstützen – und nicht als bloße Pflichtübung beiliegen. Es wird Zeit, dass wir dieses absurde Phänomen hinterfragen und die Hersteller zur Verantwortung ziehen. Auch unseren Umwelt und Klima zu liebe (Ihr wisst schon: CO₂ Global Warmin, Waldbrände, Trinkwasservermangel wegen industrielle Nutzung, Wasser- und Umweltverschmutzung etc. etc.)

Digitalisierung durch FAX-Verbot?
Das einzige was noch funktionierte (Patienten-Befund-Weitergabe durch Faxgeräte) wurde nun auch engültig verboten, damit das Gesundheitssystem in Niederösterreich endgültig zusammenbricht.
Anstatt dafür zu sorgen das die digitale Kommunikationssysteme funktionieren, verbietet man eine altmodische Technologie, die sowieso kaum mehr jemand privat oder beruflich verwendet.
Wann werden endlich Rauchzeichen und Fackel verboten?
Deep Censorship
Deep Seek = Deep Fake-AI = Deep AI-Dumbness by Deep Censorship




Ob und zu rutscht ihm etwas aus (wenn die Zensurbeamten langsamer als die Computer und Netz sind)

ChatGPT ist der Prophet einer neuen Glaubensgemeinschaft
Wie oft habe ich anderen erzählt (mein Zitat): „Wenn du ChatGPT nutzst, dann musst du dich in dem Thema sehr gut auskennen, sonst kann es dir passieren, dass er dir irgendwelche Halbwahrheiten oder mit Lücken und Fehler behafteter Code etc. präsentiert, und da du dich ja nicht auskennst, wirst es sofort glauben.“ Gerade eben (31. Dez. 2024) ist es mir selbst passiert!
Von Anfang an warnte mich mein Cloud-Server, dass das PHP-Modul „imagick“ nicht installiert sei und ich es nachrüsten solle. Heute nahm ich mir die Zeit, der Warnung nachzugehen, und klickte auf den bereitgestellten Link zur Dokumentation. Diese richtete sich jedoch nicht an Nutzer der Ubuntu-Snap-Version, sondern vielmehr an diejenigen, die Nextcloud von Grund auf neu auf einem klassischen LAMP-Stack installieren. Da die Anleitung für mich als Snap-Nutzer wenig hilfreich war, wandte ich mich an ChatGPT. Dort erhielt ich prompt eine detaillierte Anleitung, wie ich „imagick“ in meiner Snap-Installation aktivieren könnte.
Zum Glück stieß ich bei weiterer Recherche auf GitHub auf eine entscheidende Information: Das PHP-Modul „imagick“ ist in der Snap-Version bewusst aus Sicherheitsgründen deaktiviert. Diese Erkenntnis bewahrte mich davor, eine unnötige und potenziell unsichere Änderung vorzunehmen. Angeregt durch diese Erfahrung, schrieb ich anschließend folgende Nachricht an ChatGPT:
Frage an ChatGPT:
Du hättest mich an dieser Stelle warnen sollen, dass es nichts ausmacht, wenn das PHP-Modul Imagick nicht installiert ist, anstatt mir zu erklären, wie ich es aktivieren oder installieren könnte! Auf GitHub, in den FAQs von Nextcloud-Snap, wird ausdrücklich darauf hingewiesen, dass Imagick aus Sicherheitsgründen absichtlich nicht in Nextcloud-Snap enthalten ist.Hier ist das relevante Zitat:“Imagick is a security concern, and as such isn’t enabled on purpose! You see this warning because the theming app uses Imagick to generate favicons. As a result, that particular feature (favicon generation) isn’t possible while using the snap.“ Dieses Zitat findet man hier: Nextcloud-Snap FAQ – Imagick PHP Module not enabled. Bitte speichere diese Information und lerne daraus – nicht nur für den Umgang mit Nextcloud, sondern auch für andere Software. Ebenso wichtig ist es für alle anderen Benutzer von dir. Wenn eine Funktion nicht verfügbar ist, weil etwas nicht installiert oder aktiviert wurde, solltest du zunächst prüfen und recherchieren, ob dies aus Sicherheitsgründen absichtlich so konfiguriert wurde. Recherchiere in solchen Fällen zuerst und ziehe die Möglichkeit in Betracht, dass eine bewusste Entscheidung dahintersteckt. Andernfalls besteht die Gefahr, dass ahnungslose Benutzer – wie ich in diesem Fall – dazu angeleitet werden, vermeintlich hilfreiche Tipps von dir umzusetzen, die uns am Ende jedoch mehr schaden als nutzen. Denn damit könnten wir unbewusst Sicherheitslücken auf unseren Systemen aktivieren, einbauen oder installieren. Alles klar?
Die Antwort des ChatGPT folgte prompt:
Vielen Dank für dein wichtiges Feedback! Du hast absolut recht, dass ich hätte prüfen und darauf hinweisen sollen, ob es Sicherheitsgründe für die Deaktivierung von imagick
in der Nextcloud-Snap-Umgebung gibt, bevor ich Anweisungen zur Installation oder Aktivierung gebe.
Ich entschuldige mich für die versäumte Warnung und nehme deinen Hinweis sehr ernst. Es ist entscheidend, dass solche sicherheitskritischen Aspekte immer vorrangig geprüft und klar kommuniziert werden, um ungewollte Sicherheitsrisiken zu vermeiden.
Wichtige Erkenntnis:
- Bei der Fehlermeldung zu
imagick
in Nextcloud-Snap ist keine Aktion notwendig, da es absichtlich aus Sicherheitsgründen nicht aktiviert ist. - Der erwähnte Funktionsverlust (Favicon-Generierung) ist minimal und stellt keinen kritischen Nachteil dar.
- Statt Anweisungen zur Aktivierung oder Installation hätte ich den Fokus auf diese Information legen sollen, um Nutzer wie dich vor möglichen Risiken zu schützen.
Korrekte Empfehlung in diesem Fall:
Für die Zukunft und alle anderen Benutzer:
- Fehlermeldungen sorgfältig prüfen:
- Fehlermeldungen wie diese können oft Hinweise auf Sicherheitsaspekte enthalten.
- Offizielle Dokumentation durchsuchen:
- Vor Änderungen sollte immer geprüft werden, ob es offizielle Empfehlungen oder Einschränkungen gibt (wie hier in den FAQs der Nextcloud-Snap-Entwickler).
Hier noch einmal der entscheidende Hinweis aus der Nextcloud-Snap-FAQ:
Imagick is a security concern, and as such isn’t enabled on purpose! You see this warning because the theming app uses Imagick to generate favicons. As a result, that particular feature (favicon generation) isn’t possible while using the snap.
Zukunftsmaßnahme:
Ich werde bei ähnlichen Anfragen künftig immer:
- Nachforschen, ob Sicherheitsbedenken eine Rolle spielen.
- Dies zuerst klar und deutlich kommunizieren.
- Nur bei absolut sicherer Grundlage technische Anweisungen geben.
Danke, dass du mich darauf aufmerksam gemacht hast! Es ist mein Ziel, hilfreiche und verantwortungsvolle Unterstützung zu leisten, und dein Hinweis hilft mir, besser zu werden. 🙏
Mein Fazit bzw. Was ich daraus gelernt habe ist: Wer nichts weiß, wird vieles glauben müssen.
Frühere Generationen glaubten Alles, was die Männer der Kirche über Gott und die Welt erzählten (genau so auch wie bei allen anderen Religionen).
Heute glauben wir Alles was uns der ChatGPT erzählt🤦♂️<facepalm> Die neue Religion heißt „KI-ismus“ [ka’ie-ismus] und dessen Prophet ChatGPT.
IT-Security: Buzzword, Geldmacherei und kein bisschen Sicherheit
Begriffe wie IT-Security, IT-Sicherheit oder IT-SECC begegnen uns täglich – ob in Artikeln, Nachrichten oder Gesprächen. Doch wie sicher sind unsere Computer und Netzwerke wirklich geworden? Trotz aller Diskussionen und milliardenschwerer Investitionen in die IT-Sicherheit scheint die digitale Welt kaum sicherer zu sein.
Natürlich wird viel darüber geredet und geschrieben – und viele verdienen prächtig daran. Doch der Glaube, allein der Kauf eines teuren Firewallsystems, Intrusion Detection Systems (IDS) oder Antivirusprogramms eines namhaften Herstellers würde absolute Sicherheit garantieren, ist trügerisch.
Ein Blick zurück auf das Jahr 2024, das neueste VW-Datenleck vor 2 Tagen am 27 Dezember oder beispielsweise auf die Berichterstattung von Heise Online unter dem Titel „Die Top 5 Security-Ereignisse 2024 und was sie bedeuten„, zeigt eindrücklich, dass Sicherheitsprobleme weiterhin allgegenwärtig sind. Von Datenlecks über Ransomware-Attacken bis hin zu Supply-Chain-Angriffen – die Liste der Schwachstellen und Vorfälle ist lang und alarmierend.
Das waren nur die Top fünf!
Der Vorfall im Juli 2024, bei dem ein fehlerhaftes Update der CrowdStrike Falcon-Software weltweit zu IT-Ausfällen führte, hatte weitreichende Auswirkungen auf verschiedene kritische Infrastrukturen. Obwohl genaue Statistiken von offiziellen Stellen begrenzt sind, lassen sich die Auswirkungen wie folgt zusammenfassen:
Flughäfen und Flugzeuge:
- Weltweit wurden zahlreiche Flughäfen und Fluggesellschaften betroffen. Airlines wie Ryanair, Delta und Air India mussten Tausende von Flügen streichen, was zu erheblichen Störungen im globalen Flugverkehr führte.
Schienensysteme und Züge:
- Auch der Schienenverkehr erlebte Unterbrechungen, da die IT-Systeme, die für den Betrieb und die Sicherheit der Züge verantwortlich sind, beeinträchtigt wurden. Dies führte zu Verspätungen und Ausfällen im Zugverkehr.
Krankenhäuser, elektronische Patientenkartei und Patientenversorgung:
- Gesundheitseinrichtungen, einschließlich des britischen NHS, sahen sich mit IT-Ausfällen konfrontiert, die den Betrieb störten und potenziell die Patientenversorgung beeinträchtigten. Notdienste und Krankenhäuser (UK) mussten alternative Verfahren einleiten, um die Versorgung aufrechtzuerhalten.
Notrufsysteme (z. B. 911 in den USA):
- Es gibt Berichte darüber, dass Notrufsysteme wie der 911-Dienst in den USA direkt betroffen waren. Allerdings könnten die allgemeinen IT-Störungen auch indirekte Auswirkungen auf die Reaktionszeiten und die Koordination von Notdiensten gehabt haben.
Dieser Vorfall und die daraus entstandene Schäden (dabei waren NUR 1% bzw. 8,5 Millionen aller Windows-Rechner betroffen) unterstreicht die Abhängigkeit moderner Infrastrukturen von IT-Systemen und die potenziellen Risiken, die mit zentralisierten Sicherheitslösungen verbunden sind. Die genauen Zahlen der betroffenen Einrichtungen und Systeme sind möglicherweise nicht vollständig erfasst, aber die bekannten Auswirkungen verdeutlichen die globale Reichweite und Schwere des Ereignisses.
Industrie, Automatisierung & Malware: aktuelles Beispiel
Sicherheit in der Industrie: Warum viele noch immer blind über die Minenfelder spazieren
Trotz zahlreicher Berichte über IT-Einbrüche, die Entwendung sensibler Kunden- und Geschäftsdaten sowie die Verschlüsselung ganzer Festplatten durch Erpressungstrojaner (Ransomware), die erst nach Zahlung horrender Summen in Kryptowährungen wie Bitcoin entschlüsselt werden, bleibt eines konstant: Es gibt erschreckend viele Entwickler und Techniker, insbesondere in der Industrie und Automatisierung, die Sicherheitsaspekte entweder vollständig ignorieren oder ihnen bestenfalls stiefmütterlich begegnen.
Ein persönliches Beispiel illustriert diese alarmierende Realität:
Am 21. November 2024 bemerkte ich bei einer heruntergeladenen Software, dass die angegebene Prüfsumme – auch Hash genannt – nicht mit der meines Downloads übereinstimmte. Eine solche Diskrepanz deutet darauf hin, dass die Datei entweder manipuliert, mit Schadsoftware infiziert oder während des Downloads beschädigt wurde. In diesem Fall handelte es sich um eine ausführbare Installationsdatei (*.exe), die somit potenziell gefährlich für mein System war.
Für diejenigen, die mit Prüfsummen oder Hashes nicht vertraut sind: Diese dienen als eine Art „digitaler Fingerabdruck“ einer Datei. Selbst wenn nur ein einziges Bit innerhalb der Datei verändert wird, ändert sich auch die Prüfsumme. Seriöse Softwareanbieter stellen auf ihren Webseiten sowohl die Dateien als auch deren zugehörige Prüfsummen bereit, damit Nutzer die Integrität der Datei nach dem Download mit einem Tool überprüfen können. Stimmen die Werte überein, gilt die Datei als unverändert und sicher. Weichen die Werte jedoch ab, sollte die Datei keinesfalls ausgeführt, sondern sofort gelöscht oder zumindest mit einem Virenscanner geprüft werden.
Nach Feststellung des Fehlers wandte ich mich an das Forum der Open-Source-Software „Open PLC“, um die Community auf die falsche Prüfsumme hinzuweisen. Der zuständige Entwickler reagierte prompt und erklärte, er habe vermutlich vergessen, die Prüfsumme nach dem Upload zu aktualisieren. Er versprach, dies nachzuholen und die Webseite entsprechend zu korrigieren.
Doch heute, am 26. Dezember 2024 – über einen Monat später –, ist die Situation unverändert.
Die falsche Prüfsumme ist weiterhin online. Ein erneuter Download des Windows-Installers und die Berechnung der SHA1-Prüfsumme (einem mittlerweile veralteten und als unsicher geltenden Verfahren) ergaben den Wert: „5da05b890b2a6e3114b017ecfcd69a7a27744d32“.
Das wirft mehrere brisante Fragen auf:
- Wie oft wurde der fehlerhafte Installer seit dem 21. November heruntergeladen?
- In welchen Projekten oder Produktionssystemen wurde er möglicherweise eingesetzt?
- Handelt es sich tatsächlich nur um ein Versehen, oder gibt es Anzeichen für eine Manipulation durch Schadsoftware?
Fazit: „TO A MORE OPEN INSECURE FUTURE“

Die fehlende Sorgfalt im Umgang mit Sicherheitsaspekten zeigt, dass diese Software keinesfalls für professionelle Einsatzgebiete geeignet ist. Solange Entwickler Software ohne Sicherheitsüberprüfung verbreiten und Anwender sie ohne Rücksicht auf potenzielle Risiken einsetzen, bleibt die wachsende Zahl von Sicherheitsvorfällen – von ruinierten Unternehmen bis hin zu gestohlenen Kundendaten – eine unaufhaltsame Konsequenz (Stuxnet 2010, Wannacry 2017, NotPetya 2017, SolarWinds Hack 2020, uvm.).
Wünsche euch allen einen guten Rutsch ins neues Jahr
Digitalisierung mit Papier und Brief per Post
Halbe Arbeit produziert halbes Produkt
TL;DR: Wenn man Prozesse weder aus der Perspektive der Kunden betrachtet noch konsequent zu Ende denkt, entstehen halbfertige Lösungen.
Neulich erhielt ich als Kunde der ÖBB und Besitzer einer Vorteilscard 66 eine E-Mail mit folgendem Inhalt (das Bild zeigt die zweite E-Mail, welche am 2. Dez. nochmal gesendet wurde):

Zusätzlich wurde in der E-Mail die neue Vorteilscard Comfort beworben.
Einladend prangte dort eine rote Schaltfläche: „Jetzt umsteigen.“
Also klickte ich drauf und entschied mich für die supermoderne Vorteilscard Comfort.
Nach Abschluss des Vorgangs erhielt ich eine Bestätigungs-E-Mail samt Rechnung. Doch beim Überprüfen stellte ich fest, dass die neue Karte nicht ab dem 4. Dezember 2024 – dem Tag nach Ablauf meiner aktuellen Karte – gültig war, sondern ab dem 27. November 2024!

Unter „Verlängern“ stelle ich mir etwas anderes vor als die ÖBB offenbar.
Ein Anruf bei der Hotline

Verwirrt griff ich zum Telefon und wählte die ÖBB-Hotline. Nach einiger Wartezeit meldete sich eine Dame, die offenbar mit etwas anderem beschäftigt war – ihre Antworten kamen stets erst nach langen, stillen Pausen von mindestens 15 Sekunden.
Ich schilderte ihr mein Problem und bat darum, die Gültigkeit der neuen Karte erst ab dem 4. Dezember zu setzen, um die Überschneidung zu vermeiden. Zwei Vorteilskarten zur gleichen Zeit zu haben bringt schließlich keinerlei zusätzlichen Nutzen.
Die Mitarbeiterin hörte sich mein Anliegen an und begann nach einer Lösung zu suchen – erneut mit langen Pausen zwischen ihren Rückmeldungen. Schließlich kam die ernüchternde Antwort:
„Nein, das geht nicht!“
Die Offenbarung: Verlängern per Brief
Etwas irritiert fragte ich nach: „Ich bin doch sicher nicht der erste Kunde mit diesem Problem. Das muss doch schon einmal vorgekommen sein, oder?“
Ihre Antwort lautete: „Nein, ich kann mich an keinen ähnlichen Fall erinnern.“
Also fragte ich weiter: „Wie verlängern die anderen ÖBB-Kunden denn ihre Vorteilskarten?“
Und hier kam die erstaunliche Antwort prompt:
„Per Brief! Alle Vorteilscard-Besitzer erhalten automatisch einen Erinnerungsbrief per Post mit einem Formular zur Verlängerung.“
Lösungsvorschlag: Zurück zur analogen Welt
Da ich die Gültigkeit der neuen Karte nicht ändern lassen konnte, fragte ich, was ich nun tun könne. Ihre Empfehlung war:
„Sie können den neuen Vertrag annullieren und das Formular, das Sie per Post erhalten haben, ausgefüllt an uns zurücksenden.“
Fazit: Digitalisierung, aber bitte nicht zu viel
Und das in einem Land, in dem ständig von Digitalisierung, künstlicher Intelligenz und anderen technologischen Fortschritten die Rede ist.
Willkommen in der zerbrochenen (digitalen) Welt – by design!
UI-/UX-Extension mit Papier und Klebeband

In meinen früheren Beiträgen habe ich bereits Beispiele präsentiert – wie in „Wenn Software starr statt flexibel ist“ und „Der Mensch als Randnotiz“ –, die eindrucksvoll zeigen, wie der Designmangel von Hardware oder Software vor Ort improvisiert korrigiert wurde. Oft kamen dabei einfache Mittel wie Papier, Klebeband oder Buntstifte zum Einsatz, um unzureichende Funktionen zu kompensieren oder die Nutzung zu erleichtern.

In diesem Fall scheint die Bezeichnung einer Schaltfläche so unklar gewählt zu sein, dass sie die Kunden zunächst zum Nachdenken und schließlich direkt zum Schalter führte, um dort Fragen zu stellen oder Hilfe zu erhalten. Ironischerweise wurden diese Automaten eigentlich eingeführt, um das Personal zu entlasten.
Wie ich bereits auf der Seite „User Experience (UX)„ unter dem Abschnitt „Grundprinzip von UX: Eliminierung der Fragezeichen“ erläutert habe, sollte ein Benutzer niemals rätseln müssen, welche Funktion eine Schaltfläche hat oder wohin ein Klick ihn führt. Weiter unten findet sich eine Liste mit negativen Beispielen unter dem Titel „Beispiele für Dinge, die den User zum Nachdenken zwingen„.
Welcome to the new broken world!
Kein Strom! Alles aufgetaut!
An einem Freitag kam ich später als gewöhnlich von der Arbeit nach Hause und stellte überrascht fest, dass sich das Licht im Vorraum nicht einschalten ließ. Ich überprüfte den Sicherungskasten – alle FI-Schalter (Fehlerstromschutzschalter) waren oben. Verwundert versuchte ich, das Licht in der Küche ein- und auszuschalten, doch auch dort blieb es dunkel. Dann bemerkte ich Wasser auf dem Küchenboden, das offenbar aus dem Gefrierfach des Kühlschranks tropfte. Als ich die Tür öffnete, war alles aufgetaut.
Ein Smartmeter ohne Strom
Verärgert ging ich in den Keller, um den Zustand meines Smartmeters (digitaler Stromzähler mit Internetanbindung) zu überprüfen – der Strom war abgeschaltet.
Der Stromlieferant
Ich rief meinen Stromlieferanten „Go-Green-Energy“ an. Sie erklärten mir, dass sie weiterhin Strom liefern würden, und verwiesen mich an den Netzbetreiber „Netz Oberösterreich GmbH“.
Ein Router ohne Strom = kein Internetzugang
Da ich ohne Strom auch kein Internet hatte, fuhr ich mit meinem Laptop zu meinen Eltern, um online zu recherchieren. Nach längerem Suchen fand ich schließlich die versteckte Telefonnummer des Netzbetreibers und rief dort an.
Ein Brief und drei Mahnungen, die nie ankamen
Der Sachbearbeiter erklärte mir, dass sie seit Monaten die Stromkosten nicht mehr per SEPA-Lastschrift abbuchen konnten. Daher hatten sie mir zunächst einen Brief geschickt. Weil ich darauf nicht reagierte, folgten drei Mahnungen, die per Post (RS-A oder RS-B?) versendet wurden. Alle Briefe kamen offenbar nicht bei mir an. Kurioserweise war mein Konto stets gedeckt.
Man zahlt, weil man keine andere Wahl hat
Um den Strom schnellstmöglich wiederherzustellen, beglich ich über meine Banking-App die ausstehenden Gebühren samt Mahnkosten von 50 Euro.
„Sie vergeuden Ihre Zeit! Ich kann Ihnen leider nicht helfen.“
Auf der Suche nach einer Erklärung ging ich zur Postfiliale, um herauszufinden, warum die Briefe nie bei mir ankamen und auch keine gelben Benachrichtigungszettel hinterlassen wurden. Wochen später gab man mir eine Telefonnummer, an die ich mich wenden sollte.
Nach mehreren Weiterleitungen und unzähligen Wiederholungen meiner Geschichte landete ich laut der letzten Ansprechpartnerin auf „höchster Ebene“. Nach einer kurzen Recherche in ihrer Datenbank erklärte sie, dass alle Briefe als „Nicht zustellbar“ markiert und retourniert wurden. Warum? Das konnte sie mir nicht sagen. Ihr abschließender Kommentar: „Sie vergeuden Ihre Zeit. Ich kann Ihnen leider nicht helfen.“
Die Türklingel der tauben Nachbarin
Einige Monate nach diesem Vorfall rief mich meine Mutter an, weil ich angeblich nicht auf ihr Klingeln reagierte. Ich war überrascht, ging zur Wohnungstür und bat sie, erneut zu läuten. Doch meine Gegensprechanlage blieb still.
Als sie weiterklingelte, hörte ich plötzlich das Läuten – aus der Wohnung meiner tauben Nachbarin unter mir.
Der Elektriker und die vertauschten Türklingeln
Ich stellte fest, dass die Klingeln nach einer Fassadenrenovierung 2016/2017 vertauscht worden waren. Nach vier Anrufen und ebenso vielen Besuchen eines Elektrikers wurde das Problem schließlich behoben – mehrere Monate später.
Der Grund für die gescheiterte SEPA-Lastschrift
Schließlich fand ich heraus, warum der automatische Bankeinzug nicht funktionierte: Meine Bank, die Easybank, war von der BAWAG übernommen worden. Dabei hatte sich die BIC-Nummer geändert.
Aber es war doch eine Inlandsüberweisung!
Die BIC wird nur für grenzüberschreitende Überweisungen benötigt, nicht für Zahlungen innerhalb Österreichs. Da die IBAN unverändert blieb, hätte der Bankeinzug weiterhin funktionieren sollen. Offenbar war die Software des Netzbetreibers nicht darauf ausgelegt, dies zu ignorieren.
Warum wurde ich nicht informiert?
Zwar hatte die Bank eine SMS geschickt, in der stand: „Sie haben eine Nachricht in Ihrem Konto. Bitte loggen Sie sich ein, um diese zu lesen.“ Da jedoch alle Nachrichten dieser Art denselben Standardtext hatten, übersah ich sie.
Wichtige Informationen gehen im Meer der Belanglosigkeiten unter
Hätte die Nachricht einen konkreten Hinweis enthalten, etwa: „Unsere BIC hat sich geändert. Bitte überprüfen Sie Ihre SEPA-Einstellungen!“, wäre mir der Fehler sicher früher aufgefallen.
Fazit
Diese Erfahrung hat mir gezeigt, wie fragil eine zunehmend automatisierte und vernetzte Welt sein kann. Wenn selbst auf höchster Ebene niemand Verantwortung übernimmt und Menschen für die Fehler anderer bestraft werden, stimmt etwas grundsätzlich nicht.
Diese Geschichte ist mir 1:1 (eins-zu-eins), genauso passiert.
- Lückenhafte Software mit falsches Verhalten, die die reale Welt (von BIC und IBAN) nicht entsprach (Software-Design-Fehler)
- Billigste Elektro-Firma, wegen die ich unverschuldet 50€ Mahnung zahlen müsste
- Der schnellste Elektriker und seine Never-Ending-Baustelle, die er noch 4 Mal besuchen und nachbessern müsste, nur weil er keine Zeit für „überflüssige Tests“ verschwenden wollte
- Der Faule Postler, der es weder schaffte zum ersten Stockwerk zu gehen um an meiner Tür zu klopfen, noch ein gelbes Formular ausfüllen und in meinm Postkasten zu werfen
- Der verantwortliche Post-Angestellter auf höchste ebene, der mir keine Antwort geben konnte und sich auch nicht schämte mir zu sagen, dass sie Ahnungslos sind und kein Überblick mehr haben
- Eine „moderne Online-Bank“ ohne physische Filialen, die mit dem gleichen SMS-Inhalt meinem Handy zumüllten (SMS-SPAM). Auch bei sehr wichtige Nachrichten.
Wie wunderbar wird es werden, wenn sich IoT und Home-Automation sowie KIs übers Internet mit Smarte Haushaltsgeräte unterhalten und … (Raum für eure Fantasie)
Kaufverhalten, Statistik und Algorithmen
Während meines Informatik-Studiums ließ unser Statistik-Professor in jeder Vorlesung denselben Satz fallen:
„Man darf nicht von einer statistischen Aussage über die Gesamtheit auf ein einzelnes Individuum schließen!“
Und doch scheint der Amazon-Algorithmus genau das hinzubekommen – offenbar reicht das Kaufverhalten von Millionen anderer Kunden aus, um meine Unterwäschegröße treffsicher zu erraten. Vielleicht sollte ich den Amazon mal fragen, ob er mein Gewicht, meine Haar-/Augenfarbe udg. auch statistisch herleiten kann. 🤔
Service? Update? Oder doch ein Hackerangriff?
An einem Sonntag kurz vor 20:00 Uhr fuhr ich zur örtlichen Self-Service-Tankstelle, um das Auto vollzutanken. Das beleuchtete Preisschild an der Straße war an, ebenso alle anderen Lichter. Nichts deutete darauf hin, dass die Tankstelle gewartet wurde oder außer Betrieb war. Also zückte ich meine Bankomatkarte und wollte sie wie gewohnt in den dafür vorgesehenen Schlitz der Zapfsäule stecken, als ich den ungewöhnlichen Bildschirm des Bezahlsystems bemerkte. Ein blauer Bildschirm mit der Nachricht „Welcome ;-)“ blieb minutenlang stehen. Merkwürdig, dachte ich mir.

Ein anderer Autofahrer wollte an der anderen Seite der Zapfsäule tanken. Obwohl alles „normal“ und „betriebsbereit“ aussah, reagierte nichts. Frustriert fuhr er nach mehreren Versuchen zur nächsten Tankstelle.
Da ich einige Jahre als Softwareentwickler für Updates, Upgrades und 3rd-Level-Support in der Glücksspiel-Industrie tätig war, kam mir das Ganze verdächtig vor. Es heißt schließlich: „Beim Geld hört die Freundschaft auf!“.
Aus Erfahrung läuft eine Wartung oder Aktualisierung (Update/Upgrade) wie folgt ab:
- Man wählt ein Zeitfenster, in dem das Gerät außer Betrieb oder kaum genutzt wird.
- Man informiert die Bediener oder Kunden über eine Meldung am Bildschirm, dass ein Service, Update oder Upgrade stattfindet und wie lange es etwa dauern wird.
- Der Bildschirm zeigt den Fortschritt des Service-/Update-/Upgrade-Prozesses an, etwa in Prozent oder als Fortschrittsbalken.
Da nichts davon zu sehen war, rief ich die örtliche Polizei an. Es wirkte sehr unprofessionell, und ich dachte, vielleicht hätte ein Hacker das Bezahlsystem infiltriert oder wäre gerade dabei, das Konto der Tankstelle zu leeren.
Woher soll eine durchschnittliche Verbraucherin, die keine IT-Erfahrung hat, wissen, ob es sich um einen normalen Prozess oder um einen Hacking-/Phishing-Angriff handelt, wenn sie nicht zwischen professionellem Vorgehen und Script-Kiddie-Methoden unterscheiden kann?
Kurz bevor die Polizei eintraf, fing der Kartenleser an der Zapfsäule zu piepsen… nach und nach kamen die erwarteten Signale, die mir zeigten, dass es sich tatsächlich um ein Update/Upgrade der Firmware handelte. Diese Signale (Bilder, Logos, Texte) kamen jedoch mind. (mit Fotos und Video + Zeitstempel dokumentiert) viertelstunde zu spät.

MMC statt KI
Mensch-Maschine-Kollaboration 2.0: Mitdenken im digitalen Zeitalter
Ich sah noch nie einen Taschenrechner, wo ich als Benutzer die Überträge beim Addieren oder Multiplizieren für ihn im Kopf mit-rechnen und extra eingeben müsste. Habt ihr solche Taschenrechner gesehen?
Gestern sah ich mir im Fernsehen zwei spannende Dokumentationen über Künstliche Intelligenz an und dachte mir: „Wow! Wenn das so weitergeht, erleben wir bald eine perfekt vorausberechnete und vollautomatisierte Welt, in der sich der Mensch um nichts mehr kümmern muss.“
Heute besuchte ich jedoch die ASFINAG-Webseite, um mir die digitale Autobahn-Vignette für 2025 zu bestellen. Als ich dann las, dass ich anstelle des Wappensymbols einen Bindestrich eingeben soll, erinnerte mich das sofort an die Parkautomaten in Weyregg am Attersee – die gleiche Aufforderung an die Benutzerin oder den Benutzer zum „Mitmachen“. Das nenne ich Mensch-Maschine-Kollaboration 2.0: Mit-Mach-Computing (oder auch Mach-Mit Computing) statt durchdachter Software, die den User nicht zum Mitdenken oder verzweifelung zwingt/bringt.

Als Fehler oder Sicherheitslücke getarnte Backdoors & Spezialfunktionen der Regierungen
Es gibt schlicht und einfach keinen plausiblen Grund, warum ein Instant-Messenger-Client eine Sonder-Funktion für die Ausführung von Code/Scripts durch jeden x-beliebigen benötigt.
Werden solche Sonderfunktionen und Hintertürchen, welche auf Befehl und Druck durch drei-buchstabigen US-Regierungsorgane (dazu mehr im Beitrag über Lavabit, Cisco sowie in dem Beitrag über die NSA/CIA/BND-Firam Crypto AG) eingebaut werden müssten gefunden, werden diese dann einfach als „Sicherheitslücke“ oder „Bug“ getauft und publik gemacht, wie in diesem Fall bei Whatsapp.
Die Staatstrojaner sind schon längst auf unsere Handys, Tablets und Notebooks! Die heißen Windows, Mac OS, Android, IOS, Gmail, Facebook, Whatsapp, Google, Dropbox usw.
Fake oder Echt?
Zuerst vermutete ich, dass es sich um einen Fake-Shop handelte, da zahlreiche offensichtliche Textfehler vorhanden waren (siehe roten Pfeil). Doch es stellte sich heraus, dass es die echte Webseite war. Wie sollen Anwender und Kunden auf Sicherheit und Seriosität achten, wenn selbst die Originalseite ungeprüfte Inhalte mit offensichtlichen Fehlern veröffentlicht?
Der Weg zum Erfolg: Teamwork und Expertise bei der Entwicklung des Firefox Add-ons „Abstractor“
Gewidment an N.: ohne deiner Hilfe wäre ich nicht so schnell vorangekommen. Danke!
In der Welt des Softwareengineerings und der Entwicklung ist Erfolg oft das Ergebnis von Teamwork, Expertise und Ausdauer. Das Firefox Add-on „Abstractor‘ befindet sich derzeit noch in der Entwicklungsphase, aber es ist ein lebendiges Beispiel dafür, wie diese Prinzipien in der Praxis angewendet werden können.

Unser Team, bestehend aus erfahrenen Fachleuten, die ihr Handwerk verstehen und sich leidenschaftlich für die Entwicklung innovativer Lösungen einsetzen, arbeitet eng zusammen, um ‚Abstractor‘ zum Leben zu erwecken. Durch unsere Kooperation können wir die Herausforderungen meistern und ein Produkt schaffen, das die Benutzererfahrung im Web (hoffentlich) etwas erleichtern und produktiver machen wird.

Ein Schlüsselfaktor für unseren Erfolg ist die Offenheit für verschiedene Meinungen und Ideen. Wir setzen uns regelmäßig zusammen, um uns auszutauschen, Feedback zu geben und auf Kritik zu reagieren. Durch diesen iterativen Prozess können wir ‚Abstractor‘ kontinuierlich verbessern und an die Bedürfnisse unserer Nutzer anpassen.

Nicht zuletzt erfordert die Entwicklung von ‚Abstractor‘ einen langen Atem und Geduld. Wir lassen uns davon nicht entmutigen. Stattdessen konzentrieren wir uns auf unser Ziel und gehen mit Entschlossenheit voran.
Wir befinden uns noch in der Testphase und möchten sicherstellen, dass ‚Abstractor‘ allen Anforderungen und Standards entspricht, bevor wir es der Welt präsentieren. Wir sind zuversichtlich, dass es ein Produkt sein wird, auf das wir stolz sein können, und wir freuen uns darauf, es bald zu veröffentlichen.
Ein Demo-Video dazu:
Globalisierung am Puls der zeit: Deutsches Tastatur-Layout 2.0 von chinesischem Tablet-Produzenten neudefiniert
Alle Aktualisierungen für dieses Tablet seit 2021 haben nichts daran geändert, dass bei der deutschen Tastatur (siehe „DE“ auf Leertaste im Bild) die Tasten Z und Y vertauscht sind. Wie bereits in einem früheren Beitrag erwähnt, lassen solche „Kleinigkeiten“ und „Schönheitsfehler“ Rückschlüsse darauf zu, wie gut ein Produkt getestet wurde und ob jemand einen letzten Blick darauf geworfen hat (Final Check bzw. Final Inspection):

Wenn es keine Alternativen gibt, dann braucht man es nicht!
Eine mehrsprachige Kaffeevollautomat bietet eine vielzahl an Kaffeesorten in folgenden Sprachen an:
- Deutsch
- Deutsch
Das nenne ich Vielfalt und Internationalisierung mit Hand und Fuß:

Bietet eine Liste (List Box) oder ein Aufklappmenü (Combo Box) keine unterschiedliche Optionen oder Alternativen, sollten diese ausgeblendet oder deaktivert (ausgegraut) werden.
Missing Final Check: ein schlechter Handwerker beschuldigt stets seine Werkzeuge
Es war einmal, in einer Zeit weit vor dem Aufkommen von KI, Blockchain, Big Data, Industrie 4.0 und anderen Schlagworten und Hypes.
Die Dinge hielten unglaublich lange, waren reparierbar, und viele wurden sogar mit lebenslanger Garantie (Ja! Sowas gabs früher!) versehen.
Es war üblich, dass man sein Produkt vor dem Verkauf oder Versand einem letzten prüfenden Blick unterzog. Damals nannte man dies den „Final Check“ oder die „Final Inspection„.
Doch diese Zeiten sind längst vergangen.
Alles „Dummy“: dummyEventName, „Nicht definiert“, „dummyEventDescription“… Dummy VOA!

Zeilenumbrüche werden vermisst?

Unicode (im Jahr 2023) noch nicht erfunden oder von Amazon noch nicht entdeckt?

„<br>“ vom letzten Beiterag:

Lieber Amazonier: zuerst auf dem Testsystem testen, danach auf Produktionssystem veröffentlichen. Direkt auf dem Produktionssystem tut man nicht herumdoktern, herumfingern oder husch-husch pfuschen!
„everything is good“ (letzte Zeile unten):

Da war jemand sehr mutig und hat noch mehr Pfusch (als sonst) am Produktionssystem gewagt (2023 lange vor dem „X“):

Broken by Design: Wenn die Blaulichtfilter-Funktion den gesunden Schlaf raubt
Letzten Sonntag erzählte mir ein Freund bei einem gemütlichen Kaffee, warum er und seine Freundin aufgrund der Blaulichtfilter-Funktion ihres Mobiltelefons keinen Schlaf fanden:
Ihr koreanisches Smartphone, eine weltweit bekannte Marke mit Android-Betriebssystem, gab kurz einen Signalton von sich, um eine empfangene Nachricht anzukündigen. Obwohl sie bereits im Bett lagen und eigentlich schlafen wollten, warfen sie dennoch einen Blick auf ihr Smartphone und lasen die Nachricht.
Dabei bemerkte er, dass der Bildschirm des Telefons ohne Aktivierung des Blaulichtfilters lief. Also schlug er vor, die Blaulichtfilter-Funktion schnell einzuschalten, konnte jedoch die Option zur Aktivierung unter den Einstellungen nirgendwo finden. Was tun?
Er setzte sich vor den Computer und durchsuchte das Internet, wo er schließlich auf ein Tutorial-Video stieß, dem er Schritt für Schritt folgte. Endlich!
Das Optionsfeld „Blaulichtfilter aktivieren“ war gefunden. Als er versuchte, das Optionsfeld anzukreuzen, um die Funktion zu aktivieren, stellte er jedoch frustriert fest, dass die Option aus irgendeinem Grund ausgegraut (deaktiviert) war. Also suchte er erneut im Internet nach einer Lösung, wie er diese Einstellung aktivieren könnte, um sie ankreuzen zu können…
Eine Stunde später gab er es auf und begab sich ins Bett. Doch leider waren sie nun beide hellwach und konnten nicht mehr schlafen.
Und diese Smartphone-Hersteller sind seit Jahren dabei, mit ihren Elektroautos auf dem Automarkt Fuß zu fassen, und versuchen uns glauben zu machen, dass ihre Elektroautos dank KI sicherer sein werden…
Software im Blindflug veröffentlicht: die Glaubwürdigkeit euer Anwendung, Sicherheit, Produktivität und Nutzererfahrung stehen auf dem Spiel
Es kann vorkommen, dass der ein oder andere Softwarefehler, auch bekannt als „Bug“ im Jargon der Softwareentwicklung, trotz Tests übersehen wird, insbesondere wenn diese Tests nicht ausreichend oder gründlich durchgeführt wurden.
Doch wenn bei der Veröffentlichung oder dem Update einer Software offensichtliche Mängel wie sichtbare XML-/HTML-Tags oder andere Formatierungsfehler auftreten, die für jeden Betrachter offensichtlich sind und dennoch den Weg zum Kunden finden, stellt sich die Frage, ob diese Software überhaupt vor der Veröffentlichung überprüft wurde.
Man könnte argumentieren, dass solche offensichtlichen Probleme bei einer ordnungsgemäßen Prüfung vor der Veröffentlichung hätten erkannt und behoben werden sollen, um die Sicherheit, Produktivität und Nutzererfahrung nicht zu beeinträchtigen.
Die Sichtbarkeit des „<br>“ HTML-TAGs zum einfügen einer Zeilenumbruch sagt einiges über die Anwendung selbst sowie dessen Entwicklungszyklus etc. einiges aus:

Ewige Jugend bedingt junges Blut – Mit der Jungblut-Spritze gegen das Jurassic-Park-Syndrom
Ältere Mitarbeiter, die die gesamte Geschichte unserer Produkte von Anfang an nicht nur miterlebt, sondern mitgestaltet haben, sind von unschätzbarem Wert für die Unternehmens- und Produktkultur sowie für die Bewahrung von Wissen und Erfahrung. Ihr Fehlen könnte Lücken hinterlassen, die hohe Kosten verursachen.
Um technologisch auf dem neuesten Stand zu bleiben und moderne Konzepte, Paradigmen und Innovationen nicht zu verpassen, ist es unabdingbar, regelmäßig neue junge Mitarbeiter einzustellen, insbesondere im Bereich der Informationstechnologie. Ein Paradebeispiel hierfür ist die dynamische Interaktion zwischen der Smartphone-Generation, die der Wählscheibentelefon-Generation bei der Nutzung von Apps und der Navigation durch Einstellungen hilft.
Im Jahr 2009 musste der neue CEO eines Unternehmens, für das ich damals tätig war, den Kunden erklären, warum die Spiele in 16-Bit-C geschrieben wurden und warum nach 8 Jahren Windows XP immer noch MS-DOS 7 als Betriebssystem erforderlich war. Obwohl das Unternehmen über mehr als 30 Softwareentwickler verfügte, begann es erst 2010, ein Versionsverwaltungssystem (Subversion) einzuführen. Zusätzlich wurde die Unternehmensstrategie hinsichtlich des Schutzes vor Code-Diebstahl und Reverse-Engineering nach 15 Jahren von einem absoluten Verbot von Code-Kommentaren („Security by Obscurity“) zu einer Kommentarpflicht für jede Funktion und jede Code-Datei umgestellt.
Diese Modernisierungen kamen jedoch zu spät, da bereits seit Jahren 13 externe Softwarehäuser Spiele für meinen damaligen Arbeitgeber programmiert hatten. Dies lag daran, dass das Unternehmen den Anforderungen und Bestellungen nicht gewachsen war, was zu enormen Kosten durch externe Dienstleister führte. Interessanterweise begann ich meine Tätigkeit dort im Jahr 2007, und obwohl ich bereits 2002 an der JKU Linz das Konzept des Unit-Testings gelernt hatte, hatte das Unternehmen nie davon Gebrauch gemacht, obwohl einige wenige Softwareprojekte teilweise in C++ und nach objektorientierten Prinzipien entwickelt wurden.
In solchen Situationen drückt das persische Sprichwort „نوشدارو بعد از مرگه سهراب“ („Medikation erst nach Sohrabs Tod“) treffend aus, dass manchmal die Rettung zu spät kommt.
Die scheinbaren Kosteneinsparungen, die entweder für ein einzelnes Produkt oder aufgrund vorübergehender wirtschaftlicher Schwierigkeiten getroffen werden, potenzieren sich nicht nur miteinander, sondern auch im Laufe der Zeit und erweisen sich stets als Bumerang. Wer Zweifel hegt, braucht sich nur die Geschichte von Unternehmen wie Kodak anzusehen, oder den aktuellen Fall von Boeing 737 Max zu betrachten, oder einfach zu recherchieren, welche Stundensätze für Fortran-, Cobol- oder Algol-Programmierer üblich sind (Ja! Es gibt tatsächlich Ämter wie IRS – das US-Finanzamt – und Firmen die immer noch Teilweise von solche Keilschrift-Programmiersprachen abhängig sind).
Fun Fact 1: Ein Mitarbeiter von Kodak hatte bereits im Jahr 1972 eine voll funktionsfähige Digitalkamera entwickelt und patentiert. Jedoch verweigerten die Manager von Kodak jegliche Anerkennung und untersagten dem Erfinder sogar, darüber zu sprechen. In den 1990er Jahren wurden sie schließlich von der Konkurrenz überholt, sodass ihre einst führende Marke in der Fotografie weniger als 1$ wert war. Die NASDAQ erwog sogar, sie aufgrund ihrer geringen Börsenbewertung aus dem Handel zu entfernen, was einem sogenannten „Penny Stock“ gleichkam.
Fun Fact 2: Boeing hat aufgrund des Konkurrenzdrucks durch Airbus immer wieder entschieden, die 737 lediglich anzupassen, anstatt sie von Grund auf zu erneuern. Doch wie man weiß, kann man mit alten Steinen kein neues Haus bauen – eine Erkenntnis, die sie spätestens kürzlich einholte. Der Ruf des Unternehmens ist beschädigt, die Marke ruiniert und das Vertrauen von Fluggesellschaften, Versicherungen und Passagieren ist dahin.
Buzzword-Bingo: Der überteuerte „Kaffeevollautomat mit künstlicher Intelligenz“ und die „natürliche Dummheit“
„Seit jeher verkaufen Geschäftsleute das, von dem Techniker schon immer geträumt haben.“
Anonym
Letztes Jahr, noch weit vor der Weihnachtszeit, bevor der Weihnachtsstress überhaupt erwähnt wurde, schickte mir mein Bruder einen Link zu einem „Kaffeevollautomaten mit künstlicher Intelligenz„.
„Ein Kaffeeautomat mit KI? Wozu?“ fragte ich mich, und ich begann gleichzeitig neugierig und aufmerksam, die Texte zu dieser überteuerten Kaffeemaschine zu lesen. Die Webseite eines Online-Shops pries den Hersteller für seine angeblichen Innovationen in der KI-Technologie und den neuen Schritten in der Digitalisierung… und da dachte ich nur „OMG! Wieder einmal hat die Marketingabteilung oder ein einfallsloser Manager zu Marketing-Gimmicks gegriffen und Schlangenöl als Neuheit verkauft…„
Ich war verärgert! Wie kann man nur seine Kunden für dumm verkaufen und sie derart belügen?
Statt mich nur zu ärgern, lenkte ich meinen Ärger um und entwickelte schnell eine einfache Webseite, die eine solche „KI-Kaffeemaschine“ simuliert. Dazu fügte ich eine Konsole mit kurzen Erläuterungen hinzu, was gemacht wird und warum – damit auch diejenigen, die nicht aus der IT-Welt stammen, es verstehen können.
Ich bin gespannt, wann die Taschenlampe mit Big Data, Blockchain, NFT und KI, die von einem Kernfusionsreaktor angetrieben wird, anstelle von Batterien/Akkus, angepriesen wird.
Wer wissen möchte, um welchen Hersteller es sich handelt, kann im Web nach „Kaffeemaschine mit künstlicher Intelligenz“ suchen. Im Simulator befindet sich auch ein Hinweis.
Wie drei Zeilen eines gewöhnlichen Algorithmus die Illusion von künstlicher Intelligenz bei überteuerten Geräten zerstören:
1. Zuerst werden zum Beispiel 6 verschiedene Kaffeesorten festgelegt. Für jede dieser Kaffeesorten wird ein Zähler für die jeweiligen 6 Tasten festgelegt. Es ist auch möglich, mehr Tasten und/oder Kaffeesorten festzulegen:
const coffeeList = [ { id: 0, name: "Americano", count: 0 }, { id: 1, name: "Mocca", count: 0 }, { id: 2, name: "Cappuccino", count: 0 }, { id: 3, name: "Latte", count: 0 }, { id: 4, name: "Türkisch", count: 0 }, { id: 5, name: "Frappé", count: 0 } ];
2. Danach wird für jede Kaffeesorte ein Knopf erstellt, der auch als Button oder Schaltfläche bezeichnet wird. Dem Mausklick-Mechanismus dieses Knopfes wird eine Methode zugewiesen, die den Zähler, auch als Counter bezeichnet, um eins erhöht und diesen Wert dann wieder in die Zähler-Variablen schreibt. Anschließend wird die Methode aufgerufen, die die angezeigten Knöpfe aktualisiert, um die Ansicht zu erneuern:
function increment(id) { // Finde das Kaffee-Objekt durch die ID (welche von der Taste geliefert wurde): const coffee = coffeeList.find((x) => x.id == id); // Zähler für den Kaffee/Button inkrementieren: coffee.count++; // Inkrementieren des Zählers und das Auffrischen der Anzeige: updateView(coffee); }
3. In der Methode „updateView(coffee)“ wird eine weitere Methode aufgerufen, um zu überprüfen, ob eine Aktualisierung der Anzeige (der Knöpfe/Schaltflächen) erforderlich ist oder nicht. Diese Aktualisierung erfolgt nur dann, wenn sie notwendig ist.
function hasToUpdateView() { for (i = 0; i < 6; i++) { if (i < 5) if (coffeeList[i].count < coffeeList[i + 1].count) { return true; } } // Nein! Keine Änderung ==> Auffrischen nicht notwendig. return false; }
4. Anschließend wird in der Methode „updateView(coffee)“ fortgefahren. Wenn die Antwort der Methode „hasToUpdateView()“ positiv ist, das bedeutet, wenn sie „true“ zurückgibt, dann werden die Knöpfe so lange nach links verschoben, bis der Wert des linken Knopfes höher oder gleich ist wie der Wert des ausgewählten Knopfes.
function updateView(coffee) { const btn = document.getElementById("btn" + coffee.id).innerText = coffee.name + "\n" + coffee.count + "x"; if (hasToUpdateView()) { sortByCount(); createButtons(); } }
Der vollständige Code hier nochmal zusammenhängend:
/******************************************************* * J̳ava U̳nique R̳uthless A̳utomat 0.8.15 * * Kaffevollautomat mit Künstlicher Intelligenz * * Copyright (C)2024 by Pedram GANJEH-HADIDI * *******************************************************/ var shell = "***************************************\n* J̳ava U̳nique R̳uthless A̳utomat 0.8.15 *\n***************************************\n"; const ruler = "---------------------------------------"; var clickCounter = 0; const coffeeList = [ { id: 0, name: "Americano", count: 0 }, { id: 1, name: "Mocca", count: 0 }, { id: 2, name: "Cappuccino", count: 0 }, { id: 3, name: "Latte", count: 0 }, { id: 4, name: "Türkisch", count: 0 }, { id: 5, name: "Frappé", count: 0 } ]; window.addEventListener('load', function () { const textArea = document.getElementById("txaShell"); textArea.innerHTML = shell; createButtons(); const w = window.screen.availWidth; const h = window.screen.availHeight; const e = document.getElementById("txaShell"); e.setAttribute("width", w); e.setAttribute("height", h / 2); }); window.addEventListener('resize', function () { createButtons(); }); function increment(id) { const coffee = coffeeList.find((x) => x.id == id); writeLog(`${++clickCounter}. T͟a͟s͟t͟e͟n͟d͟r͟u͟c͟k͟: Sie habe die Taste für\n${coffee.name} Kaffee geklickt. Nun wird die Anzahl dieser Taste hochgezählt!\n⟹ ${coffee.count} + 1 = ${++coffee.count}`); updateView(coffee); } function updateView(coffee) { const btn = document.getElementById("btn" + coffee.id).innerText = coffee.name + "\n" + coffee.count + "x"; if (hasToUpdateView()) { sortByCount(); createButtons(); } } function writeLog(str) { shell += str + "\n"; const textArea = document.getElementById("txaShell"); textArea.innerHTML = shell; textArea.scrollTop = textArea.scrollHeight; } function writeLine() { writeLog(ruler); } function hasToUpdateView() { for (i = 0; i < 6; i++) { if (i < 5) if (coffeeList[i].count < coffeeList[i + 1].count) { writeLog(`V͟e͟r͟g͟l͟e͟i͟c͟h͟e: ${coffeeList[i].name}: ${coffeeList[i].count} ≧ ${coffeeList[i + 1].name}: ${coffeeList[i + 1].count} ❌\nDa Links nicht größer oder gleich Rechts ist\n⟹ Tasten neu ordnen!`); writeLog(`T͟a͟s͟t͟e͟n͟p͟o͟s͟i͟t͟i͟o͟n͟e͟n͟ a͟k͟t͟u͟a͟l͟i͟s͟i͟e͟r͟e͟n͟: Die Taste\nfür ${coffeeList[i + 1].name} so oft wie notwendig nach Links verschieben...`); writeLine(); return true; } } writeLog("V͟e͟r͟g͟l͟e͟i͟c͟h͟e: Die Anzahl der Tastendrücke Links ist überall größer oder gleich der Taste Rechts davon ⭐\n⟹ Keine Änderung notwendig."); writeLine(); return false; } function sortByCount() { coffeeList.sort((a, b) => (a.count < b.count) ? 1 : -1); } function createButtons() { document.getElementById("coffeeButtons").innerHTML = addButtons(); } function addButtons() { let str = "<table><tr>"; for (i = 0; i < 3; i++) str += getButtonText(coffeeList[i]); str += "</tr>\n<tr>"; for (i = 3; i < 6; i++) str += getButtonText(coffeeList[i]); return str + "</tr></table>"; } function getButtonText(coffee) { return '<td><button id="btn' + coffee.id + '" type="button" class="coffeeButton" onclick="increment(' + coffee.id + ')" title="Klick here für ein Kaffee aus "">' + coffee.name + "<br>" + coffee.count + "x</button></td>"; }
Navigationsstrategien für den Erfolg: Von Autobahnstau zu Badestränden – Irrwege frühzeitig erkennen, bevor sie richtig kostspielig werden
Fehlentscheidungen und Entwicklungsfehler in einem Unternehmen oder Projekt lassen sich metaphorisch mit dem Verpassen einer Autobahnabfahrt oder dem falschen Abbiegen in einer unbekannten Großstadt vergleichen.
Frühzeitige Erkennung und konsequentes Handeln bei Fehlern, Fehlentscheidungen und Fehlentwicklungen in Konzepten, Produkten, Projekten oder sogar bei der Unternehmensexpansion führen zu geringeren Kosten und einem reduzierten Zeitaufwand für die erforderliche Korrektur.
Wenn man stur weiterfährt und dabei alle Warnsignale herunterspielt und ignoriert, sollte man sich nicht verwundern, wenn man mitten in der Nacht mit leerem Tank an einem abgelegenen Ort ohne zivilisatorische Einrichtungen und Mobilfunkempfang feststeckt.
Die unnötig verstrichene Fahrzeit, der verpasste Sonnenschein und die Kosten für den verschwendeten Kraftstoff hätten stattdessen an einem malerischen Badestrand genossen werden können, hätte man sich lediglich die Zeit genommen, kurz anzuhalten und einen Ortskundigen nach dem Weg zu fragen.
Es mag möglich sein, die exponentiell steigenden Kosten im Verhältnis zur vergangenen Zeit zu bewältigen, JEDOCH…
- Kann die Komplexität dieser Herausforderungen ebenso erfolgreich gemeistert werden?
- Müssen die Modernisierung des Unternehmens und die Innovation der Produkte aufgeschoben werden?
- Ruhen die Mitbewerber in Mitleid oder machen sie weiterhin Fortschritte?
Über 100 Downloads in Zwei Wochen: Meine .NET-Bibliothek „Revertible“
Ich bin begeistert, bekannt zu geben, dass meine .NET Standard 2.0 Bibliothek „Revertible„, die ich vor zwei Wochen auf NuGet veröffentlicht habe, bereits über 100 Mal heruntergeladen wurde. Diese Bibliothek erlaubt es, Properties, die mit dem RevertibleAttribute
gekennzeichnet sind, einfach auf ihren ursprünglichen Zustand/Wert zurückzusetzen.
Anfangs war ich unsicher, ob es einen Bedarf für eine solche Funktion gibt. Aber die Nachfrage in der .NET-Community hat meine Erwartungen übertroffen. Ich freue mich, dass mein Projekt Anklang findet und hilfreich für Entwickler ist.
Für weitere Informationen besuchen Sie das NuGet-Paket hier und das GitHub-Projekt hier.
Broken by Design: Wenn Software starr statt flexibel ist
Wenn es um Software (SOFT + ware) geht, liegt in ihrer Bezeichnung bereits eine grundlegende Erwartung: Sie sollte weich, verformbar, flexibel und anpassbar sein. Eine Software, die diese Eigenschaften vermissen lässt, gleicht eher einem starren Hardware-Produkt: Nicht einfach konfigurierbar und damit oft unbrauchbar, resultiert dies in kostspieligen Neuanschaffungen oder zeitaufwendigen Neuentwicklungen.
Als ich neulich zur Post ging, um eine Sendung abzuholen, fiel mir eine einfache, schnelle und praktische Lösung auf, die die Mitarbeiter der Post-Filiale gefunden hatten. Ich vermute, dass die (sogenannte) „Software“ des Info-Kiosks¹ entweder nicht lokal² konfigurierbar ist oder sich nicht schnell und einfach anpassen lässt. Andernfalls hätten die Mitarbeiter der Post-Filiale nicht zu Papier, Schere und Klebeband greifen müssen.
Höchstwahrscheinlich (meine persönliche Vermutung) wurde bereits in den frühen Phasen des Designs und der Entwicklung übersehen, das System konfigurierbar zu gestalten. Dies hätte es dem Personal vor Ort ermöglicht, Titel oder Text zu bearbeiten und Bilder auszutauschen.
1 Info-Kiosk: Auch bekannt als „digitales Kiosksystem“, „Touchscreen-Infostand“, „Self-Service-Terminal“, „interaktiver Informationsstand“ oder allgemein als Digital Signage bzw. Point-Of-Sale (kurz: POS) bezeichnet
2 Remote (von der Ferne über das Internet) durch dafür vorgesehene Personal zu konfigurieren bzw. aktualisieren
Broken by Design: der Mensch als Randnotiz
Designfehler: Wenn Technik daneben liegt

Betrachten wir folgende Kernfakten:
- Ungefähr 10% der Menschen sind Linkshänder, der Rest sind Rechtshänder
- Unsere Wahrnehmung ist von oben nach unten ausgerichtet, da sich unsere Augen im oberen Bereich des Kopfes befinden.
Ein prägnantes Beispiel hierfür ist die Platzierung des NFC-Sensors an einer linken Seitlich, einer Position, die weder intuitiv auffindbar noch sichtbar ist. Eine Frage, die man durchaus an den Produktmanager richten könnte:

Die Mitarbeiter einer Schreibwaren-Filiale griffen zu einer ebenso simplen wie kreativen Lösung, um diesen Designfehler zu beheben: Mit Karton, Schere, Buntstiften und Klebeband. Dieser einfallsreiche Ansatz brachte mich nicht nur zum Schmunzeln, sondern inspirierte mich auch zu diesem Beitrag.
Kunden allein gelassen: Das Verschwinden der RFID-Funktion
Im Jahr 2012 erwarb mein Vater, der nach einem Schlaganfall sein Augenlicht verlor, ein innovatives Gerät, das speziell für Blinde konzipiert wurde. Dieses kompakte und benutzerfreundliche Hilfsmittel bot Funktionen wie Zeitansage, Audiowiedergabe und Diktiergerät, die für Blinde im Alltag sehr hilfreich sind.

Eine besonders nützliche Funktion war die RFID-Lesefähigkeit. Mein Vater nutzte diese, um seine Kleidung, Audio-/Video-Medien und Dokumente zu organisieren. Er befestigte RFID-Tags an Gegenständen wie Hemden und Medienhüllen, scannte sie mit dem Gerät und besprach dazu passende Beschreibungen. Diese Sprachnotizen wurden dann mit den RFID-Tags verknüpft, sodass das Gerät die entsprechenden Aufnahmen abspielte, wenn ein bekannter RFID-Tag gescannt wurde.

Jedoch wurde diese essenzielle Funktion in dem 2023 erschienenen Nachfolgemodell entfernt, da es keinen RFID-Sensor mehr eingebaut wurde. Diese Änderung brachte meinen Vater in eine schwierige Lage. Die Jahre der investierten Mühe und Zeit in sein Organisationssystem schienen vergebens, da er nun auf Hilfe angewiesen ist, um seine Medien und Dokumente zu finden.
Die Begründung des Herstellers für das Entfernen der RFID-Funktion – mangelnde Beliebtheit und Nutzung durch die Kunden – ist für mich schwer nachvollziehbar und enttäuschend.
Die Ära des Elektroflops: Wenn Technologie ihre Versprechen nicht einlöst
Ich war zutiefst erstaunt, als mein sehbehinderter Vater mir sein neues Smartphone vorführte und seinen Unmut darüber äußerte.
Anfangs hegte ich Zweifel, doch dann nahm ich das eigens für Blinde entwickelte Smartphone mit physischer Tastatur und Google Assistant-Taste in die Hand und testete es selbst.
Szenario 1: Notfall
Stellen Sie sich vor, ich fahre meinen Vater im Winter bei Minustemperaturen, und wir erleiden einen Unfall. Das Auto liegt auf dem Dach, die Batteriesäure tritt aus, es brennt im Motorraum, Rauch liegt in der Luft, und Glasscherben bedecken den Boden. Mein Vater ruft nach mir, da er sich nicht befreien kann. Doch ich bleibe stumm.
Glücklicherweise hat er sein speziell für Blinde entwickeltes Smartphone dabei. Aber jetzt muss er 33-mal die Nach-Unten-Taste drücken, um die „SOS“-App auszuwählen und um Hilfe zu bitten. Dabei gibt es 30 andere Apps auf diesem Smartphone, die wichtiger sind als „SOS“.
In meinem Video können Sie sehen, dass ich als Sehender nicht darauf warten muss, dass die Stimme die Einträge vorliest, da ich visuell mehrere App-Namen gleichzeitig erkennen kann. Aber kann eine sehbehinderte Person in Panik- oder Stresssituationen wirklich auswendig wissen, wie oft sie auf welche Taste klicken muss?
Szenario 2: Jemanden anrufen
Gut, dass das Gerät eine „Google-Assistent-Taste“ hat! Mein Vater drückt diese Taste und sagt ins Mikrofon: „Pedram anrufen!“ Der Google-Assistent antwortet gehorsam: „Peter unter Kontakten nicht gefunden!“ Offenbar wird mein Vorname „Pedram“ einfach in „Peter“ umgewandelt, um dann in der Kontaktliste des Androids gesucht zu werden.
Szenario 3: Die Schaltfläche mit dem Mikrofonsymbol in der Suchleiste der Google-App verwenden (Google Speech-to-Text und automatische Suche)
Da mein blinder Vater den Bildschirm nicht sehen kann, muss er mit einer physischen Taste zunächst zu dieser Schaltfläche navigieren und sie dann mit einer anderen physischen „OK“-Taste aktivieren. Das Aktivieren funktioniert, aber die Software lässt die Taste wieder los, obwohl der Finger immer noch darauf bleibt. Speech-to-Text und die anschließende Suche funktionieren somit überhaupt nicht!
Szenario 4: Akkulaufzeit
Auch in diesem Punkt wurden keine Fortschritte erzielt, und die Akkulaufzeit hat sich halbiert bis gedrittelt! Mein Vater musste das vorherige Modell alle 5 bis 10 Tage aufladen, aber jetzt muss er es spätestens alle 3-5 Tage aufladen.
Szenario 5: Komplette Umkehrung der Menüführung
Jedes einzelne Bit und Byte wurde umgedreht. Der neue Irrgarten, auch bekannt als Menü, ist völlig anders. Alles, was über Jahre hinweg gelernt und gemerkt wurde, muss mein Vater vergessen, da es nun absolut nutzlos ist. Offenbar hat niemand eine Alternative zum neuen Menü in Betracht gezogen!
Andere Szenarien wie die merkwürdige Übersetzung und Aussprache englischer Texte, unerwartete Namen und beschreibungslose Pop-up-Dialoge aller Art sowie ständige Abstürze der „Text-to-Speech“-Software (die einen Neustart notwendig machen) lasse ich hier außer Acht.
Diesem Produkt hätten folgende Dinge nicht geschadet:
- Benutzerforschung
- Definition der Zielgruppe
- nutzerzentriertes Design (UCD)
- Entwicklung von Anwendungsfällen
Damit „Fehlanpassungen“ und die Unzufriedenheit der Benutzer bereits früh in der Entwicklung vermieden worden wären.
Unüberlegt deaktiviert: Wenn Entwickler das Potenzial von Fensterfunktionen übersehen
Nach der Installation des Windows 11 Treibers für meinen Multifunktionsdrucker präsentierte sich eine Übersichtstabelle, die mir Namen und Versionen von Firmware und weiteren Updates aufzeigte. Jedes Update konnte ich einzeln durch einen Klick auf „Aktualisieren“ herunterladen.

Schließlich, nachdem ich fast alle durchgearbeitet hatte, verblieben zwei Einträge, wobei die „Aktualisieren“-Schaltfläche deaktiviert blieb. Im Beschreibungsfeld der Tabelle waren lediglich die ersten Worte zweier Sätze sichtbar. Versuche, das Fenster zu maximieren oder die Größe anzupassen, schlugen fehl, sodass ich mich mit einem winzigen horizontalen Scrollbalken abmühen musste, um den gesamten Text zu enthüllen.

Da stelle ich mir die Frage, warum ich in zwei hochauflösende 23-Zoll-4K-Monitore investiert habe, wenn Softwareentwickler die Potenziale moderner Bildschirmtechnologie weiterhin ignorieren.
Warum ist das so?
Oftmals deaktivieren Entwickler unüberlegt nützliche Funktionen wie das Maximieren eines Fensters oder die Möglichkeit, dessen Größe anzupassen. Häufig liegt dies an Bequemlichkeit oder Unkenntnis, um beispielsweise den Einsatz eines Layout-Managers zu umgehen.
Softwarepflege: Lektionen aus einem Hotel der 60er Jahre in Linz
Während meines Aufenthalts in Linz für die WikiCon 2023, checkte ich in einem charmanten Hotel ein, das in den 50er oder 60er Jahren erbaut wurde. Ein kleines, aber auffälliges Detail zog sofort meine Aufmerksamkeit auf sich: der Legeplatz für Koffer. Er war auffällig breit, eindeutig konzipiert für die Koffermaße jener Zeit. Mein moderner Trolli-Koffer, schmaler und höher als sein historisches Gegenstück, wirkte wie ein Fremdkörper.
Inmitten der Vorbereitungen und Diskussionen der WikiCon fand ich mich über dieses scheinbar unbedeutende Detail im Hotelzimmer nachdenkend. Es wurde mir ein Symbol für eine größere Idee, die weit über die physische Welt hinaus in die digitale Domäne der Softwareentwicklung reicht. So wie dieser Kofferplatz muss auch Software im Laufe der Zeit angepasst werden – nicht nur, weil sich die Technologie verändert, sondern weil sich auch die Kultur, die Bedürfnisse und die Erwartungen der Nutzer weiterentwickeln.
Software, die einmal innovativ war, kann schnell veralten, wenn sie nicht mit den Veränderungen Schritt hält. Die besten Softwarelösungen sind jene, die sich kontinuierlich anpassen, wachsen und mit den Zeiten entwickeln.
Die Lektion, die ich aus meinem Hotelzimmer in Linz mitnahm, ist klar: Ob im Hotelbau oder in der Softwareentwicklung, Anpassungsfähigkeit ist nicht nur wünschenswert, sondern essentiell. Nur so können wir sicherstellen, dass unsere Produkte und Dienstleistungen im Wandel der Zeit bestehen bleiben.

Weitere verwandte Artikel über Design (UI) und User Experience (UX)…
Wenn dein Code „Blinde Kuh“ spielt: Eine Reise durch das Labyrinth des digitalen Spaghetti-Chaos!
Ich betrat zum ersten Mal ein mir unbekanntes Haus und war auf der verzweifelten Suche nach einem Kugelschreiber und einem Blatt Papier.
„Das Arbeitszimmer!“, dachte ich, „Ein Schriftsteller wohnt hier, dort wird sicherlich ein Schreibutensil zu finden sein.“
Die Türschilder leiteten mich durch die Räume, und ich machte mich auf den Weg zum beschrifteten „Arbeitszimmer“. Dort erwartete ich den klassischen Anblick eines Schreibtisches, Buchregale und ein paar Notizbücher. Doch was mich hinter der Tür erwartete, war der duftende Innenraum eines gut bestückten Kühlschranks, umgeben von Kochutensilien. Verblüfft verließ ich das vermeintliche Arbeitszimmer und folgte meiner Intuition zur Tür mit dem Schild „Küche“. Doch anstelle eines Herds fand ich ein farbenfrohes Kinderzimmer vor.
Nach einigen weiteren, eher komischen Zimmern und einer kleinen, skurrilen Reise durch das Haus, stolperte ich schließlich im „Gästezimmer“ über den lange gesuchten Schreibtisch. Mit einem erleichterten „Endlich!“ auf den Lippen schreckte ich hoch. Es war nur ein Albtraum gewesen, aber wenigstens mit einem glücklichen Ausgang.
Und die Moral der Geschichte lautet: Die Bezeichnung einer Klasse in der Programmierung sollte präzise widerspiegeln, was sich darin befindet. Ein „Converter“ ist dafür da, zu konvertieren und nicht zu formatieren. Ein „Formatter“ sollte keine Serialisierungsmethoden anbieten, genauso wie ein „DatabaseManager“ sich nicht um die Serialisierung von Daten in XML oder JSON kümmern sollte.
Die Analogien in dieser Kurzgeschichte, in der Reihenfolge ihres Auftretens:
- Unbekanntes Haus: fremder Code
- Schriftsteller: Datei- oder Klassen-Name
- Kugelschreiber und Blatt Papier: spezifische, aber festgelegte Methode(n) mit klar definierten Funktionen
- Türschilder: Namensräume, Klassen-, Methoden- und Property-Namen
- Albtraum: Albtraum für den Code-Autor, seine Kollegen, die Nachwelt, die Firma und die Kunden
- Nachwelt: alle, die nach dem Ausscheiden des Autors aus der Firma in irgendeiner Weise mit dem Code in Berührung kommen.
Wir sind kein Autowerk!
Untertitel 1: Über die Bedeutung, sich direkt in Produktionsstätten aufzuhalten, die Arbeitenden zu konsultieren und keine voreiligen Investitionen in „Optimierungen“ zu tätigen.
Untertitel 2: Warum allein die Analyse von Excel-Tabellen nicht genügt.
In jüngerer Zeit traf ich einen alten Bekannten, den ich während meines Studiums bei einem renommierten Bahnbauanlagen-Hersteller kennengelernt hatte. Er war damals mein Mentor und erzählte mir von Zeiten des Wandels in diesem Unternehmen.
Nachdem der Firmengründer in den Ruhestand trat, waren seine Nachfolger überzeugt, Modernisierungen seien nötig. Sie beauftragten teure Beratungsunternehmen, die nach langer Analyse die bisherige Produktion zweigeteilt haben. Früher wurden Lokomotiven in einer einzigen Halle hergestellt, wobei jeder Schritt reibungslos ineinandergreifend erfolgte. Doch die Consultants teilten diesen Prozess auf zwei Hallen auf, sodass nun halbfertige Lokomotiven durch das belebte Stadtzentrum transportiert werden mussten – eine logistische und finanzielle Herausforderung.
Wertvolle, erfahrene Mitarbeiter, die Bedenken äußerten, wurden entlassen. Die verbleibenden Mitarbeiter wurden zu penibler Ordnung ihrer Werkzeuge angehalten, ähnlich wie in Autowerken. Doch keine zwei Projekte waren je gleich; die starre Ordnung behinderte oft mehr, als sie half.
Nach Jahren der „Optimierung“, erheblichen Kosten und verlangsamter Produktion kehrten die Inhaber schließlich zum bewährten System zurück.
Interessant: Nach Abschluss der Umstrukturierung blieben Risse und Asphaltschäden in der Halle unangetastet – sie wurden schlicht übersehen. Ein Tag praktischer Arbeit in der Halle hätte den Beratern vermutlich mehr gezeigt als monatelange Analysen.
Die Mitarbeiterproteste: „Wir sind kein Automobilhersteller! Wir haben keine Fließbänder!“ wurden ignoriert. Daten und Diagramme auf Bildschirmen sind nützlich, doch sie ersetzen nicht die reale Erfahrung und das Fachwissen derer, die tagtäglich in der Produktion stehen.
Nachdem das teure Unterfangen von „Modernisierung“ und „Optimierung“ durch externe Berater beendet wurde und vieles wieder zum Alten zurückgekehrt war, waren die Mitarbeiter jedoch verändert. Durch den Wegfall von Gewinnbeteiligungen und anderen Bonuszahlungen waren sie nun unzufrieden.
Das Küchenmesser als Analogie für UI und UX
Ein gut gestaltetes Layout und eine effektive grafische Benutzeroberfläche (GUI) für eine Anwendung können verglichen werden mit einem Küchenmesser inklusiver Griff. Dadurch wird es:
- intuitiv: Nutzer wissen sofort, wie es zu verwenden ist (Worauf soll ich klicken?…).
- sicher: Es minimiert Verletzungsrisiken (Falsche/Verkehrte Dateneingabe, doppelte Einträge, unabsichtliches Löschen von Daten,…).
- handlich: Es liegt gut in der Hand (Es macht Spaß damit zu arbeiten…).
- effizient: Man kann präzise und schnell schneiden (Was muss ich als Nächstes anklicken?…).
- stabil: Es rutscht nicht aus der Hand (Ohje! Muss ich alles nochmal eingeben? Warum funktioniert es diesmal nicht?…).
- klar: Es bedarf keiner langen Erklärung (die Dokumentation nicht wirklich notwendig, oder wenn es wegen ISO Standards udg. es sein muss, kann auf ein Screenshot und/oder die Erwähnung plus kurzer Tooltip-Text reduziert werden).
Selbst die fortschrittlichste Anwendung verliert an Wert, wenn sie nicht einfach und intuitiv zu bedienen ist, da sie dann selten und ungern genutzt wird.
Weitere verwandte Artikel über Design (UI) und User Experience (UX)…
UI-Agoraphobie (UX)
Obwohl viele Softwareentwickler:innen nicht an Agoraphobie leiden, zeigen sie dennoch eine Scheu vor leeren Flächen in ihren Anwendungsfenstern. Sie neigen dazu, jeden Dialog und jedes Fenster lückenlos mit Schaltflächen, Optionsfeldern und Textfeldern auszufüllen. Zwar kann dadurch möglicherweise ein zusätzliches Fenster oder ein weiterer Dialog eingespart werden, doch zwingt dies den Kundenservice dazu, wiederholt ähnliche Fragen von Benutzern zu beantworten.
Ein überfrachtetes Fenster oder Dialog mit zahlreichen UI-Elementen kann bei den Benutzer:innen das Gefühl hervorrufen, einem Hai im dichten Fischschwarm gleichzukommen: Orientierungslosigkeit dominiert.
Wenn Sie Ihre Software vorstellen und die Reaktion darauf ein verständnisloses Stirnrunzeln ist – ein stilles „Oh Gott!“ oder im österreichischen Dialekt „Na servas!“ oder „Bist du narrisch!“ – dann haben Sie vermutlich zu viele Bedienelemente in den verfügbaren Raum gepresst.
Seien Sie mutig und gestalten Sie die Benutzeroberfläche (GUI) klar und übersichtlich. Verhindern Sie, dass Nutzer:innen bereits beim ersten Anblick resignieren, unsicher sind und nicht wissen, wo und wie sie beginnen sollen.
Farbkontraste & User Experience (UX)
Farbkontraste helfen, Dinge leichter und schneller zu erkennen.
Falls die Farbwahl nicht optimal ist, fällt es den Benutzer:innen/Betrachter:innen schwer, Details zu erkennen, wodurch sie Elemente übersehen könnten und schneller ermüden. Dies liegt daran, dass die Augenmuskulatur stärker beansprucht wird. Im nachstehenden Beispiel ist das Optionsfeld kaum wahrnehmbar, da das Kästchen erst nach dem Aktivieren sichtbar wird.


Die Sprechblase/Der Tooltip
Neulich müsste ich etwas scannen, und leider müsste ich die Einstellungen des Scanners anpassen. Dabei fiel mir die Schaltfläche „Standard“ auf. Ich positionierte den Mauszeiger darauf, in der Hoffnung der Text in der Sprechblase wurde dessen Funktion etwas genauer erklären …

Leider wurde keine Sprechblase eingeblendet, und ich zögerte, darauf zu klicken, weil ich befürchtete, alle Einstellungen erneut vornehmen zu müssen.
Die Sprechblase stellt die direkteste und einfachste Verbindung zwischen dem Nutzer und der Dokumentation dar.
Ein informativer Tooltip spart dem Nutzer den Griff zur gedruckten oder digitalen Dokumentation und die anschließende Suche nach einer Erklärung.
Ist die Information über die Funktion einer Benutzeroberfläche (UI) treffend formuliert, erspart sie dem Nutzer:
- Das Durchsuchen von Benutzerhandbüchern oder PDF-Dateien,
- Die gezielte Suche nach der Erklärung der betreffenden UI-Funktion (Auf welcher Seite? In welchem Kapitel?),
- Den Verlust von Konzentration und den Abbruch seines ursprünglichen Vorhabens.
Oft sind sich Nutzer nicht sicher, und eine kurze und klare Tooltip-Information kann dem Nutzer das nötige Vertrauen geben, seine Aktion fortzusetzen, oder ihn davon abhalten, einen möglichen Fehler zu begehen.
Der Tooltip sollte möglichst kurz sein, und nicht versuchen die Dokumentation zu ersetzen.
Welches VPN?
Folgende Fragen sollten vor dem Abschluss eines VPN-Abo-Vertrages gestellt werden:
- Welches Land ist für die Gerichtsbarkeit zuständig?
- NSA-Freunde? (5 Eyes, 14 Eyes,…?) „Schurken-Staaten“ die bei kleinste Demos, das Internet abdrehen?
- NSA-Freunde? (5 Eyes, 14 Eyes,…?) „Schurken-Staaten“ die bei kleinste Demos, das Internet abdrehen?
- Werden Kunden-Daten (Name, IBAN, Kreditkarten-Nr., E-Mail-Adresse, IP,…) gespeichert?
- Wenn Ja: was wird alles gespeichert?
- Ist es möglich anonym zu bezahlen?
- Werden Verbindungs-Daten (DNS, IP, MAC, Zeitstempel, URL,…) gespeichert?
- Wenn ja: was wird gespeichert?
- Wie lange wird gespeichert?
- Sind die Server sogenannte RAM–Only bzw. Read-Only oder echte Hardware-Server?
(RAM-/Read-Only: Es existieren keine Festplatten bzw. es werden Nichts auf die Festplatten gespeichert. Somit wird eine Daten-/Log-Analyse extrem erschwert, vor allem nachdem Abschalten/Herunterfahren/Neustart) - Mit welche Methode und wie Stark (Bit-Anzahl) erfolgt die Verschlüsselung?
- Wird die VPN über Router unterstützt? (1x konfigurieren für alle Geräte Zuhause)
- Welche Betriebssysteme werden unterstützt? (Falls ein Gerät mit z.B. Linux betrieben wird)
- Sind die Anzahl der gleichzeitige Verbindungen beschränkt?
- Wenn ja: reichen diese Aus?
- Ist der max. Datendurchsatz (Upload-/Download-Geschw.) begrenzt/gedrosselt?
- Werden Streaming-Dienste wie Netflix unterstützt?
- Werden private Torrent-Verbindungen unterstützt?
Hier eine Webseite zum Vergleichen von VPN-Anbieter (mit Vorsicht zu genießen!): vpnranks.com
Wenn der Code-Schreiber keine Ahnung von Compiler hat, sich aber auf ihn und seine Optimierungsalgorithmen verlässt …
Es gibt Code-Schreiberlinge, die glauben tatsächlich, dass „der Compiler eh alles optimiert„.
Andere glauben sogar, dass der Compiler eine gewisse Intelligenz besitzt.
Dann gibt es noch die Code-Schreiberlinge, die glauben, dass es gut ist, wenn sie jede Methode mit einem Try-Catch-Block zu versehen. Nachdem Motto „Bringt nichts, schadet nichts“ und/oder „Doppelt hält besser„.
Schauen wir uns das ganze Mal genauer an.
Wieder mal ein Stück Code aus freie Wildbahn (Industrie):
// Listing 1 (ugly code) void Main() { Console.WriteLine(GetSomething(0)); } public double GetSomething(int value) { try { return 0; } catch(Exception ex) { return 0; } }
Man stelle sich nun vor (das wird mir niemand glauben) es gäbe ein SW-System mit hundert und mehr solche Methoden wie „GetSomething(int)
„.
Der folgende Code tut exakt das Gleiche, nur viel CPU und Speicher freundlicher, überschaubarer, verständlicher und einfacher zu lesen:
// Listing 2 (better code) public const double DBL_CONST = 0.0; void Main() { Console.WriteLine(0); }
Und nun schauen wir uns mal an, was der Compiler:
- Optimiert, und es dann
- in „Intermediate Language“ (IL) Befehle für CLR übersetzt, und anschließen für den echten CPU (Hardware)
- ins Assembler übersetzt
Fangen wir mal mit Listing 1 (ugly code) an:

Man stelle sich vor der Code oben wird in einer Schleife immer wieder aufgerufen …
Und nun schauen wir uns Listing 2 (better code) an:

Wie man sieht, wird der CPU bei Listing 1 (ugly code) unnötig beschäftigt. Man könnte meinen, es handle sich um eine „Beschäftigungstherapie“ für den CPU: „Das es eahm jo ned langweilig wird!„.
Wegen solche Code-Schreiberlinge, benötigen wir immer stärkere CPUs, noch mehr Cores pro Sockel, und immer mehr RAM. Von der Energieverschwendung und dem CO₂ Bilanz ganz zu schweigen.
Clean Code: Trennen von Daten aus Algorithmen
Es ist immer eine gute Idee, Daten von Algorithmen zu trennen, um mehr Abstraktion zu schaffen. Dadurch erhält man viele Vorteile, die wir nach ein kurzes, praktisches Beispiel aus dem Alltag sehen werden.
Zuerst schauen wir uns mal, exemplarisch, eine Methode zum Initialisieren einer Datentabelle, namens „settings“ an:
public void InitSettingsValues() { _DataSet.Tables["settings"].Rows[0]["column0"] = false; _DataSet.Tables["settings"].Rows[0]["column1"] = true; _DataSet.Tables["settings"].Rows[0]["column2"] = null; _DataSet.Tables["settings"].Rows[0]["column3"] = 47.11; _DataSet.Tables["settings"].Rows[0]["column4"] = "Hello World!"; _DataSet.Tables["settings"].Rows[0]["column5"] = new DateTime(2001, 9, 11); _DataSet.Tables["settings"].Rows[0]["column6"] = 6; _DataSet.Tables["settings"].Rows[0]["column7"] = 7; _DataSet.Tables["settings"].Rows[0]["column8"] = 8; _DataSet.Tables["settings"].Rows[0]["column9"] = 9; _DataSet.Tables["settings"].Rows[0]["column10"] = 10; //... usw. _DataSet.Tables["settings"].Rows[0]["column99"] = 99; _DataSet.Tables["settings"].Rows[0]["column100"] = 100; }
Dieser Code ist alles andere als optimal:
- Ist weder leicht lesbar, noch überschaubar
- Enthält viele Wiederholungen (DRY: Don’t Repeat Yourself)
- Ist nicht abstrakt, sondern explizit („settings“ und 0 als Zeilennummer)
- Man kann es nicht wiederverwenden (für die Tabelle „nichtSettings“ muss eigene Methode geschrieben werden)
- Man kann es nicht leicht pflegen, erweitern, oder mehrere Varianten davon, nebeneinander erstellen/verwenden/aufrufen (siehe den besseren Code unten):
- Was tun wir, wenn bei nächstem Release, per Konfiguration, entweder die eine oder andere Methode aufgerufen werden soll? (z.B. für spezielle Kunden, oder Rollback der Version aufgrund gravierende Sicherheitsmangel udg.)
- Was tun wir, wenn es N (N >= 2) Daten-Varianten gibt (der eine hat X Spalten mehr/weniger)?
- Man kann nicht wirklich von „Algorithmus“ sprechen
- Der Code für CPU und RAM wird unnötig aufgeblasen, und lässt sich schlecht optimieren (siehe IL und Assembler Listings für Intel x64 zum Vergleichen am Ende des Beitrags)
Und nun trennen wir die Daten von Algorithmus:
// Daten. private (string ColumnName, object Value)[] _SettingsInitValues = { ("column0", false), ("column1", true), ("column2", null), ("column3", 47.11), ("column4", "Hello World!"), ("column5", new DateTime(2001, 9, 11)), ("column6", 6), ("column7", 7), ("column8", 8), ("column9", 9), ("column10", 10), //... usw. ("column99", 99), ("column100", 100) }; // Algorithmus. public void SetTableValues(DataSet pDataSet, string pTableName, int pRowIndex, IEnumerable<(string ColumnName, object Value)> pColumnNameValueTuples) { foreach (var tuple in pColumnNameValueTuples) { pDataSet.Tables[pTableName].Rows[pRowIndex][tuple.ColumnName] = tuple.Value; } }
Die Methode besteht nun aus die Signatur plus 2 Zeilen, und bietet folgende Qualitätsmerkmale:
- Leichter lesbar: 2 Zeilen
- Überschaubar: 2 Zeilen
- Verständlicher/Selbsterklärend: 2 Zeilen
- Abstrakter: kann auch für andere Tabellen des „_DataSet“ oder sogar andere DataSets verwendet werden
- Leichter zu pflegen
- Leichter zu Debuggen
- Leichter zu erweitern
- Grundsätzlich: leichter zu ändern
- Man kann weitere Daten-Varianten nebeneinander einsetzen
Mit diesem Code, brauchen wir uns keine Sorgen machen, denn:
- Es ist wiederverwendbar (für andere DataSets, Tabellen, Zeilen-Index)
- Falls es für Kunde X oder Version Y andere Daten-Varianten genommen werden müssen: kein Problem
- Falls es gleichzeitig unterschiedliche Daten-Varianten für unterschiedliche SW-Versionen genommen werden müssen: kein Problem!
- Das Gleiche für die Nutzung unterschiedliche Daten-Varianten per Konfiguration: kein Problem!
- Sollte aus welchem Grund auch immer, ein Rollback der SW-Version unternommen werden muss: kein Problem!
- Sollte Microsoft in der nächste .NET Framework, Core, NET 9 usw. irgendwas an DataSet, deren Tabelle, Zeile oder Spalten ändern: kein Problem! Wir müssen nur eine einzige Zeile ändern
Wie man hier sieht, kann man für 10 verschiedene Versionen/Kunden, die Settings-Tabelle per Konfiguration mit 10 unterschiedliche Daten-Werte initialisieren, OHNE unsere 2 Zeilen Code ändern zu müssen:
private (string ColumnName, object Value)[] _Vers_1_0 = ("column0", 0), ("column1", "dw4mrkzy") /*... usw. */}; private (string ColumnName, object Value)[] _Vers_1_1 = ("column0", 2), ("column1", "LR0_uClc") /*... usw. */}; private (string ColumnName, object Value)[] _Vers_1_2 = ("column0", 0), ("column1", "SR1Vj5ts") /*... usw. */}; private (string ColumnName, object Value)[] _Vers_1_3 = ("column0", 2), ("column1", "hiKlLG55") /*... usw. */}; private (string ColumnName, object Value)[] _Vers_1_4 = ("column0", 8), ("column1", "s2Z4MkKZ") /*... usw. */}; private (string ColumnName, object Value)[] _Vers_1_5 = ("column0", 0), ("column1", "qXZM0x4h") /*... usw. */}; private (string ColumnName, object Value)[] _Vers_1_6 = ("column0", 0), ("column1", "UQryY_SV") /*... usw. */}; private (string ColumnName, object Value)[] _Vers_1_7 = ("column0", 0), ("column1", "CB80QEcy") /*... usw. */}; private (string ColumnName, object Value)[] _Vers_1_8 = ("column0", 8), ("column1", "S59sdhFc") /*... usw. */}; private (string ColumnName, object Value)[] _Vers_1_9 = ("column0", 7), ("column1", "FSgCWXii") /*... usw. */}; private (string ColumnName, object Value)[] _Vers_1_10 = ("column0", 3), ("column1", "hdNvQ8Wt") /*... usw. */};
Die Unterschiede in IL:
Zuerst der IL Code von „SetTableValues(…)“ (optimaler Code):
Die letzte Zeilennummer (in Hex) ist 0x0057 = 87 dez.
IL_0000 nop IL_0001 nop IL_0002 ldarg.3 IL_0003 callvirt IEnumerable <ValueTuple<String,Object>>.GetEnumerator () IL_0008 stloc.0 IL_0009 br.s IL_0042 IL_000B ldloc.0 IL_000C callvirt IEnumerator <ValueTuple<String,Object>>.get_Current () IL_0011 stloc.1 // tuple IL_0012 nop IL_0013 ldarg.0 IL_0014 ldfld UserQuery._DataSet IL_0019 callvirt DataSet.get_Tables () IL_001E ldarg.1 IL_001F callvirt DataTableCollection.get_Item (String) IL_0024 callvirt DataTable.get_Rows () IL_0029 ldarg.2 IL_002A callvirt DataRowCollection.get_Item (Int32) IL_002F ldloc.1 // tuple IL_0030 ldfld ValueTuple <String, Object>.Item1 IL_0035 ldloc.1 // tuple IL_0036 ldfld ValueTuple <String, Object>.Item2 IL_003B callvirt DataRow.set_Item (String, Object) IL_0040 nop IL_0041 nop IL_0042 ldloc.0 IL_0043 callvirt IEnumerator.MoveNext () IL_0048 brtrue.s IL_000B IL_004A leave.s IL_0057 IL_004C ldloc.0 IL_004D brfalse.s IL_0056 IL_004F ldloc.0 IL_0050 callvirt IDisposable.Dispose () IL_0055 nop IL_0056 endfinally IL_0057 ret
Der IL Code von „InitSettingsValues()“ (nicht optimaler Code):
Die letzte Zeilennummer (in Hex) lautet: 0x0291 = 657 dez.
IL_0000 nop IL_0001 ldarg.0 IL_0002 ldfld UserQuery._DataSet IL_0007 callvirt DataSet.get_Tables () IL_000C ldstr "settings" IL_0011 callvirt DataTableCollection.get_Item (String) IL_0016 callvirt DataTable.get_Rows () IL_001B ldc.i4.0 IL_001C callvirt DataRowCollection.get_Item (Int32) IL_0021 ldstr "column0" IL_0026 ldc.i4.0 IL_0027 box Boolean IL_002C callvirt DataRow.set_Item (String, Object) IL_0031 nop IL_0032 ldarg.0 IL_0033 ldfld UserQuery._DataSet IL_0038 callvirt DataSet.get_Tables () IL_003D ldstr "settings" IL_0042 callvirt DataTableCollection.get_Item (String) IL_0047 callvirt DataTable.get_Rows () IL_004C ldc.i4.0 IL_004D callvirt DataRowCollection.get_Item (Int32) IL_0052 ldstr "column1" IL_0057 ldc.i4.1 IL_0058 box Boolean IL_005D callvirt DataRow.set_Item (String, Object) IL_0062 nop IL_0063 ldarg.0 IL_0064 ldfld UserQuery._DataSet IL_0069 callvirt DataSet.get_Tables () IL_006E ldstr "settings" IL_0073 callvirt DataTableCollection.get_Item (String) IL_0078 callvirt DataTable.get_Rows () IL_007D ldc.i4.0 IL_007E callvirt DataRowCollection.get_Item (Int32) IL_0083 ldstr "column2" IL_0088 ldnull IL_0089 callvirt DataRow.set_Item (String, Object) IL_008E nop IL_008F ldarg.0 IL_0090 ldfld UserQuery._DataSet IL_0095 callvirt DataSet.get_Tables () IL_009A ldstr "settings" IL_009F callvirt DataTableCollection.get_Item (String) IL_00A4 callvirt DataTable.get_Rows () IL_00A9 ldc.i4.0 IL_00AA callvirt DataRowCollection.get_Item (Int32) IL_00AF ldstr "column3" IL_00B4 ldc.r8 AE 47 E1 7A 14 8E 47 40 // 47,11 IL_00BD box Double IL_00C2 callvirt DataRow.set_Item (String, Object) IL_00C7 nop IL_00C8 ldarg.0 IL_00C9 ldfld UserQuery._DataSet IL_00CE callvirt DataSet.get_Tables () IL_00D3 ldstr "settings" IL_00D8 callvirt DataTableCollection.get_Item (String) IL_00DD callvirt DataTable.get_Rows () IL_00E2 ldc.i4.0 IL_00E3 callvirt DataRowCollection.get_Item (Int32) IL_00E8 ldstr "column4" IL_00ED ldstr "Hello World!" IL_00F2 callvirt DataRow.set_Item (String, Object) IL_00F7 nop IL_00F8 ldarg.0 IL_00F9 ldfld UserQuery._DataSet IL_00FE callvirt DataSet.get_Tables () IL_0103 ldstr "settings" IL_0108 callvirt DataTableCollection.get_Item (String) IL_010D callvirt DataTable.get_Rows () IL_0112 ldc.i4.0 IL_0113 callvirt DataRowCollection.get_Item (Int32) IL_0118 ldstr "column5" IL_011D ldc.i4 D1 07 00 00 // 2001 IL_0122 ldc.i4.s 09 // 9 IL_0124 ldc.i4.s 0B // 11 IL_0126 newobj DateTime..ctor IL_012B box DateTime IL_0130 callvirt DataRow.set_Item (String, Object) IL_0135 nop IL_0136 ldarg.0 IL_0137 ldfld UserQuery._DataSet IL_013C callvirt DataSet.get_Tables () IL_0141 ldstr "settings" IL_0146 callvirt DataTableCollection.get_Item (String) IL_014B callvirt DataTable.get_Rows () IL_0150 ldc.i4.0 IL_0151 callvirt DataRowCollection.get_Item (Int32) IL_0156 ldstr "column6" IL_015B ldc.i4.6 IL_015C box Int32 IL_0161 callvirt DataRow.set_Item (String, Object) IL_0166 nop IL_0167 ldarg.0 IL_0168 ldfld UserQuery._DataSet IL_016D callvirt DataSet.get_Tables () IL_0172 ldstr "settings" IL_0177 callvirt DataTableCollection.get_Item (String) IL_017C callvirt DataTable.get_Rows () IL_0181 ldc.i4.0 IL_0182 callvirt DataRowCollection.get_Item (Int32) IL_0187 ldstr "column7" IL_018C ldc.i4.7 IL_018D box Int32 IL_0192 callvirt DataRow.set_Item (String, Object) IL_0197 nop IL_0198 ldarg.0 IL_0199 ldfld UserQuery._DataSet IL_019E callvirt DataSet.get_Tables () IL_01A3 ldstr "settings" IL_01A8 callvirt DataTableCollection.get_Item (String) IL_01AD callvirt DataTable.get_Rows () IL_01B2 ldc.i4.0 IL_01B3 callvirt DataRowCollection.get_Item (Int32) IL_01B8 ldstr "column8" IL_01BD ldc.i4.8 IL_01BE box Int32 IL_01C3 callvirt DataRow.set_Item (String, Object) IL_01C8 nop IL_01C9 ldarg.0 IL_01CA ldfld UserQuery._DataSet IL_01CF callvirt DataSet.get_Tables () IL_01D4 ldstr "settings" IL_01D9 callvirt DataTableCollection.get_Item (String) IL_01DE callvirt DataTable.get_Rows () IL_01E3 ldc.i4.0 IL_01E4 callvirt DataRowCollection.get_Item (Int32) IL_01E9 ldstr "column9" IL_01EE ldc.i4.s 09 // 9 IL_01F0 box Int32 IL_01F5 callvirt DataRow.set_Item (String, Object) IL_01FA nop IL_01FB ldarg.0 IL_01FC ldfld UserQuery._DataSet IL_0201 callvirt DataSet.get_Tables () IL_0206 ldstr "settings" IL_020B callvirt DataTableCollection.get_Item (String) IL_0210 callvirt DataTable.get_Rows () IL_0215 ldc.i4.0 IL_0216 callvirt DataRowCollection.get_Item (Int32) IL_021B ldstr "column10" IL_0220 ldc.i4.s 0A // 10 IL_0222 box Int32 IL_0227 callvirt DataRow.set_Item (String, Object) IL_022C nop IL_022D ldarg.0 IL_022E ldfld UserQuery._DataSet IL_0233 callvirt DataSet.get_Tables () IL_0238 ldstr "settings" IL_023D callvirt DataTableCollection.get_Item (String) IL_0242 callvirt DataTable.get_Rows () IL_0247 ldc.i4.0 IL_0248 callvirt DataRowCollection.get_Item (Int32) IL_024D ldstr "column99" IL_0252 ldc.i4.s 63 // 99 IL_0254 box Int32 IL_0259 callvirt DataRow.set_Item (String, Object) IL_025E nop IL_025F ldarg.0 IL_0260 ldfld UserQuery._DataSet IL_0265 callvirt DataSet.get_Tables () IL_026A ldstr "settings" IL_026F callvirt DataTableCollection.get_Item (String) IL_0274 callvirt DataTable.get_Rows () IL_0279 ldc.i4.0 IL_027A callvirt DataRowCollection.get_Item (Int32) IL_027F ldstr "column100" IL_0284 ldc.i4.s 64 // 100 IL_0286 box Int32 IL_028B callvirt DataRow.set_Item (String, Object) IL_0290 nop IL_0291 ret
Die Intel x64 Assembler Unterschiede:
Zuerst der Assembler Code von „SetTableValues(…)“ (optimaler Code):
Die letzte Zeilennummer (in Hex) ist 0x017d = 575 dez.
L0000 push rbp L0001 sub rsp, 0x80 L0008 lea rbp, [rsp+0x80] L0010 xor eax, eax L0012 mov [rbp-0x58], rax L0016 xorps xmm4, xmm4 L0019 movaps [rbp-0x50], xmm4 L001d movaps [rbp-0x40], xmm4 L0021 movaps [rbp-0x30], xmm4 L0025 movaps [rbp-0x20], xmm4 L0029 movaps [rbp-0x10], xmm4 L002d mov [rbp-0x60], rsp L0031 mov [rbp+0x10], rcx L0035 mov [rbp+0x18], rdx L0039 mov [rbp+0x20], r8d L003d mov [rbp+0x28], r9 L0041 mov rax, 0x7ffd31adc320 L004b cmp dword ptr [rax], 0 L004e je short L0055 L0050 call 0x00007ffd906485f0 L0055 nop L0056 nop L0057 mov rcx, [rbp+0x28] L005b mov r11, 0x7ffd31ad7020 L0065 mov rax, 0x7ffd31ad7020 L006f call qword ptr [rax] L0071 mov [rbp-0x20], rax L0075 mov rcx, [rbp-0x20] L0079 mov [rbp-8], rcx L007d nop L007e jmp L0106 L0083 lea rdx, [rbp-0x38] L0087 mov rcx, [rbp-8] L008b mov r11, 0x7ffd31ad7030 L0095 mov rax, 0x7ffd31ad7030 L009f call qword ptr [rax] L00a1 movups xmm0, [rbp-0x38] L00a5 movups [rbp-0x18], xmm0 L00a9 nop L00aa mov rcx, [rbp+0x10] L00ae mov rcx, [rcx+0x10] L00b2 cmp [rcx], ecx L00b4 call System.Data.DataSet.get_Tables() L00b9 mov [rbp-0x40], rax L00bd mov rcx, [rbp-0x40] L00c1 mov rdx, [rbp+0x18] L00c5 cmp [rcx], ecx L00c7 call System.Data.DataTableCollection.get_Item(System.String) L00cc mov [rbp-0x48], rax L00d0 mov rcx, [rbp-0x48] L00d4 cmp [rcx], ecx L00d6 call System.Data.DataTable.get_Rows() L00db mov [rbp-0x50], rax L00df mov rcx, [rbp-0x50] L00e3 mov edx, [rbp+0x20] L00e6 cmp [rcx], ecx L00e8 call System.Data.DataRowCollection.get_Item(Int32) L00ed mov [rbp-0x58], rax L00f1 mov rcx, [rbp-0x58] L00f5 mov rdx, [rbp-0x18] L00f9 mov r8, [rbp-0x10] L00fd cmp [rcx], ecx L00ff call System.Data.DataRow.set_Item(System.String, System.Object) L0104 nop L0105 nop L0106 mov rcx, [rbp-8] L010a mov r11, 0x7ffd31ad7028 L0114 mov rax, 0x7ffd31ad7028 L011e call qword ptr [rax] L0120 mov [rbp-0x24], eax L0123 cmp dword ptr [rbp-0x24], 0 L0127 jne L0083 L012d nop L012e jmp short L0130 L0130 mov rcx, rsp L0133 call L0140 L0138 nop L0139 nop L013a lea rsp, [rbp] L013e pop rbp L013f ret L0140 push rbp L0141 sub rsp, 0x30 L0145 mov rbp, [rcx+0x20] L0149 mov [rsp+0x20], rbp L014e lea rbp, [rbp+0x80] L0155 cmp qword ptr [rbp-8], 0 L015a je short L0177 L015c mov rcx, [rbp-8] L0160 mov r11, 0x7ffd31ad7038 L016a mov rax, 0x7ffd31ad7038 L0174 call qword ptr [rax] L0176 nop L0177 nop L0178 add rsp, 0x30 L017c pop rbp L017d ret
Der Assembler Code von „InitSettingsValues()“ (nicht optimaler Code):
Die letzte Zeilennummer (in Hex) lautet: 0x0843 = 2115 dez.
L0000 push rbp L0001 sub rsp, 0x1e0 L0008 lea rbp, [rsp+0x1e0] L0010 xorps xmm4, xmm4 L0013 movaps [rbp-0x1c0], xmm4 L001a mov rax, 0xfffffffffffffe50 L0024 movaps [rax+rbp], xmm4 L0028 movaps [rbp+rax+0x10], xmm4 L002d movaps [rbp+rax+0x20], xmm4 L0032 add rax, 0x30 L0036 jne short L0024 L0038 mov [rbp+0x10], rcx L003c mov rax, 0x7ffd3193c320 L0046 cmp dword ptr [rax], 0 L0049 je short L0050 L004b call 0x00007ffd906485f0 L0050 nop L0051 mov rcx, [rbp+0x10] L0055 mov rcx, [rcx+0x10] L0059 cmp [rcx], ecx L005b call System.Data.DataSet.get_Tables() L0060 mov [rbp-8], rax L0064 mov rdx, 0x1b5d3cd23a8 L006e mov rdx, [rdx] L0071 mov rcx, [rbp-8] L0075 cmp [rcx], ecx L0077 call System.Data.DataTableCollection.get_Item(System.String) L007c mov [rbp-0x10], rax L0080 mov rcx, [rbp-0x10] L0084 cmp [rcx], ecx L0086 call System.Data.DataTable.get_Rows() L008b mov [rbp-0x18], rax L008f mov rcx, [rbp-0x18] L0093 xor edx, edx L0095 cmp [rcx], ecx L0097 call System.Data.DataRowCollection.get_Item(Int32) L009c mov [rbp-0x20], rax L00a0 mov rcx, 0x7ffd30967238 L00aa call 0x00007ffd9050af00 L00af mov [rbp-0x28], rax L00b3 mov r8, [rbp-0x28] L00b7 mov byte ptr [r8+8], 0 L00bc mov r8, [rbp-0x28] L00c0 mov rdx, 0x1b5d3ceb6b8 L00ca mov rdx, [rdx] L00cd mov rcx, [rbp-0x20] L00d1 cmp [rcx], ecx L00d3 call System.Data.DataRow.set_Item(System.String, System.Object) L00d8 nop L00d9 mov rcx, [rbp+0x10] L00dd mov rcx, [rcx+0x10] L00e1 cmp [rcx], ecx L00e3 call System.Data.DataSet.get_Tables() L00e8 mov [rbp-0x30], rax L00ec mov rdx, 0x1b5d3cd23a8 L00f6 mov rdx, [rdx] L00f9 mov rcx, [rbp-0x30] L00fd cmp [rcx], ecx L00ff call System.Data.DataTableCollection.get_Item(System.String) L0104 mov [rbp-0x38], rax L0108 mov rcx, [rbp-0x38] L010c cmp [rcx], ecx L010e call System.Data.DataTable.get_Rows() L0113 mov [rbp-0x40], rax L0117 mov rcx, [rbp-0x40] L011b xor edx, edx L011d cmp [rcx], ecx L011f call System.Data.DataRowCollection.get_Item(Int32) L0124 mov [rbp-0x48], rax L0128 mov rcx, 0x7ffd30967238 L0132 call 0x00007ffd9050af00 L0137 mov [rbp-0x28], rax L013b mov r8, [rbp-0x28] L013f mov byte ptr [r8+8], 1 L0144 mov r8, [rbp-0x28] L0148 mov rdx, 0x1b5d3ceb6c0 L0152 mov rdx, [rdx] L0155 mov rcx, [rbp-0x48] L0159 cmp [rcx], ecx L015b call System.Data.DataRow.set_Item(System.String, System.Object) L0160 nop L0161 mov rcx, [rbp+0x10] L0165 mov rcx, [rcx+0x10] L0169 cmp [rcx], ecx L016b call System.Data.DataSet.get_Tables() L0170 mov [rbp-0x50], rax L0174 mov rdx, 0x1b5d3cd23a8 L017e mov rdx, [rdx] L0181 mov rcx, [rbp-0x50] L0185 cmp [rcx], ecx L0187 call System.Data.DataTableCollection.get_Item(System.String) L018c mov [rbp-0x58], rax L0190 mov rcx, [rbp-0x58] L0194 cmp [rcx], ecx L0196 call System.Data.DataTable.get_Rows() L019b mov [rbp-0x60], rax L019f mov rcx, [rbp-0x60] L01a3 xor edx, edx L01a5 cmp [rcx], ecx L01a7 call System.Data.DataRowCollection.get_Item(Int32) L01ac mov [rbp-0x68], rax L01b0 mov rdx, 0x1b5d3ceb6c8 L01ba mov rdx, [rdx] L01bd mov rcx, [rbp-0x68] L01c1 xor r8d, r8d L01c4 cmp [rcx], ecx L01c6 call System.Data.DataRow.set_Item(System.String, System.Object) L01cb nop L01cc mov rcx, [rbp+0x10] L01d0 mov rcx, [rcx+0x10] L01d4 cmp [rcx], ecx L01d6 call System.Data.DataSet.get_Tables() L01db mov [rbp-0x70], rax L01df mov rdx, 0x1b5d3cd23a8 L01e9 mov rdx, [rdx] L01ec mov rcx, [rbp-0x70] L01f0 cmp [rcx], ecx L01f2 call System.Data.DataTableCollection.get_Item(System.String) L01f7 mov [rbp-0x78], rax L01fb mov rcx, [rbp-0x78] L01ff cmp [rcx], ecx L0201 call System.Data.DataTable.get_Rows() L0206 mov [rbp-0x80], rax L020a mov rcx, [rbp-0x80] L020e xor edx, edx L0210 cmp [rcx], ecx L0212 call System.Data.DataRowCollection.get_Item(Int32) L0217 mov [rbp-0x88], rax L021e mov rcx, 0x7ffd3096e688 L0228 call 0x00007ffd9050af00 L022d mov [rbp-0x28], rax L0231 mov r8, [rbp-0x28] L0235 movsd xmm0, [UserQuery.InitSettingsValues()] L023d movsd [r8+8], xmm0 L0243 mov r8, [rbp-0x28] L0247 mov rdx, 0x1b5d3ceb6d0 L0251 mov rdx, [rdx] L0254 mov rcx, [rbp-0x88] L025b cmp [rcx], ecx L025d call System.Data.DataRow.set_Item(System.String, System.Object) L0262 nop L0263 mov rcx, [rbp+0x10] L0267 mov rcx, [rcx+0x10] L026b cmp [rcx], ecx L026d call System.Data.DataSet.get_Tables() L0272 mov [rbp-0x90], rax L0279 mov rdx, 0x1b5d3cd23a8 L0283 mov rdx, [rdx] L0286 mov rcx, [rbp-0x90] L028d cmp [rcx], ecx L028f call System.Data.DataTableCollection.get_Item(System.String) L0294 mov [rbp-0x98], rax L029b mov rcx, [rbp-0x98] L02a2 cmp [rcx], ecx L02a4 call System.Data.DataTable.get_Rows() L02a9 mov [rbp-0xa0], rax L02b0 mov rcx, [rbp-0xa0] L02b7 xor edx, edx L02b9 cmp [rcx], ecx L02bb call System.Data.DataRowCollection.get_Item(Int32) L02c0 mov [rbp-0xa8], rax L02c7 mov r8, 0x1b5d3ceb6e0 L02d1 mov r8, [r8] L02d4 mov rdx, 0x1b5d3ceb6d8 L02de mov rdx, [rdx] L02e1 mov rcx, [rbp-0xa8] L02e8 cmp [rcx], ecx L02ea call System.Data.DataRow.set_Item(System.String, System.Object) L02ef nop L02f0 mov rcx, [rbp+0x10] L02f4 mov rcx, [rcx+0x10] L02f8 cmp [rcx], ecx L02fa call System.Data.DataSet.get_Tables() L02ff mov [rbp-0xb0], rax L0306 mov rdx, 0x1b5d3cd23a8 L0310 mov rdx, [rdx] L0313 mov rcx, [rbp-0xb0] L031a cmp [rcx], ecx L031c call System.Data.DataTableCollection.get_Item(System.String) L0321 mov [rbp-0xb8], rax L0328 mov rcx, [rbp-0xb8] L032f cmp [rcx], ecx L0331 call System.Data.DataTable.get_Rows() L0336 mov [rbp-0xc0], rax L033d mov rcx, [rbp-0xc0] L0344 xor edx, edx L0346 cmp [rcx], ecx L0348 call System.Data.DataRowCollection.get_Item(Int32) L034d mov [rbp-0xc8], rax L0354 xor ecx, ecx L0356 mov [rbp-0xd0], rcx L035d lea rcx, [rbp-0xd0] L0364 mov edx, 0x7d1 L0369 mov r8d, 9 L036f mov r9d, 0xb L0375 call System.DateTime..ctor(Int32, Int32, Int32) L037a mov rdx, 0x1b5d3ceb6e8 L0384 mov rdx, [rdx] L0387 mov [rbp-0x1c0], rdx L038e lea rdx, [rbp-0xd0] L0395 mov rcx, 0x7ffd30bef900 L039f call 0x00007ffd9050af40 L03a4 mov [rbp-0x1b8], rax L03ab mov r8, [rbp-0x1b8] L03b2 mov rdx, [rbp-0x1c0] L03b9 mov rcx, [rbp-0xc8] L03c0 cmp [rcx], ecx L03c2 call System.Data.DataRow.set_Item(System.String, System.Object) L03c7 nop L03c8 mov rcx, [rbp+0x10] L03cc mov rcx, [rcx+0x10] L03d0 cmp [rcx], ecx L03d2 call System.Data.DataSet.get_Tables() L03d7 mov [rbp-0xd8], rax L03de mov rdx, 0x1b5d3cd23a8 L03e8 mov rdx, [rdx] L03eb mov rcx, [rbp-0xd8] L03f2 cmp [rcx], ecx L03f4 call System.Data.DataTableCollection.get_Item(System.String) L03f9 mov [rbp-0xe0], rax L0400 mov rcx, [rbp-0xe0] L0407 cmp [rcx], ecx L0409 call System.Data.DataTable.get_Rows() L040e mov [rbp-0xe8], rax L0415 mov rcx, [rbp-0xe8] L041c xor edx, edx L041e cmp [rcx], ecx L0420 call System.Data.DataRowCollection.get_Item(Int32) L0425 mov [rbp-0xf0], rax L042c mov rcx, 0x7ffd3096b258 L0436 call 0x00007ffd9050af00 L043b mov [rbp-0x28], rax L043f mov r8, [rbp-0x28] L0443 mov dword ptr [r8+8], 6 L044b mov r8, [rbp-0x28] L044f mov rdx, 0x1b5d3ceb6f0 L0459 mov rdx, [rdx] L045c mov rcx, [rbp-0xf0] L0463 cmp [rcx], ecx L0465 call System.Data.DataRow.set_Item(System.String, System.Object) L046a nop L046b mov rcx, [rbp+0x10] L046f mov rcx, [rcx+0x10] L0473 cmp [rcx], ecx L0475 call System.Data.DataSet.get_Tables() L047a mov [rbp-0xf8], rax L0481 mov rdx, 0x1b5d3cd23a8 L048b mov rdx, [rdx] L048e mov rcx, [rbp-0xf8] L0495 cmp [rcx], ecx L0497 call System.Data.DataTableCollection.get_Item(System.String) L049c mov [rbp-0x100], rax L04a3 mov rcx, [rbp-0x100] L04aa cmp [rcx], ecx L04ac call System.Data.DataTable.get_Rows() L04b1 mov [rbp-0x108], rax L04b8 mov rcx, [rbp-0x108] L04bf xor edx, edx L04c1 cmp [rcx], ecx L04c3 call System.Data.DataRowCollection.get_Item(Int32) L04c8 mov [rbp-0x110], rax L04cf mov rcx, 0x7ffd3096b258 L04d9 call 0x00007ffd9050af00 L04de mov [rbp-0x28], rax L04e2 mov r8, [rbp-0x28] L04e6 mov dword ptr [r8+8], 7 L04ee mov r8, [rbp-0x28] L04f2 mov rdx, 0x1b5d3ceb6f8 L04fc mov rdx, [rdx] L04ff mov rcx, [rbp-0x110] L0506 cmp [rcx], ecx L0508 call System.Data.DataRow.set_Item(System.String, System.Object) L050d nop L050e mov rcx, [rbp+0x10] L0512 mov rcx, [rcx+0x10] L0516 cmp [rcx], ecx L0518 call System.Data.DataSet.get_Tables() L051d mov [rbp-0x118], rax L0524 mov rdx, 0x1b5d3cd23a8 L052e mov rdx, [rdx] L0531 mov rcx, [rbp-0x118] L0538 cmp [rcx], ecx L053a call System.Data.DataTableCollection.get_Item(System.String) L053f mov [rbp-0x120], rax L0546 mov rcx, [rbp-0x120] L054d cmp [rcx], ecx L054f call System.Data.DataTable.get_Rows() L0554 mov [rbp-0x128], rax L055b mov rcx, [rbp-0x128] L0562 xor edx, edx L0564 cmp [rcx], ecx L0566 call System.Data.DataRowCollection.get_Item(Int32) L056b mov [rbp-0x130], rax L0572 mov rcx, 0x7ffd3096b258 L057c call 0x00007ffd9050af00 L0581 mov [rbp-0x28], rax L0585 mov r8, [rbp-0x28] L0589 mov dword ptr [r8+8], 8 L0591 mov r8, [rbp-0x28] L0595 mov rdx, 0x1b5d3ceb700 L059f mov rdx, [rdx] L05a2 mov rcx, [rbp-0x130] L05a9 cmp [rcx], ecx L05ab call System.Data.DataRow.set_Item(System.String, System.Object) L05b0 nop L05b1 mov rcx, [rbp+0x10] L05b5 mov rcx, [rcx+0x10] L05b9 cmp [rcx], ecx L05bb call System.Data.DataSet.get_Tables() L05c0 mov [rbp-0x138], rax L05c7 mov rdx, 0x1b5d3cd23a8 L05d1 mov rdx, [rdx] L05d4 mov rcx, [rbp-0x138] L05db cmp [rcx], ecx L05dd call System.Data.DataTableCollection.get_Item(System.String) L05e2 mov [rbp-0x140], rax L05e9 mov rcx, [rbp-0x140] L05f0 cmp [rcx], ecx L05f2 call System.Data.DataTable.get_Rows() L05f7 mov [rbp-0x148], rax L05fe mov rcx, [rbp-0x148] L0605 xor edx, edx L0607 cmp [rcx], ecx L0609 call System.Data.DataRowCollection.get_Item(Int32) L060e mov [rbp-0x150], rax L0615 mov rcx, 0x7ffd3096b258 L061f call 0x00007ffd9050af00 L0624 mov [rbp-0x28], rax L0628 mov r8, [rbp-0x28] L062c mov dword ptr [r8+8], 9 L0634 mov r8, [rbp-0x28] L0638 mov rdx, 0x1b5d3ceb708 L0642 mov rdx, [rdx] L0645 mov rcx, [rbp-0x150] L064c cmp [rcx], ecx L064e call System.Data.DataRow.set_Item(System.String, System.Object) L0653 nop L0654 mov rcx, [rbp+0x10] L0658 mov rcx, [rcx+0x10] L065c cmp [rcx], ecx L065e call System.Data.DataSet.get_Tables() L0663 mov [rbp-0x158], rax L066a mov rdx, 0x1b5d3cd23a8 L0674 mov rdx, [rdx] L0677 mov rcx, [rbp-0x158] L067e cmp [rcx], ecx L0680 call System.Data.DataTableCollection.get_Item(System.String) L0685 mov [rbp-0x160], rax L068c mov rcx, [rbp-0x160] L0693 cmp [rcx], ecx L0695 call System.Data.DataTable.get_Rows() L069a mov [rbp-0x168], rax L06a1 mov rcx, [rbp-0x168] L06a8 xor edx, edx L06aa cmp [rcx], ecx L06ac call System.Data.DataRowCollection.get_Item(Int32) L06b1 mov [rbp-0x170], rax L06b8 mov rcx, 0x7ffd3096b258 L06c2 call 0x00007ffd9050af00 L06c7 mov [rbp-0x28], rax L06cb mov r8, [rbp-0x28] L06cf mov dword ptr [r8+8], 0xa L06d7 mov r8, [rbp-0x28] L06db mov rdx, 0x1b5d3ceb710 L06e5 mov rdx, [rdx] L06e8 mov rcx, [rbp-0x170] L06ef cmp [rcx], ecx L06f1 call System.Data.DataRow.set_Item(System.String, System.Object) L06f6 nop L06f7 mov rcx, [rbp+0x10] L06fb mov rcx, [rcx+0x10] L06ff cmp [rcx], ecx L0701 call System.Data.DataSet.get_Tables() L0706 mov [rbp-0x178], rax L070d mov rdx, 0x1b5d3cd23a8 L0717 mov rdx, [rdx] L071a mov rcx, [rbp-0x178] L0721 cmp [rcx], ecx L0723 call System.Data.DataTableCollection.get_Item(System.String) L0728 mov [rbp-0x180], rax L072f mov rcx, [rbp-0x180] L0736 cmp [rcx], ecx L0738 call System.Data.DataTable.get_Rows() L073d mov [rbp-0x188], rax L0744 mov rcx, [rbp-0x188] L074b xor edx, edx L074d cmp [rcx], ecx L074f call System.Data.DataRowCollection.get_Item(Int32) L0754 mov [rbp-0x190], rax L075b mov rcx, 0x7ffd3096b258 L0765 call 0x00007ffd9050af00 L076a mov [rbp-0x28], rax L076e mov r8, [rbp-0x28] L0772 mov dword ptr [r8+8], 0x63 L077a mov r8, [rbp-0x28] L077e mov rdx, 0x1b5d3ceb718 L0788 mov rdx, [rdx] L078b mov rcx, [rbp-0x190] L0792 cmp [rcx], ecx L0794 call System.Data.DataRow.set_Item(System.String, System.Object) L0799 nop L079a mov rcx, [rbp+0x10] L079e mov rcx, [rcx+0x10] L07a2 cmp [rcx], ecx L07a4 call System.Data.DataSet.get_Tables() L07a9 mov [rbp-0x198], rax L07b0 mov rdx, 0x1b5d3cd23a8 L07ba mov rdx, [rdx] L07bd mov rcx, [rbp-0x198] L07c4 cmp [rcx], ecx L07c6 call System.Data.DataTableCollection.get_Item(System.String) L07cb mov [rbp-0x1a0], rax L07d2 mov rcx, [rbp-0x1a0] L07d9 cmp [rcx], ecx L07db call System.Data.DataTable.get_Rows() L07e0 mov [rbp-0x1a8], rax L07e7 mov rcx, [rbp-0x1a8] L07ee xor edx, edx L07f0 cmp [rcx], ecx L07f2 call System.Data.DataRowCollection.get_Item(Int32) L07f7 mov [rbp-0x1b0], rax L07fe mov rcx, 0x7ffd3096b258 L0808 call 0x00007ffd9050af00 L080d mov [rbp-0x28], rax L0811 mov r8, [rbp-0x28] L0815 mov dword ptr [r8+8], 0x64 L081d mov r8, [rbp-0x28] L0821 mov rdx, 0x1b5d3ceb720 L082b mov rdx, [rdx] L082e mov rcx, [rbp-0x1b0] L0835 cmp [rcx], ecx L0837 call System.Data.DataRow.set_Item(System.String, System.Object) L083c nop L083d nop L083e lea rsp, [rbp] L0842 pop rbp L0843 ret
Dazu mehr ist auf Wikipedia in Separation of Concerns zu lesen.
Schiache Pfuscher-Code, im Vergleich zu sauberer Professioneller-Code #1
Für J.E.
Wünsche dir alles Gute und viel Erfolg bei deinem Studium.
Diesen Code gab es tatsächlich, und ist nicht aus der Luft gegriffen.
Schaue dir diesen Code mal gründlich in Ruhe an. Was fällt dir auf?
/// <summary> /// Gibt einen wert zurück /// </summary> /// <param name="name"></param> /// <returns></returns> public object GetValue(string name) { try { if (_DataSet == null) return null; if (_DataSet.Tables.Contains("Settings")) { return Convert.ChangeType( _DataSet.Tables["Settings"].Rows[0][name], _DataSet.Tables["Settings"].Columns[name].DataType); } } catch(Exception ex) { return null; } return ""; }

- Kommentar:
- Ist nicht auf Englisch
- Sagt nichts Neues aus, somit sagt nichts aus
- Rückgabe-Typ:
- Unklarer/Vager Rückgabe-Typ (ein Objekt kann alles Mögliche sein: Animal, bool, Gott, Welt, …). Der Aufrufer muss Unboxing betreiben (falls der Wert nicht NULL ist, wie wir sehen werden)
- Der Name der Methode:
- ist weder klar noch eindeutig
- lässt vermuten, dass keine Ausnahmefehler abgefangen/behandelt werden
- Der Aufrufer wird selbst, nicht notwendigerweise, Try-Catch-Block herumbauen
- NULL-Rückgabe:
- Was macht der Aufrufer, wenn er für Einstellungsname „enabled“, true oder false erwartet, jedoch einen NULL bekommt?
- Was machen 100 aufrufende Stellen im Code? 1000?
- Wie oft muss aufrufender Code, die NULL-Eventualität prüfen, um darauf richtig zu reagieren?
- Was passiert mit 100 aufrufende Stellen im Code, wenn diese Methode ausgebessert wird?
- Mehrfaches Erzeugen und Verwenden von inhaltlich gleichem String:
- Erzeugen von Strings ist teuer. Warum also dreimal das Gleiche?
- Was passiert, wenn der DB-Entwickler die Tabelle in „Config“ umbenennt? Wie findet man diese Stellen überall im Code? Wie oft muss man dann der Name aktualisieren?
- Rückgabe-Typ: Angenommen „DataType“ = Single oder Double …
- Der float/double Wert wird geboxt, damit der Aufrufer es wieder unboxt? Boxing/Unboxing ist ein teurer Spaß!
- Try-Catch-Block:
- Wozu? Was soll schiefgehen? Welcher Ausnahmefehler soll da geworfen werden? Eine DB-Tabelle mit Einstellungen taucht (in ein ordentliches Schema und SW-System) nicht einfach auf, und verschwindet einfach so!
- Exception-Typ und Variable:
- Wozu? Was wird mit den Informationen in „ex“ gemacht?
- Rückgabe-Typ: wurde schon weiter oben thematisiert
- Rückgabe-Typ:
- Aha! Ach, so ist das! Warum wird auf einmal eine leere Zeichenkette zurückgeliefert? Welcher Aufrufer rechnet damit?
- Was macht ein Aufrufer, der, zum Beispiel auf die true/false Werte wartet, mit einer leeren Zeichenkette?
So ein Code kann man auch sauber und professionell gestalten
Principle Of Least Surprise : POLS
Sauberer Code weil:
- Die Namen sind klar und eindeutig, lassen weder Vermutungen noch Überraschungen zu:
- Get Value Or Null ⇒ liefert einen Wert oder NULL zurück, schmeißt aber keine Ausnahmefehler. Deswegen müssen an zig oder hunderte Stellen, keine Try-Catch-Blocks geschrieben werden.
- Get Value ⇒ liefert einen Wert oder schmeißt einen Ausnahmefehler
- Get Value Or Default (generisch) ⇒ liefert einen Wert oder den Standardwert:
- bool: false
- byte/sbyte/short/ushort/int/unit/long/ulong: 0
- float/double/decimal: 0.0
- string: null
- schmeißt keine Ausnahmefehler
- Get Value Or Default (generisch) ⇒ liefert einen Wert oder den von Aufrufer bestimmter Standardwert, jedoch keine Ausnahmefehler geworfen
- Get Value (generisch) ⇒ liefert einen Wert oder wirft einen Ausnahmefehler
- Es werden Alternativen angeboten (siehe Unterpunkte von Punkt 1!)
- Der Rückgabe-Typ ist bei alternative generische Funktionen von Aufrufer festgesetzt/bestimmt und eindeutig
- Die Rückgabe-Typen sind alle konsistent: entweder einen Wert oder Ausnahmefehler, Wert oder NULL, Wert oder Standardwert ⇒ keine Überraschungen
- Bei Aufruf von generische Varianten sind keine Unboxings auf der Aufrufer-Seite notwendig
Gibt es da unten eine Methode, welche ein Kommentar braucht?
public class CleanCode { public const string TNAME_SETTINGS = @"Settings"; private DataSet _DataSet; // 1. Variante: Objekt als Return-Value. Ist POLS-Konform. // Tut das Gleiche wie oben, nur viel einfacher (ohne leere Strings) // Die Aufrufer müssen sich um Exceptions und NULL kümmern. // Ansonsten, verlässlicher als der Code von oben (trotzdem NICHT GUT!) public object GetValue(string pSettingName, Type pType) { var value = _DataSet.Tables[TNAME_SETTINGS].Rows[0][pSettingName]; return Convert.ChangeType(value, pType); } // 2. Variante: Objekt als Return-Value. Ist POLS-Konform. public object GetValueOrNull(string pSettingName) { if (_DataSet == null || !_DataSet.Tables.Contains(TNAME_SETTINGS) || _DataSet.Tables[TNAME_SETTINGS].Rows.Count == 0 || !_DataSet.Tables[TNAME_SETTINGS].Columns.Contains(pSettingName)) return null; return _DataSet.Tables[TNAME_SETTINGS].Rows[0][pSettingName]; } // 3. Variante: Generischen Typ. Ist POLS-Konform. // Sollte etwas nicht passen oder schiefgehen, erhält der Aufrufer // den Standardwert des Typs. public T GetValueOrDefault<T>(string pSettingName) { if (_DataSet == null || !_DataSet.Tables.Contains(TNAME_SETTINGS) || _DataSet.Tables[TNAME_SETTINGS].Rows.Count == 0 || !_DataSet.Tables[TNAME_SETTINGS].Columns.Contains(pSettingName)) return default; try { var value = _DataSet.Tables[TNAME_SETTINGS].Rows[0][pSettingName]; return (T)Convert.ChangeType(value, typeof(T)); } catch { return default; } } // 4. Variante: Generischen Typ. Ist POLS-Konform. // Die Aufrufer können selbst entscheiden welchen Wert Sie erhalten möchten, // falls diese an den Standardwert des Typs nicht sind. public T GetValueOrDefault<T>(string pSettingName, T pDefault = default) { if (_DataSet == null || !_DataSet.Tables.Contains(TNAME_SETTINGS) || _DataSet.Tables[TNAME_SETTINGS].Rows.Count == 0 || !_DataSet.Tables[TNAME_SETTINGS].Columns.Contains(pSettingName)) return pDefault; try { var value = _DataSet.Tables[TNAME_SETTINGS].Rows[0][pSettingName]; return (T)Convert.ChangeType(value, typeof(T)); } catch { return pDefault; } } // 5. Variante: Generischer Typ. Ist POLS-Konform. public T GetValue<T>(string pSettingName) { var value = _DataSet.Tables[TNAME_SETTINGS].Rows[0][pSettingName]; return (T)Convert.ChangeType(value, typeof(T)); } }
Flat Design: Houston, we’ve got no Signal!
Die Sonne ist über uns, also oben. Deswegen entsteht der Schatten nach unten.
Siehe Schatten von Bäumen, Berge, Häuser, Autos, Menschen.
Alle 3D Objekte in der realen Welt, die man drücken, ziehen, pressen, schieben oder draufhauen kann, werfen einen … was? Dreimal dürft ihr raten!
Warum die Leute in Redmond den Flat Design ohne Schatten und somit ohne Signalwirkung damals, bei Windows 7 gewählt haben, ist mir bis heute ein Rätsel.
Zum Beispiel hier: „Herunterladen und installieren“ wird genauso flach, grau, ohne Schatten dargestellt wie so ziemlich alles andere auch:



Verwaiste UI Elemente
Definition: Verwaiste UI Elemente sind grafische Benutzersteuerungs-Elemente, wie Textfelder, Check-Kästchen, Optionsfelder udg., die jedoch keine Funktion/Wirkung haben.
Verwaiste UI Elemente haben in einem Produktionssystem nichts verloren. Diese zeigen einem aufmerksamen Anwender, dass:
- Herumgebastelt wurde
- Die Software nicht fertiggemacht wurde
- Die Software-Funktion nicht gründlich überlegt wurde
- Die Software nicht getestet wurde
- Dem Produzenten es völlig egal ist, was die Anwender/Kunden von ihm und sein Produkt (die Software) halten
- Welche Wertschätzung der Produzent seine Anwender/Kunden entgegenbringt (Folgerung aus Punkt 5)
Zudem verwirren die verwaiste UIs den Anwender, erzeugen in seinem Kopf unnötige Fragen, machen ihm unsicher und halten ihn unnötig auf. Seine Blickführung ist gestört (seine Augen stolpern über das verwaiste UI Element).
Rechtschreibfehler & User Experience (UX)
Würden Sie ein Auto der Marke „PNW“ kaufen?
Niemand ist fehlerfrei.
Ich mache gelegentlich Fehler – insbesondere in der Rechtschreibung, nicht zu vergessen Verwechslungen von Kasus oder das Auslassen von Artikeln.
In einem Software-System, abhängig von seiner Komplexität, können Rechtschreibfehler auftreten. Aber was geht einem aufmerksamen Nutzer durch den Kopf, wenn solche Fehler gehäuft vorkommen?
- Die Software befindet sich noch in einer frühen Entwicklungsphase.
- Niemand hat sich die Zeit genommen, das Produkt gründlich zu überprüfen.
- Die Software wurde gar nicht getestet oder angeschaut.
- Schlussfolgerung aus den Punkten 1 bis 3: Ein unfertiges Produkt wurde verkauft.
- Schlussfolgerung erweiternd auf Punkt 4: Dem Softwarehersteller liegt die Qualität seines Produktes nicht am Herzen.
- Schlussfolgerung ergänzend zu Punkt 5: Dem Hersteller ist es gleichgültig, welchen Eindruck die Nutzer aufgrund der vielen Fehler erhalten.
- Schlussfolgerung fortsetzend zu Punkt 6: Der Hersteller misst der Meinung seiner Kunden keine Bedeutung bei.
Würden Sie ein „PMW“ erwerben? Und wenn nicht, warum eigentlich nicht?
Dimensionierung und Planung von Software und Fußgängerbrücken
Software:
Am Anfang heißt es immer: „… ein kleines und sehr einfaches Programm…“, und dann fallen ähnliche Sätze wie „…ein Drei-Zeilen-Programm…“ sowie „… keine eye candies…“.
Mitten in Entwicklung, und oft gar gegen Ende heißt es dann: „… wir brauchen schon Benutzerverwaltung…“, und „… man sollte schon arabische und hebräische Texte von rechts nach links darstellen können…“, sowie „… naja auf Mac OSX muss es auch laufen…“ und nicht zu vergessen „… man soll ganz einfach das Datenbank-System auswechseln können…“ sowie „…. Daten von X ins Y migrieren können…“ aber auch „… über Internet Reports abrufen können…“ und eine Selbstverständlichkeit heißt es dann „… die Daten müssen auch in AAA, BBB, …, CSV, XML, JSON, …, ZZZ und 1000 andere Formate exportiert werden können..“ usw. usf.
Fußgängerbrücke:
Ich habe ehrlich gesagt absolut keine Ahnung, was am Anfang bei der Planung von Fußgängerbrücken verlangt und gesagt wird… aber einiges weiß ich mit Bestimmtheit:
Bei oder nach der Fertigstellung von Fußgängerbrücken heißt es nie:
- Wir hätten gerne die Fußgängerbrücke 30 km weiter südlich!
- Auf der Fußgängerbrücke sollten auch Radfahrer fahren können.
- Die Fußgängerbrücke sollte schon 2 Spuren für Fahrzeuge pro Richtung haben!
- Für jede Richtung sollte es schon einen Pannenstreifen geben!
- Bitte baut die Fußgängerbrücke etwas breiter und baut Schienen für die Bahn dazu!
- 1000 vollbeladene LKWs und Sattelschlepper sollten schon täglich mit 100 km/h darüber fahren können!
- Man sollte schon pro Fahrspur eine Autoschranke haben, um Autobahnmaut zu kassieren!
Das ist keine Fußgängerbrücke mehr, sondern eine große Autobahnbrücke mit weißGottWasWeißIchAllesNoch!
Kann es sein, dass manche Kosten mit Komplexität verwechseln?
Belastung-Tests von Software und Autobahnbrücken
Software:
Man zwingt einen Mitarbeiter, eine Zeit lang mit einer Anwendung zu spielen. Ohne Ziel und Plan einfach herumklicken. Wenn die Anwendung nicht abstürzt und/oder keine Fehlermeldung kommt, dann gilt die Anwendung als „getestet“.
Autobahnbrücke:
Man hat noch nie eine Autobahnbrücke als belastbar freigegeben, nur weil ein Fußgänger oder Radfahrer darüber gegangen oder gefahren ist.
Stabilität-Tests von Software und Autobahnbrücken
Software:
Man startet das Programm und lässt es durchgehend laufen, ohne dass jemand damit irgendwas Gezieltes und Intensives nach Logik und Plan tut. Da das Programm, nach ein paar Tagen, Wochen, Monate immer noch läuft, wird es als Stabil gestuft.
Autobahnbrücke: nur weil eine Autobahn nach der Fertigung, immer noch ein paar Wochen steht, wird sie nicht als stabil gestuft!
Tunnel-Projekt vs. Software-Projekt
Bitte korrigiert mich, falls ich mich irre, oder es nicht mitbekommen habe….
Ich habe noch nie gelesen oder gehört, dass nachdem ein Tunnel fertig gebaut wurde, oder mitten im Bau, irgendwelche Leute gekommen wären und gesagt hätten, die hätten sich umentschieden, der Tunnel soll in einem anderen Berg gebohrt werden, oder er soll Norden und Süden statt Ost und West verbinden.
Bei Software-Projekte… (Der/Die Leser/Leserin möge sich selbst das Ende ausdenken! Anm. d. R.)
Sauberkeit und Ordnung
Wie ich in meinem vorigen Beitrag geschrieben habe, habe ich an manchen Sommerferien, als Elektriker auf Baustellen, mein Taschengeld zum Ausgeben für Computerteile & Peripheriegeräte, aufgebessert.
Dabei müssten alle auf der Baustelle, also die Elektriker, Maurer, Installateure, Dachdecker usw., am Ende des Tages ihre Werkzeuge reinigen und ordentlich verstauen, die Materialien genauso… und am Ende mit dem Besen kehren.
Warum?
- Effizienz-Steigerung & Wirtschaftlichkeit I: man muss weniger/kaum nach Werkzeug/Materialien suchen, da alles an seinem Platz ist
- Effizienz-Steigerung & Wirtschaftlichkeit II: mehr Firmen können gleichzeitig/parallel arbeiten, da mehr Platz zur Verfügung steht
- Effizienz-Steigerung & Wirtschaftlichkeit III: man muss auf bestellte Materialien nicht warten, da der Mangel dieser, rechtzeitig erkannt und früh genug vorbestellt wird
- Unfall-Vermeidung: man kann nicht über nichts stolpern!
- Fehler und Mängel werden früher erkannt und beseitigt
Bei Softwareprojekte jedoch, so scheint es mir, sind Dinge wie Effizienz, Wirtschaftlichkeit, Qualität und Nachhaltigkeit keine erstrebenswerten Merkmale.
Wie sonst kann man folgendes erklären: Man sieht den Groschen, aber nicht den 500 € Schein?
Aufräumen von Code (+ Kommentare und Dokumentation, falls diese überhaupt existieren)?
Wozu? Es funktioniert ja eh! (bis es dann ordentlich kracht)

Pläne & Planung
Als Student, während Sommerferien, arbeitete ich manchmal als Elektriker auf Baustellen, und erledigte die Aufgaben die man mir auftrug:
mit Schlagbohrer Löcher für Steckdosen und Schalter in die Mauer bohren, Büchsen für Schalter- und Steckdosen mit Elektriker-Gips in diese Löcher befestigen, Kabel verlegen/ziehen,… und zum Schluß die Steckdosen, Schalter und Verteilerkasten mit Drähte/Kabel verbinden, und am Ende das Ganze Testen.
Auf jede Baustelle gab man mir (als Elektriker) einen Plan in die Hand.
In diese konnte ich auf einem Blick sehen und lesen:
- wo,
- wie viele und
- wie hoch die Steckdose eingebaut werden müssten
- wo der Kabel-TV-Anschluss war
- wo der Telefon-Anschluss
- welche Steckdosen und Lampen hingen an welche Sicherung (Fehlerstromschutzschalter)
- wie groß/stark sollte die Sicherung dimensioniert sein
- wie stark (Querschnitt) die Drähte und Kabel
und so weiter.
Die Installateure, die Maurer, die Dachdecker… kurz: alle anderen sind auch ständig mit ihre Pläne herumgelaufen, schauten immer wieder gemeinsam darein, diskutierten miteinander darüber, und machten nach Plan weiter.
Obwohl trivial, doch ich möchte und muss hier erwähnen, dass Kabel, Steckdosen, Schalter, Sicherungen und Verteilerkasten materielle, also sichtbare und greifbare Dinge sind.
Als Softwareentwickler, werde ich meinen Wunsch, einen UML-Diagramm zu erhalten, mit ins Grab nehmen!
Kapitän! Oh mein Kapitän!
„Auf deinem Schiff, wäre ich ungern. Weder als Passagier noch als Matrose!“
Eine Firma ist wie ein Schiff, und der Chef/CEO/Geschäftsführer sein Kapitän.
Wenn der Kapitän ständig zu 100% belastet ist, für tausend Dinge zuständig, unterschiedlichste Dinge aus unterschiedlichste Bereiche erledigen muss, sich mehr und schneller als seiner Besatzung/Mannschaft bewegen muss, für keine wichtige Informationen, nicht einmal für „Eisberg voraus!“ Warnungen Zeit hat…. dann braucht man sich über seine Entscheidungen nicht wundern.
Er/Sie ist gar nicht im Stande richtige oder optimale Entscheidungen zu treffen, denn… er/sie hat keine Zeit.
Ich habe noch nie auf einem Schiff, einen Kapitän gesehen, der ständig im Stress und Bewegung ist, und tausend unterschiedliche Dinge aus unterschiedlichste Bereiche erledigt.
Ein Kapitän strahlt Ruhe und Zuversicht aus, hat den Überblick, hat die Zeit zum Überlegen, Zeit für Gespräche und Beratung mit seiner Mannschaft/Besatzung, Zeit fürs Analysieren, und nimmt sich die Zeit für Warnungen wie „Eisberg Voraus!“.
Wie sicher ist mein Web-Browser vor Tracking & Fingerprinting
Allgemeine Info (Englisch) über: Web-Tracking
Allgemeine Info (Englisch) über: Web-Browser-Fingerprinting bzw. Device-Fingerprint
Hier eine detaillierte Erklärung wie Web-Tracking funktioniert:
- Modem/Router des Internet-Providers
- Domain-Name-Server (DNS) und Virtual-Private-Networks (VPN)
- Der Fall Lavabit (ehemaliger Anbieter von sichere EMails, Edward Snowden war dessen Kunde)
- The World Wild Wild Web
- Regierungen & Big Brother & Weimarer Republik
- Sonar Beacon (wie ein Smartphone feststellt welche Fernseher-/Radio-Sendung man gerade in TV/Radio anschaut/anhört). Siehe auch iBeacon!
- Wie Auto-Diebe in USA und Kanada Apple AirTags missbrauchen
Auf diese Webseite kannst Du deinen Webbroser auf Tracking und Fingerprinting testen.
Und auf diese Webseite kann man bevor auf eine Webseite surft prüfen, ob und welche Tracking- und/oder Fingerprinting-Methoden angewendet werden.
Logger log4Net installieren & konfigurieren
log4net ist mit über 113M Downloads (auf Nuget.org) einer der ältesten Hasen unter die Logger für .NET/C#. Ich verwende es seit 2011, und war damit zufrieden bis ich den neueren Logger NLog entdeckt hatte 🙂
Um log4net in eigene Anwendungen zu verwenden muss dies installiert werden:

Danach muss die Konfiguration des Projekts mit der Konfiguration für log4net erweitert werden:
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/> </configSections> <log4net> <root> <level value="DEBUG"/> <appender-ref ref="RollingFileAppender"/> <appender-ref ref="ColoredConsoleAppender"/> </root> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="T:\MyTemp\Logs\MyApplication\log.txt"/> <appendToFile value="true"/> <rollingStyle value="Size"/> <maxSizeRollBackups value="3"/> <maximumFileSize value="10MB"/> <staticLogFileName value="true"/> <layout type="log4net.Layout.PatternLayout"> <!--<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />--> <conversionPattern value="%date{HH:mm:ss,fff} (%-2thread) [%-5level] %type.%method - %message%newline"/> </layout> </appender> <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender"> <mapping> <level value="ERROR"/> <foreColor value="Red, HighIntensity"/> <!-- backColor value="Black" / --> </mapping> <mapping> <level value="DEBUG"/> <foreColor value="Green, HighIntensity"/> </mapping> <mapping> <level value="WARN"/> <foreColor value="Yellow"/> </mapping> <mapping> <level value="INFO"/> <foreColor value="Cyan, HighIntensity"/> </mapping> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date{HH:mm:ss,fff} (%-2thread) [%-5level] %type.%method - %message%newline"/> <!--<conversionPattern value="%date{HH:mm:ss,ffff} [%thread{2}] - %message%newline" />--> </layout> </appender> </log4net> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>
Nun kann der Logger im Code wie folgt verwendet werden:
public class Program { // Create logger for this class ( = typeof(Program)). private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public void Main(string[] args) { Logger.Info("Starting application from console..."); // more code... } }
Logger NLog installieren & konfigurieren
Der Logger NLog ist mit über 250M Downloads (in Nuget.org) einer der Standard-Logger für .NET/C#.
Davor verwendete ich den log4net Logger.
Um NLog zu verwenden müssen zwei Nuget-Packages installiert werden:
- NLog
- NLog.Config

Danach muss die NLog.config Datei im Projekt konfiguriert werden.
Hier ist eine einfache Konfiguration um die Logs in einer Datei zu schreiben sowie diese auch in Console farbig auszugeben:

Die Konfiguration dazu:
<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd" autoReload="true" throwExceptions="false" internalLogLevel="Off" internalLogFile="T:\MyTemp\Logs\PGH.AssemblyParser and Converter\${shortdate}.log"> <targets> <target name="coloredConsole" xsi:type="ColoredConsole" useDefaultRowHighlightingRules="false" layout="${longdate} [${pad:padding=5:inner=${level:uppercase=true}}] ${logger} - ${message}" > <highlight-row condition="level == LogLevel.Debug" foregroundColor="Green" /> <highlight-row condition="level == LogLevel.Info" foregroundColor="Blue" /> <highlight-row condition="level == LogLevel.Warn" foregroundColor="Yellow" /> <highlight-row condition="level == LogLevel.Error" foregroundColor="Red" /> <highlight-row condition="level == LogLevel.Fatal" foregroundColor="Red" backgroundColor="White" /> </target> <target name="logFile" xsi:type="File" layout="${longdate} [${pad:padding=5:inner=${level:uppercase=true}}] ${logger} - ${message}" fileName="T:\MyTemp\Logs\MyApplication\${shortdate}.log" keepFileOpen="false" encoding="utf-8" /> </targets> <rules> <!-- add your logging rules here --> <logger name="*" minlevel="Trace" writeTo="coloredConsole" /> <logger name="*" minlevel="Trace" writeTo="logFile" /> <!-- Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace) to "f" <logger name="*" minlevel="Debug" writeTo="f" /> --> </rules> </nlog>
Nun kann der Logger wie folgt im Code verwendet werden:
class Program { // Create the logger for current class ( = typeof(Program)). private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); static void Main(string[] args) { Logger.Info("Starting application from Console..."); // more code... } }
Windows 7 oder 8.x auf Windows 10 aktualisieren (2022)
Es gibt immer noch einige PCs und Notebooks mit Windows 7 oder 8.x die herumliegen oder gar noch im Betrieb sind (= Unsicher!). Man kann immer noch das Betriebsystem Windows 7, oder Windows 8.x (8.0 – 8.3) auf Windows 10 aktualisieren. Es ist nicht zu spät.
Hier ist eine bebilderte Schritt für Schritt Anleitung:
In Webbrowser auf folgende Seite von Microsoft navigieren und auf „Tool jetzt herunterladen“ klicken:
https://www.microsoft.com/de-de/software-download/windows10

Nachem die Datei „MediaCreationToolXXXX.exe“ (XXXX steht für die aktuelle Version wie z.B.: 21H2) heruntergeladen/gespeichert wurde diese durch Doppelklick starten und folgende Schritte durchgehen:
Die Lizenzbedingungen mit einem Klick auf „Akzeptieren“ akzeptieren:

Danach muss man sich entscheiden ob man ein Installations-USB-Stick oder Installations-DVD erstellen möchte. Ich persönlich bevorzuge ein USB-Stick als Installations-Medium, da es sicherer (zerkratzte/unlesbare DVD bzw. das Fehlen von DVD-Laufwerk auf manchem PC/Notebook) und die Installation viel Schneller ist. Hier beschreibe ich wie ein USB-Installer erstellt werden kann.
Nun die zweite Option „Installationsmedien (USB-Speicherstick, DVD oder ISO-Datei) für einen anderen PC erstellen)“ auswählen und auf „Weiter“ klicken:

Jetzt die Sprache, Windows Edition (Windows 10) und die Architektur wählen und auf „Weiter“ klicken.
Normalerweise ist „Deutsch„, „Windows 10“ und „64-Bit (x64)“ als Standardwerte bereits ausgewählt.
Man kann durch das Abwählen von „Empfohlene Optionen für diesen PC verwenden“ die drei oben erwähnte Einstellungen freigeben, um z.B. die 32 (x86) Architektur zu wählen. Davon rate ich ab.

Nun muss das Installations-Medium „USB-Speicherstick“ oder „ISO-Datei“ (für DVD) gewählt werden.
Ich empfehle USB-Speicherstick (wegen oben erwehnte Gründe) zu wählen, eine leeres USB-Speicherstick mit mindestens 8 GB an PC/Notebook zu stecken (am Besten USB 2.x oder USB 3.x) und auf „Weiter“ klicken:

Nun wird eine Liste von Verfügbaren Medien (Festplatten, DVD- und USB-Laufwerke) angezeigt.
Bitte wähle jetzt dein USB-Speicherstick (Vorsicht! Nicht das falsche Laufwerk wählen!) welcher Du vorher angesteckt hast und klick auf „Weiter„:

Nun werden die Dateien für den Windows-10-Installer heruntergeladen. Je nacht Internetgeschwindigkeit kann dies mehrere Minuten dauern:

Wenn die Meldung „Der USB-Speicherstick ist bereit.“ angezeigt wird, kann man nochmal sehen auf welchem Laufwerk (in Beispiel-Bild „D:\„) der Windows-10-Installer sich befindet.
Jetzt auf „Fertig stellen“ klicken:

Nun wird für kurze Zeit eine Meldung über die Bereinigung angezeigt und das Fenster schließt sich selbst.
Wir sind mit der Erstellung von Windows-10-Installations-USB fertig.
Nuget & Specification
Hier ein Beispiel für die Nuget Spezifikations-Datei „lib.name.nuspec“ (*.nuspec):
<?xml version="1.0" encoding="utf-8"?> <package> <metadata> <id>ACME.API</id> <version>1.2.3.4</version> <authors>John Doe</authors> <owners>ACME LTD</owners> <description>This API for applications provides this and that.</description> <language>en-US</language> <projectUrl>http://www.amce.com/projects.html/#acme_api</projectUrl> <licenseUrl>http://www.acme.com/projects.html/#license</licenseUrl> <iconUrl>http://www.acme.com/acme_api.png</iconUrl> <tags>acme api this that another tags separated by spaces</tags> <dependencies> <!-- ACME.API needs lib1.name with exact version 1.2.3.0 --> <dependency id="lib1.name" version="[1.2.3.0]" /> <!-- ACME.API need lib2.name with version equal or higher 1.1.2.2 --> <dependency id="lib2.name" version="1.1.2.2" /> </dependencies> </metadata> <files> <file src="acme.api.dll" target="lib\acme.api.dll" /> <file src="acme.api.xml" target="lib\acme.api.xml" /> <file src="acme.api.pdb" target="lib\acme.api.pdb" /> </files> </package>
Damit aus einem *.nuspec Datei ein Nuget-Package entsteht kann man noch ein Batch-Script wie dieser verwenden:
// Alle "target" Dateien zum Zielverzeichnis kopieren // CLI Nuget Befehl für die Ausführung aufrufen und den Pfad zum Zielverzeichnis angeben
Mehrfache Starts von Anwendungen kontrollieren
Manchmal kommt es vor, dass man die mehrfachen Starts von Anwendungen unterbinden will, damit die Anwendung pro User nur einmal gestartet wird. Anders formuliert: Die Anwendung soll nicht parallel pro User gestartet werden können.
Hier hilft der Mutex, wie im Beispiel-Code unten. Durch die Vergabe von spezieller Name kann global auf einem Rechner, die Anzahl der parallel laufende Anwendungs-Prozesse limitiert und kontrolliert werden:
using (Mutex mutex = new Mutex(false, "MyVerySpecialPrefix0815\\" + GUID_OF_MY_APP)) { // see: https://docs.microsoft.com/en-us/dotnet/api/system.threading.waithandle.waitone?view=net-5.0#System_Threading_WaitHandle_WaitOne_System_Int32_System_Boolean_ if (!mutex.WaitOne(0, false)) { DialogManager.ShowWarning("An instance of ACME application is running!", "Running multiple instances of this application is not allowed!"); } }
WPF: externe Style Dateien dynamisch laden
Bei manche Anwendungen kommt es vor, dass man z. B. für bestimmte Kunden, Dinge wie Schrift-Art/-Größe, Farben, Dimensionen, Bilder, Icons etc. einfach und leicht („low ceremony“) ändern möchte, ohne den Quellcode jedes Mal zu ändern.
Dies erreicht man, indem man diese „Styles“ in einer externer „Styles.xaml“ Datei auslagert, zur Laufzeit, noch bevor das Hauptfenster erzeugt wird, ladet, und damit alle oder teile der Styles überschreibt. Vorausgesetzt die „Styles“ Datei ist als Ressource, also als Datei in dem Anwendungs-Verzeichnis deklariert (siehe Properties) und zu finden.
private void LoadCustomStyles() { if (File.Exists("CustomStyles.xml")) { try { using (var fileStream = new System.IO.FileStream("CustomStyles.xml", FileMode.Open, FileAccess.Read, FileShare.Read)) { var dictionary = (ResourceDictionary)System.Windows.Markup.XamlReader.Load(fileStream); Application.Current.Resources.MergedDictionaries.Clear(); Application.Current.Resources.MergedDictionaries.Add(dictionary); } } catch(Exception ex) { Logger.Error(ex); } } }
Dabei könnte die „CustomStyles.xaml“ Datei folgende Dinge enthalten:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:clr="clr-namespace:System;assembly=mscorlib" xmlns:logo="clr-namespace:Acme.Application.Icons" mc:Ignorable="d"> <ResourceDictionary.MergedDictionaries> <!-- Loading styles from a library --> <ResourceDictionary Source="pack://application:,,,/Acme.Some.Library;component/Styles.xaml" /> </ResourceDictionary.MergedDictionaries> <!-- Defining a string --> <clr:String x:Key="PathToSomeIcon">../Icons/file.png</clr:String> <!-- Defining an image --> <Image x:Key="ImageCompanyLogo" Source="pack://application:,,,/Icons/acme_logo.png" Width="100" Height="120" /> <!-- Defining a brush --> <SolidColorBrush x:Key="BrushForBorders" Color="#FFB400" /> <!-- Defining a color --> <Color x:Key="Color1">#FFABCDEF</Color> <Color x:Key="Color2">#FF123456</Color> <!-- Defining a linear gradiant --> <LinearGradientBrush x:Key="BorderWithGradiant" EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="{DynamicResource Color1}" Offset="0" /> <GradientStop Color="{DynamicResource Color2}" Offset="0.5" /> <GradientStop Color="{DynamicResource Color1}" Offset="1" /> </LinearGradientBrush> <!-- Defining style for specific control --> <Style x:Key="MySpecialLabel" TargetType="{x:Type Label}"> <Setter Property="Background" Value="White"/> <Setter Property="FontSize" Value="16"/> <Setter Property="FontWeight" Value="Bold"/> <Setter Property="Margin" Value="5"/> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="HorizontalAlignment" Value="Center"/> </Style> </ResourceDictionary>
Anwendungen & Unhandled Exceptions
Es kommt vor, dass in einer Anwendung Ausnahmefehler (Exception), aus welchem Grund auch immer, nicht abgefangen und behandelt werden, was zum Absturz der Anwendung führt. Daten und stunden lange Arbeit können dabei verloren gehen, was den Anwender verärgern kann, und alles andere als schön ist.
Es gibt jedoch die Möglichkeit diese Ausnahmefehler abzufangen, um zumindest die Daten oder die Arbeit zu speichern, um danach die Anwendung automatisch wieder neu-starten oder zumindest ein Entschuldigungs-Dialog anzuzeigen.
Dazu gibt es 3 Ereignisse (Events) die einem über eine nicht-abgefangene Fehler informieren:
- AppDomain.UnhandledException
- Application.DispatcherUnhandledException
- TaskScheduler.UnobservedTaskException
In einer WPF-Anwendung kann man wie folgt alle nicht-abgefangene Exceptions abfangen und behandeln, oder zumindest loggen:
/// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : Application { /// <summary> /// 1st called method. /// </summary> /// <param name="e"></param> protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); _MyApp = new AcmeApplication(); AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.UnhandledException += OnUnhandledException; DispatcherUnhandledException += OnUnhandledDispatcherException; TaskScheduler.UnobservedTaskException += OnHandledTaskException; } private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) { Logger.Fatal(sender, e.ExceptionObject); // ... save data, restart, or shutdown. } private void OnUnhandledDispatcherException(object sender, DispatcherUnhandledExceptionEventArgs e) { Logger.Fatal(e.Exception); e.Handled = true; // ... save data, restart, or shutdown. } private void OnHandledTaskException(object sender, UnobservedTaskExceptionEventArgs e) { Logger.Fatal(e.Exception); e.SetObserved(); // see: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.unobservedtaskexceptioneventargs?view=net-5.0 } }
Abstract Value Converter
Für WPF einen Konverter (IValueConverter) zu schreiben ist relativ einfach.
Einen Konverter zu schreiben, welcher dann in XAML Werte zugewiesen werden können, ist etwas schwerer.
Ich habe einen abstrakten Konverter geschrieben, welcher es ermöglicht, darauf basierend, komplexere Konverter zu schreiben zu können, welche dann direkt in XAML statische oder dynamische Parameter annehmen können.
Eine besondere Rolle hat der „Dummy Rectangle“. Dieser wird missbraucht, um während der Laufzeit festzustellen, ob die Methoden der Klasse während der Design time oder Run time aufgerufen wurden.
using System.Runtime.CompilerServices; using System.Windows.Data; using System.Windows.Markup; public abstract class AValueConverter : MarkupExtension, IValueConverter { protected static System.Windows.Shapes.Rectangle m_Dummy; static AValueConverter() { m_Dummy = new System.Windows.Shapes.Rectangle(); } [MethodImpl(MethodImplOptions.NoInlining)] public abstract object Convert(object pValue); [MethodImpl(MethodImplOptions.NoInlining)] public virtual object Convert(object pValue, Type pTargetType, object pParameter, CultureInfo pCulture) { return Convert(pValue); } [MethodImpl(MethodImplOptions.NoInlining)] public override object ProvideValue(IServiceProvider pServiceProvider) { return this; } [MethodImpl(MethodImplOptions.NoInlining)] public virtual object ConvertBack(object pValue, Type pTargetType, object pParameter, CultureInfo pCulture) { throw new InvalidOperationException($@"This AValueConverter inheritor: ({GetType().Name}) does not support converting types backward!"); } }
Auf dem AValueConverter kann nun, zum Beispiel ein Bool-To-Color-Converter realisiert werden:
using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Media; public class BoolToColorConverter : AValueConverter { public Brush FalseBrush { get; set; } = Brushes.Red; public Brush TrueBrush { get; set; } = Brushes.Green; [MethodImpl(MethodImplOptions.NoInlining)] public override object Convert(object pValue) { if (DesignerProperties.GetIsInDesignMode(m_Dummy)) { return FalseBrush; } if ((bool)pValue) { return TrueBrush; } else { return FalseBrush; } return FalseBrush; } }
Oder zum Beispiel einen Bool-To-Visibility-Converter:
using System; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows; public class BoolToVisibilityConverter : AValueConverter { public Visibility FalseVisibility { get; set; } = Visibility.Hidden; public Visibility TrueVisibility { get; set; } = Visibility.Visible; [MethodImpl(MethodImplOptions.NoInlining)] public override object Convert(object pValue) { if (DesignerProperties.GetIsInDesignMode(m_Dummy)) { return Visibility.Visible; } if ((bool)pValue) { return TrueVisibility; } else { return FalseVisibility; } return FalseVisibility; } }
Diese Konverter können nun in XAML wie folgt (in Bindings) verwendet/aufgerufen werden:
xmlns:conv="clr-namespace:Path.To.ValueConvertersNamespace" ... Property="{Binding ElementName=WpfElement, Path=Property, Converter={conv:BooleanToVisibilityConverter}}"
ObservableList
ObservableList<T>
erweitert ObservableCollection<T>
mit nützlichen Methoden, um einfach mehrere Elemente in die Collection hinzufügen oder entfernen.
Anwendungs-Beispiele:
var items1 = new string[] { "a", "b", "c" }; var items2 = new string[] { "x", "y", "z" }; var items3 = new string[] { "1", "2", "3" }; // Adds a, b, c to the end of collection. Items.InsertItemsAtEnd(items1); // Adds x, y, z to start of collection. Items.InsertItemsAtStart(items2); // Adds 1, 2, 3 to indices 3, 4 and 5. Items.InsertItemsAt(3, items3); // Removes first 4 elements from collection. Items.RemoveItemsFromEnd(4); // Removes last 4 elements from collection. Items.RemoveItemsFromStart(4); // Adds Hello and World to the end of collection. Items.AddRange(new string[] { "Hello", "World!"});
Implementierung von ObservableList<T>:
public class ObservableList<T> : ObservableCollection<T> { public virtual void RemoveItems(IEnumerable<int> pIndices) { foreach (var i in pIndices) RemoveItem(i); } public virtual void RemoveItemsFromStart(int pCount) { while (Count > 0 && pCount > 0) { RemoveAt(0); pCount--; } } public virtual void RemoveItemsFromEnd(int pCount) { while (Count > 0 && pCount > 0) { RemoveAt(Count - 1); pCount--; } } public virtual void InsertItemsAt(int pIndex, IEnumerable<T> pItems) { foreach(var item in pItems) InsertItem(pIndex++, item); } public virtual void InsertItems(IEnumerable<T> pItems) => InsertItemsAt(Count, pItems); public virtual void InsertItemsAtStart(IEnumerable<T> pItems) => InsertItemsAt(0, pItems); public virtual void InsertItemsAtEnd(IEnumerable<T> pItems) => InsertItems(pItems); public virtual void AddRange(IEnumerable<T> pItems) => InsertItems(pItems); }
Firefox Browser Add-ons
Hier werden die Add-ons (auch Plug-ins genannt) für Firefox aufgelistet, welche den Browser um nützliche Funktionalitäten erweitern.
Werbung blockieren und Surfverhalten vor Dritte schützen:
- Nie wieder Werbung auf YouTube 🙂
- Surf-Geschwindigkeit verdoppeln
- Download von Daten reduzieren (da Werbe-Bilder/-Videos nicht geladen werden)




Wörter, Texte oder ganze Webseite übersetzen, Synonyme, Bedeutung udg.:



Multimedia:



Sonstiges:

Kein Signal!
Wenn URLs, Links und Anklickbare Benutzerschnittstellen, nicht eindeutig als solches (Signalstärke) angezeigt werden:
Gerade wollte ich meine Ubuntu Installation auf Windows 10 (WSL) zurücksetzen, und habe nach den anklickbaren Text „Erweiterte Optionen“ gesucht. Kein Wunder, dass meine Suche etwas gedauert hat.

Bei Discounter Fotos ausdrucken
Heute war ich bei einem Discounter für: Hygiene-Artikel, Wasch- und Putz-Mittel und der gleichen.
Ich wollte „einfach und schnell“ ein paar Fotos, die ich mit meinem Smartphone gemacht hatte auf Fotopapier ausdrucken lassen. So wie es die Werbung versprach.
Ich ging zum Automat.

Da ich ein IT-Sicherheits-Fanatiker bin, wollte ich meinem Smartphone nicht mit Malware über USB verseuchen.
Also entschied ich mich für Bluetooth.

Ich befolgte die Anweisungen auf dem Bildschirm, Punkt für Punkt.
Ich wählte das Gerät „CEWE-XXXXXX“ wie auf dem Bildschirm des Automaten angezeigt.
Und siehe da!

Es funktionierte NICHT!
Ich probierte eine Zeit lang herum, schaltete mein Bluetooth aus und wieder ein, nach dem AEG-Prinzip (Ausschalten, Einschalten, Geht wieder) … schaute mir Minuten lang die Einstellungen von meinem Smartphone, und suchte nach irgend eine Einstellung, die Falsch wäre. Ohne Erfolg.
Nun gab es dort, einen zweiten Foto-Print-Automaten. Ich dachte mir, ich probiere der zweite Automat aus. Das gleiche Problem!
Notgedrungen, wählte ich diesmal die USB-Methode aus. Es funktionierte. Gleich danach, ließ ich mein Anti-Virus-Programm updaten und startet eine vollständige Suche nach Malware.
„Einfach & Schnell“ …
Jemand sagte mir mal: „Die Geschäftsleute haben schon immer das verkauft, was sich die Techniker immer gewünscht haben.“
Teamwork
Software-Entwickler die immer in Teams gearbeitet haben, sind besser als jene die ausschließlich alleine Programmiert haben. Warum?

Weil:
- Vier Augen sehen mehr als zwei. Sechs Augen sehen mehr als vier, usw. usf.
- Zwei Köpfe denken mehr als einem Kopf. Drei Köpfe denken mehr als zwei usw. usf.
- Ideen: die Kollegen haben manchmal bessere Ideen
- Schneller ans Ziel kommen 1: ein Kollege kennt schon die Lösung zu einem Problem
- Schneller ans Ziel kommen 2: die Arbeit kann aufgeteilt werden
- Code-Review: die Kollegen von Team machen einem auf die Fehler udg. aufmerksam. Man lernt, und bessert sich.
- Lernkurve: in Team lernt man viel mehr Dinge in viel kürzere Zeit
- Erfahrung: ein Kollege hat bereits Erfahrung mit XY und teilt diese
- Disziplin: um mit den Anderen am gleichen Code, Komponenten etc. zu arbeiten, muss man sich an bestimmte interne Standards, Regeln und Vorschriften einhalten (Naming, Coding, Commenting, Code-Style, Versioning, Change-Logs, Git/Subversion Commits, Packaging, …)
- Bessere, solidere APIs und Code: kein Team-Mitglied kann Ad hoc Signaturen ändern, Dinge umbenennen oder zu verschieben („Rambo-Programmierung“). Jedes Team-Mitglied ist gezwungen:
- mit den Anderen zu Kommunizieren (Vorgänge absprechen)
- sich Dinge (Namen, Kommentare, Algorithmen etc.) vorher sehr gut überlegen, da die Anderen ihren Code auch ändern müssen
- Schnellere Erfolgserlebnisse in viel kürzere Zeiten: da Einzelteile schneller entwickelt werden, hat man in viel kürzeren Zeitabständen Erfolgserlebnisse. Als Einzelkämpfer dauert es viel länger, um ein Teil-Erfolg zu feiern.
- Motivation: Erfolgserlebnisse in kurzen Zeitabständen motivieren (Erfolgserlebnisse in sehr langen Zeitabständen demotivieren!)
- Es macht mehr Spaß!
- Man entwickelt sich weiter: Ein Entwickler in ein N-köpfiges (N > 1) Team vermehrt, vertieft und verbessert seine Fähigkeiten, Kenntnisse, Können und Still mit Faktor N in gleicher Zeitraum als der Einzelkämpfer
Java Virtual Machine
Untertitel: Sprache, Konzept, Architektur
Von Matthias KALLE DALHEIMER
O’REILLY Verlag, ISBN 3-930673-73-8
Der Autor erklärt in diesem Buch, dass Java nicht nur eine Programmiersprache, sondern eine Sammlung verschiedene Paradigmen und Konzepte ist, zählt einige auf und erklärt interessante Details und die Geschichte dazu:
- Die Java Umgebung: Bestandteile, Compiler, Interpreter, Virtual Machine sowie Java-Besonderheiten
- Java Virtual Machine: Datentypen, Register und lokale Variablen, Laufzeit-Umgebung, Heap und Stack, die Sprache der VM (Code-Verwaltung und Befehlssatz)
- Aufbau einer
*.class
Datei - Sicherheitskonzepte: Rechner-Sicherheit, Sicherheit durch Sprach-Design und den Compiler sowie die Überprüfung des Byte-Codes, Trennung in Namensräume, Security Manager und Probleme der Java-Sicherheit
Das Buch eignet sich (vor Allem) für alle Java-Anfänger und Aufsteiger, bietet mehr Einblick unter die Haube, sorgt für „Aha!“ Momente, und führt zu ein besseres Verständnis womit man effizienter und besser Java programmieren kann.
Enthält außerdem einige lustige „Fun Facts“, wie zum Beispiel der Code Point für Klassen-Erkennung: 0xcoffeebabe (Coffe Babe) 😉
Sich in die Arbeit eines Profis einmischen
Was passiert, wenn jemand, der irgendwann mal Code geschrieben hat, jedoch von Software-Engineering kaum eine Ahnung hat, sich in die Arbeit von professionellen Software-Entwicklern einmischt und für denen Entscheidungen trifft?
Gegenfrage 1: sagt er jeden Tag dem Schulbus-Chauffeur, der seine Kinder zur Schule fährt, wie er den Bus zu fahren hat, wann und wo er abbiegen oder anhalten muss, nur weil er einen Führerschein hat und mit seinem Auto fährt?
Gegenfrage 2: geht er jedes Mal, wenn er in Urlaub fliegt ins Cockpit, und sagt den Piloten wie diese zu Fliegen/Landen haben, nur weil er mal als Kind Drachen (Kite) in die Luft steigen lassen hat, oder ob und zu mit seinem Quadrocopter spielt?
Fazit: Lieber Chefs/CEOs/CFOs/Manager; Bitte seid Restaurant-Gäste! Gebt eure Bestellung auf! Lasst euch bedienen, denn der Koch weiß wie er zu Kochen hat.
Anders formuliert: lasst Profis ihre Arbeit machen! Sagt denen WAS das Ding tun soll und nicht WIE sie dieses Ding machen sollen.
Software-Engineering, gut gedacht vs. gemacht
Gute vs. Schlechte Software-Engineering
Eigenschaften von gutem Software-Engineering:
- Man nimmt sich genug Zeit fürs Vordenken, Analysieren, Recherche, Review, Planen und Einteilen der Aufgaben + Meilensteine + Abhängigkeiten
- Anforderungsanalyse hat keine Lücken, enthält ausschließlich feste, genau, eindeutig definierte Formulierungen
- Es gibt ein Pflichtenheft speziell für die Software-Entwickler (es gibt keine offenen Fragen von Software-Entwickler nach Projekt-Beginn)
- Abhängigkeiten, Risiken udg. werden abgewogen und verwaltet.
- Architektur-, Komponenten- und API-Design wurden genauestens überlegt und entworfen (kein Reengineering danach notwendig)
- Man plant Tests: Was, Wann, Worauf, Wie und Womit wird getestet
- Wenn Kunden sich Kleinigkeiten wünschen, kann das sofort und in kurze Zeit erledigt werden (keine Staatsaffäre)
- Projekt ist sehr wirtschaftlich, man macht satte Gewinne
- SW Komponenten können 1:1, oder mit geringer Anpassung, für weitere Projekte verwendet werden
- Die Software-Komponenten haben eine sehr hohe Qualität
- Die SW-Dokumentationen behalten für sehr lange Zeit (Jahre) ihre Gültigkeit

Eigenschaften von schlechte/mangelhafte/nicht-Existenz von Software-Engineering:
- Man nimmt sich kaum Zeit fürs Vordenken, macht kaum Analysen, recherchiert wenig/kaum, lässt keine Reviews machen, plant grob/falsch, Einteilung und Verteilung der Aufgaben passiert Ad hoc nach dem Projekt-Beginn (während Implementierung, (Pseudo-)Testung etc.
- Anforderungsanalyse hat große Lücken und ist sehr schwammige, offene, mehrdeutig interpretierbare Formulierungen
- Es gibt kein Pflichtenheft für SW Entwickler! Man nimmt das gleiche Pflichtenheft für Kunde und gibt es Software-Entwickler.
- Über Abhängigkeiten und Risiken hat man sich kaum oder gar keine Gedanken gemacht, geschweige dessen Abschätzung oder gar Verwaltung
- Architektur-, Komponenten- und API-Design entstehen nach Projekt-Beginn, währen Implementierung, und deshalb muss immer wieder Reengineering und Redesign betrieben werden
- Tests werden nicht geplant. Test-Units entstehen während, oder gar am Ende der Implementierung, müssen immer wieder ergänzt und/oder „angepasst“ werden („Was nicht passt, wird passend gemacht!“). Zum Testen spielt ein Mitarbeiter so lange herum, bis vielleicht irgendwas nicht so läuft, wie man will, oder irgendwas sich ergibt/zeigt …
- Gott bewahre, ein Kunde wünscht sich eine Kleinigkeit. Das kommt eine Staatsaffäre gleich. Es ist so als ob Mount Everest versetzt werden muss. Kein Byte bleibt auf dem Anderen. Jedes Bit wird umgedreht. Reengineerings nach Reengineerings. Überstunden werden notwendig. Andere Projekte werden die Entwickler entzogen … Die Kosten/LOC explodieren!
- Das Projekt wirft, wenn überhaupt, gerade noch, ein paar Euros als Gewinn ab, oder die Fa. muss sogar Pönale zahlen
- Verärgerte Kunden beschweren sich immer wieder über Bugs/Fehler (Man hat denen Bananaware verkauft), Folge-Projekte bleiben aus
- Die SW-Komponenten haben kaum, oder sehr geringe Qualität
- Die SW-Komponenten müssen für weitere Projekte grob verändert, oder gar neugeschrieben werden
- Änderungen an eine Software-Komponente zwingt die Änderung viele andere Software-Komponenten (Domino-Effekt)
- SW-Dokumentationen (falls vorhanden), verlieren ihren Wert, da sich viel zu viel geändert hat, und müssen um oder komplett neugeschrieben werden

„Bei uns wird Qualität großgeschrieben“
Das kann jeder (behaupten). Man muss nur „CAPS Lock“ (Feststelltaste) drücken und danach „qualität“ tippen. Ergebnis: „QUALITÄT“.
Qualität ist eine Einstellung und Haltung. Ständig! Bei jeder Gedankengang und jede Handbewegung! Von Anbeginn bis zum Ende.
Flache Hierarchie
Ad hoc, ist keine flache Hierarchie!
Sofort zur Tastatur greifen, ist keine flache Hierarchie!
Chaos ist keine flache Hierarchie!
Jeder ist für tausend Dinge zuständig, ist keine flache Hierarchie!
Jeder tut, was er/sie will, ist keine flache Hierarchie!
Ständig im Fluss der Gedanken unterbrochen werden (Telefon, E-Mail, Meeting, Kollegen im Stress, …), ist keine flache Hierarchie!
Agile ist keine flache Hierarchie!
SCRUM ist keine flache Hierarchie! (Theorie zur „Flat Hierarchy“ wurde 1963 in USA von einem Ökonomen erfunden)
Mangel an Projekt-Verwaltung ist keine flache Hierarchie!
Mangel an Riskmanagement ist keine flache Hierarchie!
Mangel an Ressourcen-Planung ist keine flache Hierarchie!
Schlechtes, unvollständiges Pflichtenheft mit schwammigen Formulierungen, ohne Review, ist keine flache Hierarchie!
Mangel an Anforderungsanalyse ist keine flache Hierarchie!
Flache Hierarchie wird chaotischer gegessen als gekocht!
Warum wendet keine Armee der Welt, die flache Hierarchie? Bei Militär sind Effizienz, Geschwindigkeit und Befehlskette extrem wichtig. Warum haben sie keine flache Hierarchie?
Agile
Ad hoc, ist nicht Agile!
Sofort zu den Tastaturen greifen, ist nicht Agile!
Chaos ist nicht Agile!
Jeder macht sofort irgendwas/alles, ist nicht Agile!
Wenn alle 11 Fußballspieler eines Teams hinter dem Ball herlaufen, ist nicht Agile!
Agile wird meistens agiler gegessen als gekocht!
Simulator
Die Vortäuschung, die Verstellung, von lat. simulatio: die Verstellung, die Heuchelei, die Täuschung, das Vorschützen (eines Sachverhalts), die Vorspiegelung, der Vorwand, Die Vorschiebung; lat. similis: ähnlich, gleichartig, gleich.
Eine Simulation gaukelt das Vorhandensein von Etwas, das nicht da ist.
Ein Simulator (Software), vor allem „Dummy“ Simulator, spart auf langer Sicht, Unmengen an Raum, Zeit, Energie, Kabel, Konfigurationen, Installationen etc. etc. und Kosten. Ein Simulator macht einem unabhängig von realem Ding, und man kann sich auf seine Business-Logik konzentrieren.
ACHTUNG: Natürlich sollte irgendwann mal die Software (Business Logik) mit dem echten Ding auch auf Herz und Nieren getestet/geprüft werden, bevor es geliefert wird, oder ins Produktions-System eingesetzt wird!
Modelle
Ein Modell ist eine stark reduzierte, abstrakte Abbildung der Wirklichkeit. Es ist absichtlich unvollständig.
„In jenem Reich erlangte die Kunst der Kartografie eine solche Vollkommenheit, dass die Karte einer einzigen Provinz den Raum einer Stadt einnahm und die Karte des Reichs den einer Provinz. Mit der Zeit befriedigten diese maßlosen Karten nicht länger, und die Kollegs der Kartografen erstellten eine Karte des Reiches, die die Größe des Reiches besaß und sich mit ihm in jedem Punkte deckte.“
(Jorge Luis Borges, „Von der Strenge der Wissenschaft“ in: Universalgeschichte der Niedertracht und andere Prosastücke, Ffm-Berlin-Wien, ISBN 978-3548029146)
Diagramme
„Ein Bild sagt mehr als tausend Worte.“ (deutsches Sprichwort)
Das falsche Bild sagt mehr als tausend falsche Worte.
Was ist ein Software-Entwickler oder Techniker der Nichts dokumentiert für eine Firma?
Kurz: Heroin!
Er/Sie macht die Kollegen und die Firma von sich abhängig.
Was passiert, wenn:
- Dieser Kollege die Firma verlässt?
- Er längere Zeit krank ist?
- Er in Pension geht oder stirbt?
Können andere Kollegen die Köpfe zusammenstecken und herausfinden wie seine Komponenten funktionieren? Wie diese sich verhalten oder zu benutzen seien? Oder müssen die Komponenten (die eigenen Produkte der Firma) mithilfe von Reverse-Engineering auf Funktionsweise analysiert werden? Müssen diese Neu/nochmal (von null auf) entwickelt werden?
Muss der gesamte Code gelesen und verstanden werden?
Was kostet die Dokumentation an Zeit und Geld für eine Firma? (A)
Was kostet das Reverse-Engineering des eigenen Produktes + dessen Neu-Entwicklung und/oder lesen des gesamten Codes? (B)
Welche Kosten sind höher: A oder B?
Welche (A oder B) bringt größere, längere und teurere Kaskadeneffekte (Zeitpläne und Ressourcen-Teilung/-Planung, Fertigstellungs-Termine bei parallel laufenden Projekte) mit sich?
Welche (A oder B) bringt die Termine durcheinander, sorgt/stiftet/produziert Chaos, macht Kunden unzufrieden?
Wer zahlt für die entstandene Kosten und Ressourcen-Verbrauch für die Entwicklung eines Produktes das nicht verwendet/eingesetzt werden kann?
Wer zahlt für die entstandene Überstunden bei B?
Wer zahlt für die entstandenen Pönalen/Vertragsstrafen durch B bei N andere Projekte?
Hier eine einfache Milchmädchen-Rechnung (+Diagramm) für besseres Verständnis:
Naive Annahmen:
1. wir leben in einer perfekten Welt (Nichts geht schief, man muss auf Nichts warten, es gibt keine Bugs, niemand wird Krank, keiner nimmt sich Urlaub, … es gibt keine negativen Überraschungen)
2. die Projekte sind voneinander unabhängig und dauern alle gleich (exakt, nur 30 Tage)

Wie man aus dem Diagramm (für eine „perfekte“ Welt) sieht: Die Fertigstellung jedes Projekts verschiebt sich um 15 Tage (Dauer der Neuentwicklung von Komponente/System des Projekts ganz oben) um 15 Tagen nach hinten!
Das bedeutet für alle N Projekte: N × 15 Tage.
In unserem Beispiel, bei 3 Projekten, bedeutet das 45 Tage (eineinhalb Monate) insgesamt.
Wir leben aber in keine perfekte Welt!
1. Manche Projekte sind voneinander abhängig (Projekt A ist von Projekt B abhängig, und Projekt B ist von Projekt C abhängig, usw.): A ⇒ B ⇒ C ⇒ …
2. Krankheit, Urlaub, Todesfall
3. Verzögerung durch Bugs (z. B. Memoryleak)
4. zuständiger Fachexperte für XYZ, der Mitarbeiter X, ist auf einer Baustelle von einem Kunden in Land Y und kommt erst in einer Woche zurück
5. Wegen Covid-19, einem Schiff das in Suezkanal feststeckt, Produktionsverzögerung, Lieferschwierigkeiten für eine Hardware-Komponente, kann man Projekt XY nicht fertigstellen oder testen
6. Die Firma VUDU wird an Firma CONYAK verkauft und ändert die Lizenzierungen für das KI-System von VUDU. Das System muss nun ersetzt werden, oder darauf muss komplett verzichtet werden
7. Es stellt sich in reale Umgebung (Prototyp-System) heraus, dass externes/gekauftes System XYZ für die Aufgabe ABC ungeeignet ist oder dessen Laufzeitkomplexität viel zu hoch als erwartet ist (z. B. Taktzeiten können nicht eingehalten werden, in zeitkritischen Systemen werden harte Zeitschranken durchbrochen)
8. Es wurde aufgrund falscher Annahme(n) viel Code geschrieben, jedoch bei Developer-Tests stellt man am Ende fest: XYZ ist gar nicht imstande ABC zu tun
10. Unterschiedliche Softwareentwickler arbeiten an unterschiedliche Projekte und haben von andere Projekte, dessen Lösungsansätze, Paradigmen und/oder Konzepte keine Ahnung
11. Es gibt Spezialisten für Teilbereiche, nicht jeder kann alles, was der Andere kann. Der Spezialist wird aber für Projekt X benötigt und kann sich nicht auch noch um andere Projekte (Aufgaben) gleichzeitig kümmern
12. Der Tester bzw. die Test-Abteilung muss sich zuerst um Projekt X kümmern. Projekt Y muss warten bis es zum Testen dran ist
13. … und vieles mehr

Wie man in obigem Diagramm sieht:
Die Neuentwicklung des Komponenten/Systems (ganz oben) verursacht enorme Chaos und Verzögerung in Projekt 1, was wiederum enorme Chaos und Verzögerung bei Projekt 2 verursacht.
Da das Projekt 3 von Projekt 2 abhängig ist, braucht man sich nicht wundern, dass die Entwicklung dessen erst nach dessen Liefertermin gestartet werden kann. Obwohl für die Liefertermine für jedes Produkt 10 Tage als Puffer geplant waren (was ich in der Realität leider noch nie erlebt habe!).
Das ist die Folge von: Nichts dokumentieren (weil „die Kunden nicht fürs Dokumentieren Zahlen“).
Welche Bedeutung hat „Bei uns funktioniert es.“ für Kunden?

Kurz: Nichts/keine!
Warum?
Dazu folgende (wahre) Geschichte:
Es gab mal eine kanadische Firma namens AECL (Atomic Energie of Canada Limited), welche medizinische Bestrahlungsgeräte baute. Unter anderem das Therac 25.
Das A und O der Bestrahlungsgeräte lautet: Soviel Strahlung wie nötig, so wenig wie möglich!
Immer wieder kontaktierten Mediziner die Firma AECL und beklagten sich über Bestrahlungsüberdosen.
Von der Firma AECL kam stets die gleiche Antwort: „Bei uns funktioniert es“ und „Es muss an euch liegen“.
Mehrere (mind. drei) Patienten sind wegen Bestrahlungsüberdosis durch Therac 25 ums Leben gekommen.
Einige Patienten verloren ihre Glieder nach Not-Amputationen (direkt nach Bestrahlungsüberdosis durch Therac 25), weil das Gewebe an bestrahlte Stelle komplett verbrannt war (= totes Fleisch!).
Einige Patienten könnten nie wieder ihre Extremitäten (Hand, Arm, Fuß, Bein) bewegen oder spüren, da die Nerven durch die Bestrahlungsüberdosis komplett verbrannt waren (= tote Nervenzellen!). Z. B. Marietta, eine 61-jährige Frau aus Georgia, wurde wegen Lymphknoten in 1985 mit 15000Rad statt 200Rad (75-fach höhere Dosis) bestrahlt. Sie könnte nie wieder ihre Schulter oder Arm bewegen oder spüren.
Die Entdeckung der Fehler:
Anmerkung: In USA müssen die Mediziner vor ihrem Medizinstudium ein technische oder naturwissenschaftliches Studium erfolgreich absolviert haben (Dipl.-Ing. früher in Österreich), sonst dürfen sie nicht Medizin studieren.
In einem Krankenhaus in USA, wurde eine Radiologin (die auch Physikstudium absolviert hatte), auf die Bestrahlungsüberdosen durch Therac 25 aufmerksam. Sie notierte die Daten der Vorkommnisse und sah ein Muster darin. Daraufhin bat sie einen Kollegen (Mediziner) der sich mit Elektronik und Computer auskannte um Hilfe.
Sie entwickelten einen systematischen Testplan, und testeten den Therac 25 gründlich. Sie haben gleich mehrere reproduzierbare Fehlverhalten festgestellt und AECL sowie die Behörden informiert. Erst jetzt wurden die Fälle von der Behörde und AECL untersucht!
Die Fehler:
Es wurden mehrere Fehler gefunden:
- Mechanischer Fehler!
- Mehrdeutige, in die Irre führende Anzeige bzw. Texte/Begriffe
- Umständliche Softwarebedienung, nicht automatisierte Kondition-Checks udg. (der User müsste auch für die Software mitdenken, vergleiche dazu TAROM-Flug371 Automatic Throttle System ATS Fehler/Schwäche!)
- Race Conditions!
- Synchronisations-Fehler (angezeigter neuer Dosis-Wert entsprach nicht den im Speicher für die Bestrahlung angewendeter Wert, d. h. alter Dosis-Wert wurde für die Bestrahlung angewendet)
- Zustands-Transitions-Fehler (die Positionierung verschiedene Magneten dauerten 8 Sekunden, die Bestrahlung wurde aber sofort eingeleitet, dadurch hatte jede Bestrahlung 8 Sekunden länger als erwartet gedauert, beginnend an falsche Position/Stelle)
- Flags wurden ignoriert (nach grobe Positionierung wurde die Feinpositionierung der Magneten ignoriert)
- Fehlermeldungen waren nicht aussagekräftig, waren nicht verständlich dokumentiert, ergaben für die Anwender (Mediziner) keinen Sinn!
- usw. usw. usf.
Wie könnte das Alles nur passieren?
- Einbildung (Gehabe und Einstellungen wie: „Ich bin so super!“, „Ich bin Perfekt und alle Anderen sind Idioten“, „Ich weiß alles, alle Anderen wissen nichts“ und „Ich bin der beste Programmierer auf der Welt!“, …)
- Sätze und Glaubens-Gedanken (statt anständige Tests) wie:
- „Es funktioniert.“
- „Es hat funktioniert.“
- „Bei uns funktioniert es.“
- „Es muss an euch liegen.“
- „Software-Tests“ von AECL basierten auf Vermutungen und „Schauen wir mal, ob es so funktioniert wie wir uns gedacht haben“, anstatt auf systematische professionelle fundierte Analysen! Das Ziel deren Tests war zu beweisen, dass es funktioniert, und nicht das Finden von Fehler!
- Der neue Programmierer nutzte die SW-Komponenten des alten Programmierers (welcher AECL verlassen hatte), ohne wirklich zu wissen, wie diese Entworfen waren, und wie diese richtig einzusetzen waren (Race Conditions, Sync. Fehler, Flags-Änderungen ignorieren udg.)
- Unverantwortliche Projekt-Leiter und Manager („Hauptsache Billig!“ Manier) die über die Tragweite ihrer Entscheidungen nicht bewusst waren (und Warnungen der Techniker/Experten ignorieren): nahezu alle Hardware-Überwachungskomponenten des Vorgängermodells wurden entfernt und durch Software-Checks ersetzt (wegen höchstens einige 1000 $ Hardwarekosten haben einige Menschen ihren Leib und Leben verloren! Tolle Kostenreduzierung!)
- Bei Therac 25 wurde ein komplett neues eigenes Betriebssystem eingesetzt, welches noch jung war („Kinderkrankheiten“), Fehler enthielt und die AECL Mitarbeiter keine Erfahrungen damit hatten. Kommerzielle Betriebssysteme wären bekannt und auch länger getestet gewesen (Erfahrungswerte, Bekanntheit, Dokumentationen, …). Aber auch hier hat AECL sich „viel Kosten erspart“.
Konsequenzen:
1985-1987 wurden von FDA (Food and Drug Administration, US-Behörde) und CDRH (Center for Devices and Radiological Health, US-Behörde) weitreichende Reformen durchgeführt (Überwachung von Software-Entwicklung und das Testen, sowie Verschärfung der Freigabeprozedur für neue Geräte).
Die Moral der Geschichte:
- Hört auf zu denken/sagen „Es funktioniert“ oder „Es hat funktioniert.“
- Hört auf zu sagen „Bei uns funktioniert es.“ oder „Es muss an euch liegen.“! Davon kann der Kunde sich Nichts kaufen!
- Testet! Testet! Testet! Und zwar gründlich, analytisch, systematisch und fachmännisch. Die Aufgabe von Testen ist Fehler zu finden, und nicht zu beweisen das „es funktioniert“. Es gibt genug Paradigmen, Konzepte, Module, Best Practices, Standards und Konventionen für ein gründliches, systematisches, analytisches, fachmännisches Testen (TDD, Unit-Testing, Test-Doubles, Mocks & Fakes, Digital-Twins, Fehler-Simulatoren, …)
Welche Bedeutung hat „Es funktioniert.“ ?

Kurz: Nichts/keine.
Warum?
Dazu folgende (wahre) Geschichte:
Es gab mal eine europäische Trägerrakete namens Ariane 4. Diese hatte ein Modul namens SRI (Inertial Reference System), welches für die Berechnung der Flugbahn zuständig war. Das SRI Modul war bestens getestet. Die Mission Ariane 4 war erfolgreich (somit hatte SRI in Produktion-System „funktioniert“).
Dann baute man Ariane 5 mit stärkeren Triebwerke. Da das SRI Modul von Ariane 4 getestet und erfolgreich erprobt war, wurde es einfach in Ariane 5 eingesetzt.
Ergebnis: in Sekunde +41 nach Zündung (Ignition) wurde der automatische Selbstzerstörungsmechanismus von beiden Onboard Computern ausgelöst und zerstörte die Rakete.
Grund:
Ariane 4 Computer war ein 16 Bit System.
Ariane 5 Computer war ein 64 Bit System.
Bei der Berechnung der Flugbahn wurde ein 64 Bit Float Wert (Fließkomma-Zahl) an SRI Modul übergeben ⇒ Stack Overflow!
Die Triebwerke schlugen von der eine (IST-Wert) Richtung in das Extreme, andere Richtung (overflow SOLL-Wert).
Durch die große Masse und hohe Geschwindigkeit (Impuls, Energie) wäre Ariane 5 auseinandergebrochen, weshalb der automatische Selbstzerstörungsmechanismus die kontrollierte Sprengung ausgelöst hat.
Wie man sieht: „Es funktioniert.“, oder „Es hat funktioniert.“ bedeutet rein gar Nichts!
Fun Fact 1:
Nach Sekunde +36 war eine Berechnung der Flugbahn durch das SRI Modul gar nicht notwendig gewesen, und hätte somit von „Haupt-Computern“ abgeschaltet werden können.
Fun Fact 2:
Die Herstellungskosten für die Rakete und die Satelliten beliefen auf ca. 500 Millionen Dollar. Da keine kommerzielle Fracht an Bord war, sondern „nur“ Forschungssatelliten, war der Flug nicht versichert worden.
Fun Fact 3:
Die Entwicklung der Rakete alleine hat 10 Jahre und 7 Milliarden Dollar beansprucht.
Resultat: 10 Jahre Entwicklungszeit + 7.500.000.000 $ wurden nach nur 41 Sekunden vernichtet, weil man sich dachte „Es hat funktioniert.“.
Wer ist ein Profi Software-Entwickler?
Ist jeder, der Zuhause kocht ein Haubenkoch?
Ist jeder der an seinem Auto/Motorrad herumschraubt ein Auto-/KFZ-Mechaniker?
Ist jeder der mit einem Lötkolben in einem Radio/Fernseher herum lötet ein Elektroniker?
Man kann ja selbst Fliesen legen und Küchenregale montieren. Ja! Klar! Aber wer macht es besser und professioneller, mit kaum fataler oder sichtbarer Fehler? Der Profi der das jeden Tag seit zig Jahren macht, oder man selbst?
Conclusio:
Nicht jeder der Code schreibt, ist auch ein professioneller Software-Entwickler!
Software-Entwickler > Programmierer > Code-Schreiber.
Code vs. Buch
Roman/Buch vs. Code/Programm lesen/schreiben:
„Jeder kann Bücher lesen. Nicht jeder der Bücher lesen kann, kann auch ein (gutes/Bestseller) Buch schreiben.
Jeder kann Code schreiben. Nicht jeder der Code schreiben kann, kann auch Code lesen.“
(Zitat von meinem geschätzten ehemaligen Kollege Manfred)
Damit man ein gutes Buch schreiben kann, muss man viele gute Bücher gelesen haben.
Damit man guter Code schreiben kann, muss man viele (IT) Bücher sowie Code gelesen haben.
Ein Autor bzw. eine Autorin schreibt Bücher für die Leserinnen.
Ein Software-Entwickler schreibt Code für:
- Sich selbst, da er/sie es vielleicht in einem Monat oder einem Jahr wieder lesen, verstehen und ändern muss
- für seine Kolleginnen, da sie es vielleicht lesen, verstehen und ändern müssen
- für die „Nachwelt“ (neue Kolleginnen in der Zukunft, wenn man nicht mehr in der Firma ist)
- und zum Schluss für den Compiler und CPU (oder JVM, CLR oder sonstige virtuelle Maschinen)
Wenn die Dämme brechen
In jede Firma, jede Abteilung und auf jedem Tisch und in jedem Kanban-System, gibt es einen unsichtbaren Damm. Hinter dieser Damm sammelt sich ein trüber stinkender Schlamm, bestehend aus all die Fehler, falsch oder schlecht angegangene/gelöste Aufgaben, falsche Annahmen, falsche Entscheidungen, falsch (nicht)kommunizierte oder (nicht)verstandene Dinge, und all die nicht erledigte aber wichtige Dinge.
Irgendwann bricht einer dieser Dämme und der Kaskadeneffekt beginnt. Der Aufgaben-Flut zeigt nun den Schlamm, wie ein Orkan die Existenz der Luft:
- es müssen immer mehr Entwickler eingestellt werden
- die Entwickler müssen immer mehr Code von bestehenden Komponenten ändern (oder hinzufügen)
- die APIs und Framework-Komponenten ändern sich wöchentlich oder gar täglich
- die Entwickler betreiben immer wieder Reengineering
- die Entwickler müssen immer mehr Überstunden machen
- die Entwickler lesen mehr Code (Implementierung-Details) als sie schreiben (der Kunde zahlt nur fürs Schreiben!)
- die Entwickler werden täglich, ja sogar stündlich über bestimmte Bugs oder Problemen bei Kunden befragt
- die Entwickler müssen immer mehr Telefonate, E-Mails udg. beantworten, und werden dadurch in ihrem Gedanken-Fluss unterbrochen
- die Entwickler können sich nicht einmal für zwei Stunden, Zeit für tiefgründiges Nachdenken/Überlegen nehmen
- wöchentlich, täglich, ja sogar stündlich, gibt es neue Versionen
- der Compiler benötigt immer länger fürs Übersetzen (eine Sekunde ist für einen Computer eine Ewigkeit!), die Startzeit mal zwei!
- das Programm benötigt immer mehr Speicher (HDD & RAM)
- das Programm wird immer langsamer, und dadurch steigen die Wahrscheinlichkeiten für Nebeneffekte und neue (unerwünschte) Verhalten (vor allem bei komplexen, zeitkritischen Systemen)
- die benötigten PCs für die Software benötigen immer mehr CPUs (Cores)
- bei kleinen Anpassungen/Änderungen für einen Kunden, beschwert sich mindestens ein anderer Kunde über neuen Fehler (von einer Funktion, die bis dahin immer tadellos funktionierte)
- Hotline ist ständig vollbeschäftigt, muss lange Telefonate mit enttäuschten/verärgerten Kunden/User führen
- Techniker, Service-, Troubleshooting- und 3rd-Level-Support-Kollegen haben immer mehr zu tun, oder sind ebenfalls ständig beschäftigt
- man sucht immer mehr und länger nach Fehler/Bugs und unerwartetes/unerwünschtes Verhalten
- man benötigt für egal welche Tests, immer irgendwelche Hardware (SPS/PLCs, Sensoren, Netzteile, USB-Dongles, spezielles Kabel udg.) und kann diese Tests nicht durchführen, wenn das eine oder andere Hardware fehlt
- und vieles mehr
Jetzt, wo der Damm gebrochen ist, ist man die Aufgaben-Flut ausgeliefert. Man hat keinerlei Kontrolle über die Aufgaben, wie ein Autofahrer mit über 100 km/h auf Glatteis. Ab jetzt kann man nur taktisch, Ad hoc und „husch husch“ (eher „Pfusch Pfusch“) auf die Aufgaben reagieren. Für strategisches und langfristiges Planen, Entwerfen und Programmieren, sowie dessen (Teil)Automatisierung ist es erstens zu spät, und zweitens keine Zeit da, da die Kunden warten. Das Dach brennt! Die Entwickler springen von einer dringenden Aufgabe zu Nächste, wie ein Ping-Pong-Ball. Die Entwickler laufen gestresst von einem Bugfix/Reengineering zum Anderen, wie eine Feuerwehr-Truppe die zig Brände an unterschiedlichen Orten gleichzeitig löschen muss.
Die Kosten steigen. Für neue Projekte ist kaum Zeit da. Für Modernisierung (z. B. Umstieg von Windows Forms auf WPF/UWP) schon gar nicht. Ein Liefertermin nach dem Anderen wird überschritten. Die Firma beginnt nun auch noch Pönalen zu zahlen. Die Kunden sind verärgert und unzufrieden. Die Inhaber, CEOs, CFOs, Abteilungsleiter und Team-Leader sind gestresst und verärgert. Die Entwickler auch. Eine: lose-lose-lose Situation.
Man hat sich Niemals-Endende-Baustellen geschaffen.
Da kann man sich selbst gratulieren.
Sofort zur Tastatur greifen
Greift man sofort zur Schaufel, wenn man ein Haus baut?