Müssen Betriebssysteme schlauer werden, um uns vor bösen Menschen zu schützen?

Angenommen, Sie wären ein Betriebssystem (oder ein Teil davon, vielleicht das Dateisystem). Sie wären dafür zuständig, auf Befehle wie fopen (Datei öffnen), fwrite (in eine Datei schreiben) oder fdelete (eine Datei löschen) zu reagieren.

Nun haben Sie gerade die halbe Nacht bloß immer Anweisungen bekommen, immer dieselben Infos (“checking for mail … no new mail.”) in in irgendeine Log-Datei zu schreiben. Sie schlafen schon fast ein vor Langeweile, da kommen mit einem Mal zig Anweisungen in kurzer Folge hintereinander: Jemand lässt sich erst den ganzen Verzeichnisbaum ermitteln, um dann jede Datei darin einmal komplett zu lesen und durch scheinbar zufällige Bytes zu ersetzen.

Wenn Sie ein halbwegs wacher und informierter Mensch wären, würden sie diesem Treiben Einhalt gebieten und sagen: “Mooooment! Das sieht mir nicht aus wie eine übliche, absichtliche Aktion meines Nutzers vor dem Bildschirm (der schläft normalerweise um diese Zeit), sondern eher … wie eine Ransomware-Attacke!”

So geschehen kürzlich bei einem Dienstleister einer schwedischen Supermarkt-Kette, die daraufhin ihre Filialen schließen musste. Was das kostet!

Natürlich sagen Sie sich jetzt: Wer hat denn da wieder eine Sicherheitslücke verbrochen? Aber, wie gesagt, wenn Sie schlau genug sind: Sie verweigern den Dienst. Sicherheitshalber. Sie verlangen die erneute Eingabe des User-Passworts (oder eine Zwei-Faktor-Authentifizierung).

Was ich hier vor mich hin fantasiere, ist kein neues Konzept: Ein Forschungsprojekt namens ShieldFS gibt es schon seit Jahren, scheint aber eingeschlafen zu sein. Dabei wäre es wichtiger denn je, dergleichen auf die Tagesordnung zu setzen, denn die Ransomware-Attacken werden immer schlimmer und ganz sicher nicht aufhören, wenn die Täter erstmal genug Lösegeld kassiert haben, um sich eine eigene Insel zu kaufen. Wenn man kein Gegentor kriegen will, muss die Verteidigung eben besonders tief stehen – eine Fünferkette und ein guter Torwart, direkt im Dateisystem.

Natürlich kann man einwenden: Wer von Ransomware betroffen ist, ist eh selbst schuld, weil er anfällige Systeme mit ungepatchten Sicherheitslücken verwendet. Derjenige wird auch nicht so schlau sein, ein besseres Dateisystem zu verwenden. Ja, mag sein: Aber wäre ein solches Dateisystem Standard, wäre also Sicherheit wichtiger als … sagen wir Bequemlichkeit, wäre das ein Schritt in die richtige Richtung.

Wie Spaghetti ist PHP?

Wer kennt sie nicht, die Sprache von WordPress? Laut Statistiken laufen um die 30% aller Webseiten (auch diese) auf WordPress – und damit mit der 25 Jahre alten Skriptsprache PHP (freilich vermixt mit einer gehörigen Portion HTML, Javascript und CSS). Also nicht Java, nicht C# … sondern PHP. Insgesamt kommt PHP sogar auf einen Anteil von 79% aller Webseiten, deren verwendete Plattform bekannt ist, behauptet W3Techs.

PHP – eine Sprache, die Spaghetticode geradezu herbeisehnt, denn damit können sogar Anfänger innerhalb von Sekunden dynamische Webseiten schreiben, mit Datenbank-Anbindung, Formular-Sanitychecks und haufenweise Sicherheitslücken.

Nun ja, die Situation hat sich gebessert, seit URL-Parameter nicht mehr automatisch als Variablen wie $param zur Verfügung stehen – trotzdem verleitet die Natur der Sprache zur Beimischung von HTML wie hier:

