Software-Engineering-Experts .
Mitgliedschaften in Fachverbänden:  Verein Deutscher Ingenieure VDI  Verband Deutscher Fotojournalisten DFJ: Foto | Print | Internet | Radio | TV    |    Referenzen   |    Impressum   |    Datenschutz   |    Kontakt  

🏠   |    Data Engineering  |    V‑Modell + DevOps  |    Innovation   |    Requirements Engineering   |    SW‑Architektur   |    UML   |    Coding   |    Building+Integration   |    Monitoring, Build, Tests und Testmetriken.   |    Freigabe   |    Betrieb   |    Außerbetriebsetzung   |    Dokumentation   |    SPICE   |    ML und Künstliche Intelligenz   |    Safety   |     Security  |    Projektmanagement   |    IT‑Recruiting und Führung   |    Lebenslauf   |    In der Presse   |  

 

Monitoring, Build, Tests und Testmetriken, klassisch und KI

„Wenn Debuggen der Prozess ist, Software‑Fehler zu entfernen, dann muss Programmieren der Prozess sein, sie hineinzustecken.“
Edser W. Dijkstra

Die Praxis zeigt leider, dass „Debuggen“ mit Hilfe des „Debuggers“ (Delinter, Flusenentferner 😉) der IDE (Integrated Development Environment) allzu oft bereits als Testen verstanden wird. Oder es werden schlicht naiv die Menüs nachgeklickt (manuelle End‑to‑End‑Usertests). Naives Testing ist weit verbreitet und hat viele Formen. So mancher Entwickler hat sein Handwerk nicht im Rahmen eines Informatik‑Studiums, sondern autodidaktisch erworben. Mit allen Vor‑ und Nachteilen. Dann werden allzu oft die Kunden zu Testern. Kann man so machen.

Überforderter Software-Tester Auch aus struktureller Sicht geht es oft, na sagen wir mal, suboptimal zu: die Entwickler entwickeln so vor sich hin und kurz vor einem Meilenstein, Ende eines Sprints oder vor der nächsten Stufe des Wasserfalls, wenn sich die Software als lauffähig erwiesen hat, geht das Ganze zur Prüfung an das Qualitäts‑Team, das Security‑Team, das Sales‑ und Marketing‑Team (falls es die gibt). Es folgen Fundamentaldiskussionen und abzuarbeitende Checklisten. Die Entwickler erinnern sich kaum noch an das, was sie sich damals bei ihrem Code gedacht hatten. Oder es hat ein Personalwechsel stattgefunden. Eine klärende Dokumentation mit hohem Nutzwert der Semantik steht nur rudimentär zur Verfügung. Missgestimmtheit und Frustration sind normaler Teil des Spiels. Aus DevOps‑Sicht ist natürlich auch hier ein Left‑Shift anzustreben: Compliance‑Regeln sind bereits zu Anfang der Entwicklung zur Verfügung zu stellen, sind laufend zu aktualisieren und ihre Beachtung ist durchzusetzen. Dann verlaufen die abschließenden Tests für alle Beteiligten erheblich erfreulicher. Weiterhin sind die Schleifen (Iterationen) zeitlich möglichst kurz zu halten. Klar, das schreibt sich so einfach. Das Ganze ans Laufen zu bringen ist eher ein wirtschaftspsychologisches als ein technisches Problem.

Woran messen wir eigentlich die Qualität eines Codes?
Schon die Frage ist falsch: man ersetze „Code“ durch „Software“. Also alle mit dem Projekt in irgend einem Zusammenhang stehenden Dokumente. Das Zauberwort heißt „Metriken“. So können und sollten wir z.B. automatisiert den Modularisierungsgrad des Quellcodes messen, den Zusammenhalt von Modulen, die Kopplung der Module und die eingearbeiteten Abhängigkeiten. Daraus können wir z.B. auf die Erfüllung von Security‑by‑Design‑Regeln und die spätere Wartbarkeit und Wiederverwendbarkeit schließen. Darüber hinaus geht es um Leistungstests und Fuzzy/Chaos‑Testing: Wir bewerfen das System mit unsinnigen Eingaben und über Interfaces ausgetauschten falschen Werten. Weiterhin prüfen wir die Reliabilität, etwa indem wir zufällig ausgewählte Module einfach löschen und prüfen, ob es zu Abstürzen oder einer wünschenswerten "graceful degradation" kommt. Auch nicht zu unterschätzen: die semantische(!) Qualität der Dokumentation mit besonderem Fokus auf die Header der Module sowie die Kommentarzeilen. Und wir dürfen nicht vergessen, dass Metriken die unangenehme Eigenschaft haben, zu Zielen zu werden. Sie steuern (und das sollen sie ja auch) das Verhalten der Entwickler. Nur dass sie das gnadenlos tun. Wer schnelle Lauffähgkeit lobt, bekommt sie. Nach mir die Sintflut. Wer die Anzahl der Codezeilen zur Basis einer leistungsbezogenen Bezahlung, bekommt sehr, sehr viel Code. Ein prominentes Beispiel ist weltweit bekannt. Ein denkbarer Prompt an die KI: „Schreibe mir 13.438 Zeilen kompliziert aussehenden Codes, der nichts tut und den ich überall einkopieren kann“. Und wenn Sie die Anzahl gefundener Fehler als Metrik zur Erfolgsdefinition des Qualitäts‑Teams machen, verhindern Sie die Umsetzung des Left‑Shifts. Na, gruselt es? Sich also schnell mal selbst eine Metrik zu überlegen, ist hoch riskant. Aber wir stehen ja auf den Schultern von Riesen und können uns viel Erfahrung zugänglich machen. So viel als erste Inspiration zu einem sehr viel größeren Gebiet.