foreach($angebote as $angebot) { print "<div>$angebot</div>";}

Ups, heute leider keine Angebote:

Na ja. Kann ja mal passieren.

Hinweisen wollte ich hier eigentlich nicht auf schlechte Fehlerbehandlung, sondern auf etwas anderes: HTML-Code in String-Literalen ist aus Sicht der Entwicklungsumgebung meist irgendein Text. Folglich findet darin keine Validierung statt. Ein versehentlicher, unbemerkter Tastendruck innerhalb des Strings kann die Darstellung der Webseite komplett zerschießen, ohne dass Sie, Ihre Entwicklungsumgebung oder PHP es bemerken (klar gibt es Unit-Tests für PHP, aber ich fürchte, allzu verbreitet sind die nicht). Dass man dergleichen mit einer Template-Engine umgehen kann, die HTML- und PHP-Code in getrennten Dateien verwaltet, dürfte den meisten Lesern klar sein – aber das ist natürlich viel umständlicher und nicht so schnell fertig.

Mit strukturierter (also aufwändigerer, zukunftssicherer) Programmierung ernten Sie als Früchte eine ganze Reihe Vorteile von PHP:

  • Minimaler Footprint auf dem Server (ein paar Textdateien, nicht megabyteweise Java-Libs)
  • Hohe Performance (dank Codecache und bei schlauer Programmierung, siehe dazu weiter unten)
  • Turnaround-Zeit ist 0 (Zeit zwischen Speichern einer PHP-Datei und HTTP-Aufruf gegen localhost zum Testen)
  • Und nicht zu vergessen: Hohe Verbreitung in der Community, also ist es leicht, Unterstützung zu finden.

Fairerweise seien ein paar Nachteile genannt:

  • Vergleichsweise hoher RAM-Bedarf
  • Keine strenge Typisierung
  • Objektorientierte Programmierung leicht nervig (ich vergesse dauernd das $this->, Sie auch?)
  • Verleitet zu unsauberer Programmierung durch globale Variablen, prozedurales Coden und verschachtelte includes
  • Größere Updates erforderten in der Vergangenheit größere Umbauten (z.B. MySQL-Funktionen), so dass viele Webseiten nie upgedated wurden, weil der Aufwand nicht lohnt → eine solche radikale Update-Policy führt dazu, dass viele Nutzer ihre Systeme nicht updaten und damit Sicherheitslücken bestehen bleiben

Zur oben erwähnten “schlauen Programmierung” ein kleiner Info-Drops: Im Gegensatz zu einer Java-Anwendung, die einmal hochfahren muss, ist ein PHP-Skript zunächst einmal “stateless”, es kennt also keine globalen Daten bzw. muss sich alles selbst zusammensuchen, was es braucht. “Weniger schlaue” Programmierung würde hier bedeuten, etwaige benötigte Daten beim Start des Skripts aus Dateien oder Datenbank nachzuladen. Bei jedem Start des Skripts. Das ist natürlich ineffizient. Stattdessen können Sie den In-Memory-Cache APCU verwenden, der wie ein Key-Value-Store im RAM funktioniert und daher extrem performant ist und im Gegensatz zum ebenfalls bewährten Memcached keine externe Komponente benötigt. Wir versuchen also mal im folgenden Beispiel beim Start des Skripts, einen benötigten Wert ($words) aus dem Cache zu holen. Sollte er fehlen (also beim allerersten Start), laden wir ihn aus irgendwelchen Dateien und speichern ihn im Cache:

if(apcu_exists("words")) { 
  $words=apcu_fetch("words");
} else { 
  $words = load_words_from_file("irgendwelche_woerter.txt");
  apcu_add("words",$words);
}
// es folgt der Code, der $words benötigt

Der Performancegewinn ist erheblich, wovon Sie sich leicht selbst überzeugen können, wenn Sie Test-Requests auf ein solches Beispiel loslassen. Um auch mal mehrere Requests auf einmal abzufeuern, können Sie übrigens den Apache Benchmark ab verwenden, etwa so:

ab -c 6 -n 10000 http://localhost/test.php?input=Hurra

Mit den gezeigten Parametern führt ab 10.000 Requests gegen die übergebene Adresse aus, und zwar in 6 parallelen Threads (seien Sie fair und überlassen Sie PHP/Apache auch ein paar, meine Maschine hat 12 Kerne, daher Fifty-Fifty). Das Tool gibt dann eine ausführliche Statistik über die Performancemessung aus:

Concurrency Level: 6
Time taken for tests: 0.629 seconds
Complete requests: 10000
Failed requests: 0
Non-2xx responses: 10000
Total transferred: 1850000 bytes
HTML transferred: 0 bytes
Requests per second: 15901.99 #/sec
Time per request: 0.377 ms
Time per request: 0.063 [ms] (mean, across all concurrent requests)
Transfer rate: 2872.92 [Kbytes/sec] received

Sie sehen: Ja, auch in PHP kann man strukturiert, effizient und sauber programmieren – aber PHP zwingt Sie nicht zu Disziplin, das müssen Sie schon selber tun. Empfehlenswert sind daher z.B. im Team knackige Code-Reviews und zielführende Mikroarchitektur-Debatten, um für porentief reinen Programmierstil zu sorgen.

tl;dr: PHP ist schnell und effizient, aber passen Sie auf, dass Sie keinen Spaghettisalat produzieren.

Meetup: Code-Qualität

Am 9.6. gibt’s von mir einen tollen Online-Vortrag in Zusammenarbeit mit IT Dev Café Düsseldorf. Ich zeige tolle Beispiele aus meiner Arbeit bei Codequalitätsanalysen – und diskutiere, wie es zu bestimmten Problemen typischerweise kommt. Sagte ich schon, dass es ganz toll wird?

Nehmt teil, bringt Freunde mit, kostet nix!

Hier ist der Meetup-Link!

In eigener Sache: Android-Sample-Code-Neuzugänge

Liebe Freunde von “Android-Apps entwickeln mit Java”!

Fans spaßiger App-Bastelei!

Hurra!

Ich habe mein github-Repository um einen Haufen Beispielcode erweitert. Es handelt sich dabei durchweg um Android-Apps, die ein oder mehrere Best Practices in der Android-Entwicklung mit Java zeigen. “Best Practice” heißt natürlich: Was ich für empfehlenswert halte, die Geschmäcker sind halt verschieden. Teilnehmer meiner Trainings kennen diesen Code schon, weil ich ihnen den ausführlich erklärt habe. Jetzt können Sie nochmal draufschauen – oder sich was kopieren, ist ja alles Open Source!

Mit dabei sind Samples zu Themen wie Fragments und Master-Detail-Flow, aber auch die guten alten DialogDemos, die auch das Buch erklärt. Brandneu ist eine Demo der neuen (aktuell noch in Alpha-Version erhältlichen) CameraX-API von Jetpack. Diese wird wahrscheinlich durch irgendwelche API-Änderungen ziemlich schnell obsolet; ich kann noch nicht versprechen, ob oder wann ich sie aktualisiere.

Ebenfalls bekannt aus meinem Buch ist der Kompass, der die Nutzung des Magnetometers und einen selbst gezeichneten View demonstriert. Ferner gibt es einen MiniMiniEditor, der das Speichern von Dokumenten mit dem StorageAccessFramework zeigt. Und last but not least die 9352. Wetterfrosch-App, die die schlechteste UI aller Zeiten aber dafür auch die lehrreichste Retrofit-Implementierung der letzten 23 Minuten mitbringt. Übrigens: Für nächste Woche sind 16 Grad angesagt! Hier, schauen Sie:

Diese App ist tatsächlich sinnvoll nutzbar – also, falls Sie noch keine Lieblings-Wetterfrosch-App installiert haben, nehmen Sie doch diese!

Viel Spaß mit dem Code. Beachten Sie bitte, dass bei Erscheinen einer neuen Gradle- oder Android-SDK-Tools-Version ggf. Aktualisierungen in der build.gradle vorzunehmen werden, da ich es absehbar nicht schaffe, alle Repositories aktuell zu halten.