Einige Gedanken dazu, wie es im Rahmen eines professionellen Software‑Engineerings läuft, im Folgenden. Die Testpyramide Wir beginnen mit der Testpyramide links. Tests bauen aufeinander auf: je weiter unten ein Fehler entdeckt wird, desto geringer die Kosten der Behebung. Ganz oben die Validität prüft, ob auch tatsächlich entwickelt wurde, was die Welt will (nicht unbedingt, was die eigentlich braucht oder gar brauchen sollte), der UAT (User Acceptance Test, auch Abnahmetest). Fehler im Requirements Engineering fallen typischerweise erst hier, auf der teuersten Ebene auf. Was prüfen wir? Die Liste der sinnvollen Möglichkeiten ist groß, daher hier eine extrem verkürzte Liste:

Insgesamt ergibt sich eine Testmatrix. Angesichts des Aufwandes ist gut zu überlegen, welche Tests im gesamten Wertstrom positiv wirken und welche Tests als Overkill einzustufen sind. Hochwertig moderierte Meetings klären dies möglichst frühzeitig. Das Ganze wird dann möglichst automatisiert in einer für die Entwickler transparenten Test‑Pipeline (YAML, XML...), eingebettet in CB/CI/CD von DevOps in die Praxis gegeben. Logisch, es braucht eine eigene Testentwicklung, die auch (wiederverwendbare) Mock‑Objekte bereitstellt. Ein gutes Testsystem hat sehr positive Auswirkungen: Alle entwickeln verantwortungsvoller, auch was die Lesbarkeit des Codes angeht. Ziel ist es natürlich auch, eine positive Feedbackschleife zu erzeugen.

„Es gibt keine Testumgebung. Manche haben nur zufällig eine separate Umgebung, in der sie auch nicht testen.“
Szene‑Spruch

Vielleicht ist auch deutlich geworden, dass sehr gute Software‑Entwickler eher in die Testentwicklung und den Bereich Cybersecurity gehören, als in die Standardentwicklung. Einfach, weil Coding durch gutes Software‑Engineering eine vergleichsweise einfache und sichere Aufgabe wird. Nur sehr selten ist echtes „Bleeding‑Edge‑Development“ erforderlich. Ach ja: das Monitoring. Ein großes Thema, aber ich habe hier mehr als zulässig viel Bleiwüste geschrieben. Damit zur erfolgskritischen Frage nach des Pudels Kern: Wie führen wir ein wertstromorientiertes Testing ein?

Reden wir jetzt darüber!

P.S.:
Immer stellt sich zusätzlich die Frage: klassisch‑menschlich, modernes Vibe‑Coding via KI oder irgend etwas dazwischen?

Nerden wir uns anhand von KI 'rein:
Modern bedeutet nicht automatisch „gut“. Prinzipiell stellt ein klassischer Code ein „deterministisches System“ dar: es bestehen klare Ursache‑Wirkungs‑Beziehungen. Der Code läuft damit jedes einzelne Mal exakt und reproduzierbar so, wie der Programmcode geschrieben wurde. Er ist mit semantisch hochwertigen Kommentarzeilen versehen, auch nach langer Zeit von Dritten gut lesbar, gut wartbar und erweiterbar und ist von einer aussagefähigen Dokumentation begleitet. Egoless‑Coding ist ein wichtiges Stichwort, das mit einem gewissen Anspruch an die Führungskräfte verbunden ist. Ein Beispiel aus dem oft allzu naiv beschriebenen Thema „Fehlerkultur“, hier auch nur ansatzweise angemessen dargestellt: Ein Fehler aus der Unperfektion heraus, entstanden während nach bestem Wissen und Gewissen ausgeführter Arbeit, ist ok. Manchmal sogar ein Lob wert. Sog. „vorwerfbare Fehler“, resultierend aus Handlungen, die dem Handelnden bereits während der Ausführung als falsch bekannt sind, müssen wirkungsvoll sanktioniert werden. Wie auch immer: Programmierfehler werden im Laufe der Zeit ausgemerzt (hoffentlich ohne Entropiezunahme, z.B. durch lediglich das Symptom behebende Workarounds mit langfristig negativen Folgen), so dass die Software kontinuierlich der Perfektion näher kommt (hoffentlich 😉).