Von Kleinkindern lernen

Wie Medien berichteten, hat am Sonntag ein Kleinkind einen Twitter-Beitrag im Account der US-Atomwaffenbehörde verfasst:

»;l;;gmlxzssaw« – Rätselhafter Code? Verborgene Botschaft? Die Auflösung kam schnell

Bemerkenswert daran ist natürlich nicht, dass man genau erkennt, welche Buchstaben mit der rechten (die bis gml) und welche mit der linken sehr kleinen (das z liegt auf amerikanischen Tastaturen links neben dem x) Hand (der Rest) verfasst wurden.

Bemerkenswert daran finde ich auch nicht, dass der für den Account zuständige Social-Media-Manager es nicht für nötig hielt, während seiner kurzen Abwesenheit (vermutlich musste er aufs Klo) seinen PC zu sperren, auf dem die Twitter-Webseite zum Verfassen eines Tweets gerade geöffnet war.

Denn dass der Mensch der Schwachpunkt jeder IT-Sicherheits-Infrastruktur ist, wissen wir ja schon, nicht wahr? Man muss ja nur “versehentlich” einen präparierten USB-Stick mit der Aufschrift “Pornos” vor einer Firma verlieren, schon erhält man (nach kurzer Wartezeit freilich) bequem Zugriff auf alle Systeme (auf die der glückliche Finder Zugriff hat). Tipp, falls Sie es ausprobieren wollen: Tun Sie wirklich ein paar Pornos auf den Stick, dann schöpft das Opfer nicht so schnell Verdacht.

Bemerkenswert finde ich aber, dass der Tweet zwar nach ein paar Minuten gelöscht wurde – in der Zeit aber, wie man auf dem Bild sieht, fast 5000 mal geliked und halb so oft retweetet wurde. Wohlgemerkt: “Normale” Tweets des gleichen Accounts, meist mit fast sinnlich fotografierten Kampfflugzeigen drauf, bringen es gerade mal auf etwas über 100 Likes und 30 oder 50 Retweets – aber nicht innerhalb weniger Minuten, sondern Tagen.

Das ist ein Symptom, welches auf ein grundlegendes Problem der (a)sozialen Medien hinweist: Quatsch verbreitet sich bisweilen millionenfach schneller und weiter als alles andere. Das ist aber das genaue Gegenteil des Bedarfs: Wichtige (und möglichst akkurate) Informationen sollten sich schneller und besser verbreiten als anderen. Dieses wünschenswerte Verhalten bilden die Mechanismen der sozialen Netzwerke schlicht nicht ab. Deshalb sind sie ein Problem.

tl;dr: Das Beispiel der tausendfach retweeteten IT-Attacke eines Kleinkinds zeigt: Der “soziale” Kaskadier-Mechanismus von Twitter&Co begünstigt die Ausbreitung von Unsinn.

Entkopplung mit Events

Ein Ausweg aus der Multithread-Hölle (Sie wissen schon, die mit dem fröhlichen Bad in siedenden Race conditions) ist die Entkopplung mit Events. Statt einen linearen Programmablauf zu denken, der streckenweise aus wichtigen Gründen in verschiedenen Threads abläuft, denken Sie lieber an herumgereichte Events oder, allgemeiner: Nachrichten. Ein Message-Broker läuft dazu im Hintergrund und reicht Nachrichten herum. Das entspricht einem Publish-Subscribe-Entwurfsmuster. Der entscheidende Vorteil: Die Nachricht “gehört” immer nur jenem Programmteil (oder Thread), der gerade aktiv ist. Es gibt keinen gleichzeitigen Zugriff mehrerer Threads auf das gleiche Nachrichtenobjekt. Auch der Message-Broker interessiert sich nicht mehr für eine Nachricht, sobald er sie zugestellt hat. Am Ende der Verarbeitung wird einfach eine neue Nachricht mit dem Ergebnis der Berechnung auf gleiche Weise zurück geschickt.

Publish und Subscribe

Sie wissen sicher: Viele größere Software-Systeme arbeiten längst mit Microservices und Message-Brokern wie Apache Kafka, die Nachrichten herumreichen. Aber das geht auch in Android, und Sie können damit leicht und elegant Arbeit in den Hintergrund verlagern. Statt mit AsyncTask, Thread, Handler und runOnUiThread können Sie einfach EventBus verwenden – tun Sie vielleicht eh, denn die Library hat sich in unzähligen Apps bewährt:

dependencies {
implementation 'org.greenrobot:eventbus:3.2.0'
}

Meist verwenden Sie EventBus, um Nachrichten zwischen UI-Komponenten, Fragmenten und Activities oder Services auszutauschen. Aber da Sie per Annotation festlegen können, ob ein EventHandler im Vorder- oder Hintergrund aufgerufen wird, können Sie auch sehr einfach eine saubere Background-Task-Verarbeitung umsetzen:

EB ist eine Abkürzung für EventBus.getDefault()

Links, im Main Thread, schicken Sie (z.B. nach einem Knopfdruck des Nutzers) eine CalculationStartMsg los, nix weiter. Die Message ist ein POJO, das alle nötigen Daten enthält, um die gewünschte Berechnung zu starten. Diese Nachricht (oberer Kaffeefleck) stellt EventBus im Hintergrund zu (siehe @Subscribe-Annotation). Wohlgemerkt ist der UI-Thread völlig unbeteiligt, er macht nach dem EB.post() gar nichts mehr bzw. wartet auf weitere Eingaben.

Die Berechnung im Hintergrund erzeugt eine neue Nachricht mit dem Ergebnis der Berechnung, ResultMsg (unterer Kaffeefleck), und überstellt es dem EventBus. Dieser stellt es der passenden onMessageEvent-Funktion im Main-Thread zur Verfügung, die wiederum das Ergebnis in der UI darstellt.

Async im Pool

Falls Sie oft längere Berechnungen im Hintergrund durchführen, verwenden Sie statt ThreadMode.BACKGROUND lieber ThreadMode.ASYNC. Denn während erstere Variante nur einen Thread verwendet, und mehrere Operationen daher nacheinander verarbeiten muss, benutzt ASYNC einen ThreadPool und kann daher problemlos mehrfach und für länger dauernde Berechnungen (wie Netzwerkzugriff) eingesetzt werden.

Beachten Sie immer den Android-Lifecycle: Beide Klassen (die blaue und die orange) müssen bereits instanziiert sein, sonst können sie keine Events empfangen (). Entweder die Worker-Klasse wird in onCreate der Activity (blau) erzeugt, oder alle Funktionen liegen sogar in der gleichen Activity-Klasse. EventBus kann im Gegensatz zu (expliziten) Broadcasts keine neuen Objekte erzeugen. Natürlich müssen alle beteiligten Klassen sich bei EventBus registrieren (mit EventBus.getDefault().register(this)).

In den Messages können Sie beliebige serialisierbare Daten übertragen, auch größere Mengen. Die Latenz beträgt wenige Millisekunden.

tl;dr: EventBus-ähnliche Architektur löst auf elegante Weise viele Multithreading-Probleme, da sie auf gleichzeitige Zugriffe auf ein und dieselben Ressourcen prinzipiell verzichtet. Das bedeutet maximale Entkopplung, weniger Abhängigkeiten und weniger Probleme. Mit ganz einfachen Mitteln. Investieren Sie Ihre wertvolle Zeit lieber in wichtigere Dinge, zum Beispiel Vermeiden von Sicherheitslücken…

EHCache mit Ballast

Auf manche Umstände stößt man ja eher zufällig, zum Beispiel wenn man die Festplatte aufräumt und dabei den vermissten Schlüssel für die Börse mit den zwei oder drei vor 20 Jahren vergessenen Bitcoins wiederfindet.

Nein, hier geht es nicht um Geld, sondern um Energieverschwendung. Mal wieder. Leider. Sorry.