Für selbstlernende Systeme wie Maschinelles Lernen und Künstliche Intelligenz gilt das nicht in gleicher Weise: sie stellen sog. „probabilistische Systeme“ dar: Kann sein, dass beim nächsten Durchlauf alles so ist, wie beim letzten Mal. Kann aber auch anders sein. Ich führe diese Eigenschaft von z.B. Neuronalen Netzen NN bei meinen Python+KI‑Seminaren beim VDI immer wieder gerne anhand eines Tensorflow‑NN vor. Insbesondere eine LLM‑KI halluziniert eloquent - zunächst unmerklich, der Code funktioniert bei unstrukturierten Tests oft gut. Ein Code Review wird allerdings noch bedeutsamer und aufwendiger als bisher sowieso schon: es war schon immer besonders anspruchsvoll und zeitraubend, sich in den Code eines anderen Menschen einzufinden und Bugs zu entlarven. Der Programmierstil von KIs kann von sehr unterschiedlicher Qualität sein, genau so wie die Vorlagen der Weisheit aus dem Internet (Stack Overflow und Co.) Viele Experimente und Studien zeigen inzwischen, dass wir es uns nicht zu einfach machen sollten. Das kann teuer werden. Wir irren vorzugsweise auf der richtigen Seite und rufen uns ab und zu eine einfache Lehre aus der Praxis in den Kopf:

There is no free lunch!

Das Testen herkömmlich erstellter Software ist bereits recht anspruchsvoll. Code, der mit KI erzeugt wurde, ist schon riskanter. Daher verlieren Senior‑Entwickler rund ein Drittel Effizienz, wenn sie mit KI entwickeln, wie inzwischen mehrere Experimentalstudien zeigen. KI selbst, wie z.B. ein erstelltes Agentensystem, ist kaum noch angemessen zu testen.

Nehmen wir als einfachsten Fall beispielsweise eine 32‑Bit‑Variable: sie kann rund 4,3 Milliarden unterschiedliche Werte darstellen. Enthält ein Modul oder Unterprogramm drei oder mehr solcher Variablen, reicht das Alter des Universums nicht im entferntesten aus, um einen sog. „vollständigen Test“ zur Vermeidung etwa von Punkt‑ oder Bereichsfehlern auszuführen. Und wir haben die sich aus der Cybersecurity, den Rechtsnormen auf eur‑lex.europa.eu oder ISO 29119 „Software‑Tests“ oder ISO 27001 ergebenden Coding‑Notwendigkeiten hier noch nicht einmal mitbedacht...

Oder wir bedenken, dass Module, Unterprogramme, Funktionen und Units daraufhin abzusichern sind, dass es auch bei völlig unsinnigen Austauschwerten wie ‑456°Celsius nicht zu unkontrollierten Zuständen kommt. Immerhin stellen solche Programmierschwächen recht gute Angriffsoptionen für Malware dar. Gleiches gilt auch für die Überladung von Variablen (Stack Overflow). Wer mag, recherchiert zur Canary Mitigation. Wer dem Prinzip „Security‑by‑Design“ folgt, wird Modular in Richtung Microservices programmieren. Der Test: randomisiertes (zufälliges) Abschalten/Löschen eines jeden Moduls. In keinem Fall darf es zu unkontrolliertem Verhalten kommen, wenn Angreifer sich Zugang zu Teilen verschafft haben. Genau diese Härtung wird hier getestet. Ein „graceful failure mode“ ist nötig nach dem Motto: alles kann schiefgehen. Jederzeit. überall. Es braucht eine Liste abzusichernder Szenarien, zu vermeidender unsicherer Befehle und anderen Arten an Codiervorgaben. Diese sind mindestens teilweise individuell an Projektspezifika auszurichten. Ein hochwertiger Moderationsjob, der Persönlichkeitseigenschaften wie Extraversion, sowie Gesprächstechniken auf individuell‑authentischem Anwendungsniveau genau so wie IT‑Fachkompetenz verlangt.

Fazit:
Art und Umfang der Tests, anzuwendende Messtechniken (Metriken) sind Gegenstand anspruchsvoller Planung und Ausführung. Zu testen sind alle Elemente des Software Development Lifecycle SDLC und ihre Integration, ggf. auch im Zusammenspiel mit der vorgesehenen Hardware (z.B. embedded Software). Dazu gehört auch die Qualität und Vollständigkeit der Spezifikationen sowie der Kommentarzeilen. Keinesfalls dürfen Testentwickler und Tester diejenigen Personen sein, die auch den zu testenden Code geschrieben haben. Günstig wäre ein freundlicher(!) Wettbewerb zwischen den Gruppen, durchaus eine Herausforderung an die Personalführung.

Testen ist ein potenziell konflikthafter und zugleich notwendiger Prozessschritt. Eine hochwertige Moderation und angemessene Interventionen auf Basis hierfür entwickelter und erlernbarer Gesprächstechniken sorgt für reibungsarme Abläufe.

Reden wir jetzt darüber!