Bei der Modernisierung einer etwas in die Jahre gekommenen Java-Anwendung war es erforderlich, die uralte Version 1.1 von ehcache durch eine aktuelle zu ersetzen. Da ehcache 3.x komplett inkompatible Konfigurationsdateien verwendet, greift der faule Entwickler zur letzten stabilen 2er-Version, nämlich 2.10.6.

Das funktioniert prima, die API ist dieselbe wie anno dazumal in der 1.1. Alles gut, bis ich mich fragte, wieso denn meine Webanwendung neuerdings über 22 MB groß ist.

Ein Blick ins WAR verrät den Übeltäter sofort: ehcache-2.10.6.jar mit über 10 MB macht fast die Hälfte meiner Anwendungsgröße aus!

ehcache-1.1.jar bringt im Vergleich läppische 47,5 kB auf die Waage.

Eine Vergrrrrrööööößerung also um einen Faktor 200. Ungefähr.

Wasnulos?

Zum Glück haben wir es mit Open Source zu tun und können mal nachschauen, ob der Anbieter vielleicht versehentlich ein Promotion-Video eingebaut hat:

Was ist denn das?!? Braucht das jemand!?!? Kann das weg?!?

Nein, kein Promo-Video, sondern ein Paket namens rest-management-private-classpath, in dem sich anscheinend nicht ein, sondern gleich zwei embedded Application Server befinden, nämlich ein Glassfish und ein Jetty.

Freilich weiß der Experte, dass mit ehcache-server ein Ehcache-Produkt für verteiltes Caching mit toller REST-API zur Verfügung steht, aber was hat das in dieser Library zu suchen? (Wenn es das ist, ich rate hier ein bisschen)

Klarer Fall: Grob geschätzt 99% der Anwendungen, die ehcache 2 nutzen, benötigen diese eingebauten Application Server überhaupt nicht (weil sie eigene mitbringen oder in standalone-Server deployed werden). Dass die eingebauten Server kaum jemals verwendet (oder auch nur bemerkt) werden, zeigt auch eine Suche auf stackoverflow, die für “rest-management-private-classpath” gerade mal 42 (kein Witz) Resultate auswirft, für “ehcache” jedoch 8461.

Effizienz sieht anders aus

Wer schonmal was von einer neumodischen Erfindung namens “Modularität” gehört hat, und etwas mit dem komplizierten Fremdwort “Effizienz” anfangen kann, kommt ziemlich schnell drauf, dass man weniger häufig benötigte, optionale Komponenten total cool in eigene Bibliotheken auslagern kann, um die Kernfunktionalität besonders schlank zu halten.

Durch den unnötigen Ballast laden Buildsysteme also mit ehcache 2.x andauernd ca. 8 MB (ungefähre komprimierte Größe des Ballasts) mehr Daten runter oder rauf als nötig und verschwenden so Bandbreite und Speicherplatz. Das klingt nach wenig – aber Ehcache ist nach eigener Aussage “Java’s most widely used cache”, und die Anzahl der Anwendungen, die die aufgeblähte Version verwenden, dürfte von erheblicher Größe sein, entsprechend hoch die Anzahl der Buildvorgänge, bei denen die Datei (mindestens) von einem Maven-Repository auf den Build-Rechner transferiert werden muss usw.

Zur Erinnerung: Jedes übertragene oder irgendwo gespeicherte Byte verbraucht Energie und trägt zum CO2-Ausstoß bei. Äußerst wenig natürlich, aber multipliziert mit einer extrem großen Häufigkeit ist das durchaus relevant. Und in diesem Fall unnötig. Bekanntlich tragen Rechenzentren zwischen 10 und 20% zum weltweiten Energieverbrauch bei. Mangelhafte Software-Effizienz trägt daran eine Mitschuld!

Hausaufgabe (zu morgen!): Den eigenen Code in Bezug auf diese Fragestellung in Augenschein nehmen.

Übrigens: In ehcache 3 hat man auf den Ballast verzichtet, das Artefakt ehcache-3.9.2.jar ist bloß 1,8 MB groß.

tl;dr: ehcache 2 schleppt unnötigen Ballast in jede damit arbeitende Anwendung. Um Energie und CO2 einzusparen, sollten Entwickler also zeitnah von Version 2.x auf 3.9 migrieren.

Prohibition für Saugrobby!

Was muss ich da lesen? Besoffene Saugroboter?

Jetzt mal unabhängig von der Frage, ob es schlimm oder lustig ist, wenn Saugrobby wie ein verwirrter Hamster immer im Kreis fährt oder länger als sonst zum Reinigen der Wohnung braucht: Kann ja mal passieren, dass beim Abschlusstest eines Updates irgendwas übersehen wird, nicht wahr?

Ich will auch gar nicht über schlechte Testbarkeit meckern oder spekulieren, wie hoch die technische Schuld der womöglich nicht tip-top sauberen Software der betroffenen Roombas des Herstellers iRobot ist (dear iRobot, if you need help here, drop me a message!). Aber der Anlass ist willkommen für die regelmäßige Erinnung an die inhärente Fehlerfortpflanzung bei Software:

Menschen machen nunmal Fehler, das ist menschlich. Unterläuft beispielsweise einem Frisör ein Fehler, rennt hinterher ein Kunde mit doofen Haaren herum. Unterläuft einem Programmierer ein Fehler, so sind viel, viel mehr, schlimmstenfalls Millionen Nutzer betroffen, nämlich alle, die diese Software verwenden oder den fraglichen Code bei einer Sitzung auf einer Cloud-Instanz durchlaufen, falls es sich um eine Webanwendung handelt.

Während der Frisör deshalb mit einem minimalen Korrektiv auskommt (z.B. dem Kunden den Spiegel hinter den Kopf halten und fragen, ob’s gefällt), muss die Software deutlich höhere Hürden überwinden, um in die freie Wildbahn entlassen zu werden. Da ist zunächst mal die Suite von Unit Tests (Sie haben doch Unit-Tests, oder?), Integrationstests auf einer Testumgebung und die Abnahme auf einer Staging-Umgebung bzw. weitere Ende-zu-Ende-Tests, sei es automatisiert oder manuell. Im Idealfall jedenfalls. Eine Testabdeckung von 100% aller Fälle ist jedoch utopisch. Das gilt umso mehr, wenn Endgeräte im Spiel sind, die über individuelle Daten verfügen (z.B. Aufzeichnungen über die Geometrie zu saugender Räume). Die kann man nicht alle testen. Geht nicht.

Also sind halt bisweilen ein paar Staubsauger-Bots besoffen.

Software wird von Menschen geschrieben, die nicht perfekt sind. Folglich kann auch das Produkt nicht perfekt sein. Deshalb wird Software immer ein Restrisiko mit sich bringen. Es mag bei guten Programmierern (die mein Buch gelesen haben) klein sein, aber nie Null. Wer von Software Wunder erwartet, übersieht den menschlichen Faktor. Wer den menschlichen Faktor übersieht, kalkuliert Kosten für Fehlerbehebung oder Wartung nicht hinreichend in die Wirtschaftlichkeitsanalyse ein – und gelang möglicherweise zu einem Ergebnis größer als Null und ist später überrascht, wenn er draufzahlt.

Disclaimer: Nein, dies ist keine pauschale Entschuldigung für Bugs. Schon gar nicht für solche, die durch guten Code und sauberes Testen vermeidbar gewesen wären. Es ist der ausdrückliche Wunsch nach realistischen Einschätzungen.

Wer die Anfälligkeit von Software mit einrechnet, kommt nämlich auch nicht auf so drollige Ideen wie z.B. autonome Drohnen mit tödlichen Waffen oder diskriminierende Algorithmen für die Sichtung von Bewerbungsunterlagen, Anwendungen also, die ein bisschen weniger witzig sind als besoffene Roboter.

tl;dr: Vermeiden Sie Fehler – aber tun Sie nicht so, als gäbe es keine.