Softwarequalität Legacy-Code ist eine tickende Zeitbombe

Redakteur: Franz Graser

Für die Zuverlässigkeit eingebetteter Systeme ist die Qualität der Software von entscheidender Bedeutung. John Paliotta, Cheftechnologe des Testspezialisten Vector Software, sprach mit der ELEKTRONIKPRAXIS über Strategien zu besserer Codequalität – und die Gefahren, die in altem Code stecken.

Firmen zum Thema

John Paliotta, Mitbegründer und CTO von Vector Software.
John Paliotta, Mitbegründer und CTO von Vector Software.
(Bild: Vector Software)

Von der Softwarequalität hängt ganz offensichtlich immer mehr ab, gerade im Hinblick auf Security und das Internet der Dinge. Softwaretests gewinnen daher immer mehr an Bedeutung. Würden Sie das genauso sehen?

Security ist nicht unbedingt unser Kernthema. Aber das Internet der Dinge hat sehr viel mit uns zu tun. Alle unsere Industriekunden sind bereits seit geraumer Zeit vernetzt. Das ist nicht unbedingt etwas Neues. Das industrielle Internet existiert bereits seit einiger Zeit. Es ist nicht so, dass jemand plötzlich gesagt hätte: „Wow, lasst uns mal diese Ventile zur Prozesskontrolle ans Internet hängen.“

Mit Blick auf das Consumer-orientierte IoT denke ich aber: Es treten zahlreiche neue Softwareanbieter auf den Plan, die nicht daran gewöhnt sind, dass ihre Software auch robust sein muss. Auf der letzten CES habe ich einen Kühlschrank gesehen, der mit einem Internet-Browser ausgestattet war.

Alles schön und gut, sofern der Browser nicht auf demselben Prozessor und im selben Speicher läuft wie die Steuerung des Kompressors. Wenn all die mechanischen Komponenten von denselben Prozessen gesteuert werden, die auch die nicht-kritischen Funktionen regeln, dann kann es passieren, dass der Browser abstürzt, was dazu führt, dass der Prozess stoppt, der den Kompressor steuert und Ihre Lebensmittel verderben.

Beim Nest-Thermostat trat vor einiger Zeit ein Softwarefehler auf, der dazu führte, dass die Heizung in den betroffenen Häusern komplett abgeschaltet wurde. Das ist unangenehm. Mein herkömmlicher Thermostat funktioniert dagegen seit 30 Jahren reibungslos. Die Eigenschaften von Quecksilber ändern sich eben nicht. So lange das Glasröhrchen mit dem Quecksilber nicht zerbricht, ist alles in Ordnung.

Das mögen jetzt erst mal lediglich Unannehmlichkeiten sein, aber die Komplexität der Systeme steigt in astronomischem Umfang. Und ich glaube nicht, dass wir Nutzer darauf vorbereitet sind, dass sich immer mehr Systeme auf dem kritischen Pfad bewegen. Wenn Sie einen Unfall haben, befindet sich Ihr Smartphone auf dem kritischen Pfad. Es ist ungünstig, wenn Sie niemanden anrufen können, obwohl sich 5.000 Chat-Apps auf Ihrem Handy befinden.

Im Luftfahrtbereich wird die Partitionierung zwischen kritischen und nichtkritischen Applikationen angewandt, sie sind gegeneinander isoliert. Ich glaube nicht, dass viele Leute in dem neuen IoT-Umfeld darauf vorbereitet sind, dass ihre Geräte durch Denial-of-Service-Attacken angegriffen werden könnten. Ich denke, dass sich in diesem Umfeld viele Leute erst mit dem Konzept der Robustheit vertraut machen müssen.

Viele Experten sprechen ja über eine Verifikationsstrategie mit Test, statischer Analyse, Codeanalyse und ähnlichen Domänen. Wo sehen Sie Ihre Spezialität?

Korrektheit. Statische Analyse ist großartig, wenn es darum geht, Muster von Programmierfehlern zu finden. Aber Sie können in statischer Hinsicht völlig sauber sein und trotzdem eine komplett falsche Applikation haben. Uns geht es in allererster Hinsicht um Korrektheit – um den Beweis, dass der Code das tut, was er tun soll, und nicht darum zu beweisen, dass der Code tut, was er tut! Es klingt zwar ganz ähnlich, aber dazwischen liegen Welten.

Ich habe vor Kurzem einen Vortrag gehalten, in dem es um die Herausforderungen bei der Softwarequalität ging. Unter anderem habe ich die Aussage getroffen: Oft heißt es, dass Tests auf Komponentenebene nicht sehr ergiebig seien, weil sie nicht sehr viele Bugs zutage fördern. Aber ehrlich, worum sollte es denn beim Testen auf einer sehr tiefen Ebene gehen? Es sollte darum gehen, das korrekte Systemverhalten zu formalisieren und das Verhalten in Grenzbereichen zu testen.

Es kommt aber viel zu oft vor, dass sich die Leute beim Testen auf die vorgegebenen Pfade beschränken. Um gerade diesen Fehler zu vermeiden, brauchen die Leute einen Überblick darüber, was ihre Testfälle tatsächlich prüfen. Das ist ein ganz wichtiger Aspekt. Jedesmal wenn ich einen Vortrag halte, frage ich die Zuhörer: Wer benutzt Code-Coverage-Werkzeuge?

Das ist für mich immer ernüchternd, denn in der Regel melden sich nur zwei von 40 Zuhörern, selbst bei einer Veranstaltung, bei der sich alle mit der Entwicklung von Embedded Software beschäftigen. Dabei ist das die am niedrigsten hängende Frucht! Wenn man keine Code-Coverage-Analyse vornimmt, dann hat man keine Ahnung, was man eigentlich testet!

Es kann also sein, dass Sie eine sehr robuste Testumgebung schreiben und nur ganz oberflächlich testen. Und ohne Koordination zwischen den Teams, die für den Entwurf, die Entwicklung und das Testen zuständig sind, verlieren Sie eine ganze Menge unglaublich wichtiger Informationen. Die Menschen, die für den Entwurf zuständig sind, wissen eine ganze Menge darüber, was die Applikation tun soll.

Die Person, die den Code schreibt, trifft jeden Tag wichtige Entscheidungen. Wenn ich Code schreibe, dann habe ich immer einen Notizblock neben der Tastatur liegen. Jedesmal wenn ich eine Bedingung einbaue, notiere ich mir das. Und so habe ich am Ende eine Liste der Grenzfälle, die in dem Code drinstecken, den ich gerade geschrieben habe.

Und ich stelle sicher, dass ich dafür Testfälle schreibe. Und das gebe ich dann den Leuten von der Qualitätssicherung. Die lesen, was der Designer geschrieben hat und interpretieren es. Ich lese als Entwickler, was der Designer geschrieben hat und interpretiere es meinerseits. Aber wir alle arbeiten getrennt voneinander. Wir müssen alle von ersten Tag an zusammenarbeiten und uns darüber einig sein, was die Erfolgskriterien sind.

„Im Softwarebusiness marschieren alle zu ihrer eigenen Melodie“

Der menschliche Faktor ist hier ganz wichtig. Was bringen die ganze Technik und die ganzen Tools, wenn Designer und Entwickler und Tester nicht miteinander sprechen?

Ja. Aber es geht nicht nur darum, dass sie miteinander reden. Ich nenne es „die Sprache des Tests sprechen“. Damit meine ich, der beste Weg zu definieren, was ein System tun soll und zu beweisen, dass es das auch tut, ist einen Test zu bauen, der prüft, dass das System das tut, was es soll. Nicht wahr?

Wenn Flugzeugkonstrukteure ein Flugzeug bauen, belasten sie die Flügel so stark, dass sie abbrechen. Und sie ermitteln die Kraft, die nötig ist, damit der Flügel abbricht. Das heißt, sie zerstören etwas, um zu beweisen, dass das Design schlüssig ist. Sie benutzen dafür nicht nur ein Computermodell. Dazu muss man wissen: OK, bei einer Belastung von 100 Newtonmetern pro Quadratfuß bricht der Flügel.

Das ist das Ziel, auf das man gemeinsam zuarbeitet. Der Designer entwirft die Flügelspanten so, dass sie diese Kraft aufnehmen können. Die Schweißer und Nieter bauen die Teile so zusammen, wie es der Designer entworfen hat und die Tester prüfen dann, dass es sich tatsächlich so verhält. Aber im Softwarebereich marschiert jeder zu seiner eigenen Melodie. Und der breiteste Graben liegt zwischen den Codern und der Qualitätssicherung.

Das heißt, in der realen Welt, bei der realen Produktentwicklung wendet man von vornherein so etwas wie testbasiertes Design an. Man entwickelt ein Produkt von Anfang an so, dass es in der Lage ist, bestimmte Tests zu bestehen.

Genau! Das ist ganz entscheidend. Das fehlende Glied bei der Software ist, dass niemand die Testkriterien dokumentiert. Es ist sehr einfach, einen Algorithmus zu schreiben, wenn Sie mir sagen, was er erledigen soll. Es ist noch einfacher, wenn Sie mir sagen: Das sind die Testkriterien, die er erfüllen muss.

Lassen Sie die besten Leute im Team über die Grenzfälle nachdenken und die Tests entsprechend bauen. Die Implementierung kann jeder Junior-Programmierer erledigen, wenn ich ihm sage: Hey, das sind die Tests, die das Programm bestehen muss.

Aber jetzt kommt noch etwas: Was ist mit den Millionen von Codezeilen, die draußen in der Welt sind und nicht genügend getestet wurden? Jeder Softwarehersteller hat Bestandteile in seinen Applikationen, die unzureihend getestet sind. Das ist eine große tickende Zeitbombe. Denn wenn man bestehenden Code auf neue Weise wiederverwendet oder ihn auf eine neue Art anspricht und er plötzlich nicht mehr funktioniert und Sie nicht wissen, warum, dann wissen Sie nicht, was Sie kaputtgemacht haben.

Das erinnert mich ein wenig an die Chaostheorie, die in den 90-er Jahren sehr populär war. Sie besagt, dass jedes System einen Punkt besitzt, an dem es unvorhersagbar wird. Wir wissen nicht, wo dieser Punkt liegt. Aber es gibt Bedingungen, unter denen Systeme, die man sehr gut zu kennen glaubt, sich plötzlich erratisch verhalten. Und mit dem unzureichend getesteten Code ist es genauso, er ist –

– überall. Wir benutzen ihn jeden Tag. Manchmal hängen Menschenleben davon ab.

„Bestandscode ist eine tickende Zeitbombe“

Es gab vor Kurzem ja eine ganze Welle mit Ransomware. Sogar Krankenhäuser wurden von dieser Malware komplett lehmgelegt. Und das ist eine ziemlich gruselige Vorstellung.

Erst heute Morgen hat man mir gesagt, dass einige Firmen es komplett aufgegeben haben, Angriffen vorzubeugen. Sie wissen, dass die Attacken kommen. Sie bewegen sich immer mehr in die Richtung, dass sie zu erkennen versuchen, dass sie angegriffen werden, um diese Attacken dann zu stoppen. Es klang auf jeden Fall sehr glaubwürdig.

Man weiß: Die Attacken kommen auf jeden Fall, man kann sie nicht im Vorfeld abwehren. Man kann aber den Internet-Traffic analysieren und ungewöhnliche Muster aufspüren, um zu erkennen, dass man gehackt wird, und sich dann abschalten.

Wir nehmen auf jeden Fall wahr, dass immer mehr Menschen sagen: „Hör zu, wir haben diese Mengen an altem Code. Da Softwareentwicklung so teuer ist, versuchen wir ihn so lange zu nutzen, wie es geht, bevor wir letztendlich aufgeben und alles neu machen müssen.“ Da gibt es ein unglaubliches Interesse. Deshalb entwickeln wir eine automatische Technik, die es erlaubt, einen Grundbestand an Testfällen zu erzeugen. Wenn man nämlich eine Applikation draußen im Feld hat, dann funktioniert die Software ja irgendwie und es gibt auch eine Wartungsgeschichte dafür.

Vielleicht ist sie nicht ausreichend getestet, aber sie ist immerhin ein paar Jahre im Betrieb. Sie haben auch ein paar Bugs gefixt, Ihre Kunden haben auch ihre Erfahrungen damit gemacht, also verhält sie sich erwartbar. Ich sage immer: Wenn man am allerersten Tag, an dem man eine Software neu schreibt, auch testet, dann ergibt das keinen Sinn. Aber wenn die Software ein paar Jahre lang in Betrieb ist, dann validiert man, man dokumentiert, man formalisiert, was sie tut, und das ist schon einiges wert.

Und daraus helfen wir – quasi als Zwischending zwischen Produkt und Service – einigen Kunden dabei, das Verhalten einer bestehenden Applikation zu kartografieren. Das ist unheimlich interessant. Man bringt sie von einem unzureichend getesteten Zustand zu einem ausreichend getesteten Zustand, und so haben die Kunden einen Grundbestand an Testfällen, dem sie neue hinzufügen können.

Es ist natürlich unmöglich, alle notwendigen Tests händisch zu bauen. Aber wenn wir auf den Quellcode bestimmte Heuristiken anwenden können, um intelligente Testfälle zu erzeugen, dann hat das einen echten Wert. Und wir sind bereits von einer Handvoll Kunden engagiert worden, um genau das zu tun.

Wie gehen Sie dabei vor?

Wir haben unsere eigene proprietäre Technik, die eine Erweiterung unserer bestehenden Werkzeuge darstellt. Darüber hinaus nutzen wir Algorithmen und Heuristiken, die wir den Kunden nicht verkaufen, sondern als Service einsetzen. Damit ist es möglich, 100.000 Codezeilen nach einigen Monaten zu testen und den Kunden einen Grundbestand von Testfällen zu geben – und zwar schneller, als irgendjemand das manuell tun könnte.

Wie reagiert die Industrie darauf?

Die Kunden, mit denen wir das momentan machen, sind absolut positiv gestimmt. Sie verstehen, dass sie damit 90 Prozent günstiger wegkommen, als wenn sie diese Testfälle selbst manuell erstellen müssten.

Metriken für Code-Qualität

Verstehen die Unternehmen denn, dass bei ihnen im Keller eine Zeitbombe tickt?

Immer mehr verstehen es. Eine Reihe von Interessenten oder gar Bestandskunden sagen zu uns: „Wir wissen, dass wir ein großes Problem mit unserem bestehenden Code haben.“ Das heißt, dass sie wissen, dass sie ein Qualitätsdefizit haben.

Jeder, der Code produziert, weiß, wo die Probleme liegen. Deshalb arbeiten wir zur Zeit einem webbasierten Qualitätsmonitor für VectorCast Analytics. Er erlaubt Ihnen auf sehr einfache Weise Qualitätsmerkmale zu prüfen, etwa die Komplexität, die Größe oder die Kommentardichte. Das erlaubt Ihnen zu sehen, wo Sie stehen und worauf Sie sich konzentrieren sollten.

Denn bei dem Bestandscode-Problem stellt sich jeder die Frage, wo man anfangen soll. Selbst mit Werkzeugen zur statischen Analyse bekommt man ja Millionen von Bugs angezeigt. Man kann sie aber nicht alle auf einmal fixen. Die Zeit reicht einfach nicht. Aber wir können unsere begrenzten Ressourcen intelligent an der Stelle einsetzen, wo es am meisten nützt.

Die Analyse zeigt zum Beispiel anhand von Farben die Codeabdeckung an. Jetzt habe ich etwa ein richtig komplexes Symbol, das komplett rot eingefärbt ist. Das zeigt Ihnen, dass es sehr komplex ist und dass die Komponente kaum getestet wurde. Wenn Sie ganz kleine Symbole haben, die alle grün sind, dann haben Sie die einfachen Sachen getestet. Sie sollten sich also auf die schwierigen Dinge konzentrieren.

Eine andere Analyse, die Sie vornehmen können: Welcher Code ändert sich am häufigsten? Wenn sich Module jeden Tag verändern, dann sind das mit einiger Wahrscheinlichkeit Ihre Sorgenkinder. Denn wenn sich diese Module jeden Tag ändern, dann fügen Sie entweder jeden Tag neue Funktionen hinzu oder Sie reparieren eine ganze Menge Fehler.

Eine andere interessante Sache ist: Wieviel Zeit verwenden die Entwickler darauf, Bugs zu fixen? Wir wollen ja, dass unsere Entwickler neue Software erstellen, neue Funktionen, die die Kunden zufriedenstellen. Aber wenn wir an den Punkt kommen, an dem die Entwickler zu 90 oder zu hundert Prozent Fehler beheben, dann sind wir gefesselt, nicht wahr? Wenn Sie ein Bauunternehmen wären und Ihre Mitarbeiter würden zu 90 Prozent löchrige Dächer stopfen oder Rohre reparieren, die nicht richtig installiert wurden, dann wären Sie schnell pleite.

Denn bei der Software wird so gearbeitet, als würden wir beim Hausbau nicht auf Qualität achten und dann die Wände einreißen und die löchrigen Röhren reparieren. Sie würden ja auch kein Set von acht Gläsern herstellen, die alle unterschiedlich hoch sind. Ich bin mir sehr sicher, dass die Glasfabrik nicht zuerst die Gläser herstellt und dann alle wegwirft, die nicht die richtige Höhe haben.

Aber im Softwarebereich machen wir das! Wir finden hinterher die Fehler und dann patchen wir sie! Und ziemlich oft ruinieren wir damit das ursprüngliche Design! Ich habe gestern in meinem Vortrag einen Witz gemacht: Wenn man einen Entwickler fragt, wie er mit dem neuen Feature vorankommt, dann sagt er: „Gut, wir sind zu 90 Prozent fertig. Wir müssen nur noch testen." Realistisch betrachtet ist er zu 30 Prozent fertig.

Bieten Sie diesen Service vor allem Herstellern von Embedded-Software an oder gehen Sie auch auf traditionelle IT-Firmen zu?

Wir sprechen die [traditionellen IT-Firmen] nicht an, denn unsere Domänen-Expertise liegt ganz klar im Embedded-Segment.

Ein Bekannter von mir schreibt Code für ein Maschinenbauunternehmen. Er ist aber nie zu einem Seminar für Embedded-Softwarearchitektur geschickt worden, weil er und seine Kollegen den Code quasi ad hoc entwickeln müssen. Der Code wächst quasi organisch.

Ja. Ohne jede Richtung, ohne Maß und Ziel. Das ist doch verrückt. Weiß Ihr Bekannter auch, dass das verrückt ist?

Ja. Er weiß, dass er und seine Kollegen eigentlich einen viel systematischeren Ansatz bräuchten. Aber dafür fehlt die Zeit. Und das Team kann kein Mitglied entbehren, um ihn oder sie auf einen Kurs oder ein Seminar zu schicken.

Oder wenigstens einen Schritt zurückzutreten und zu überdenken, was man gerade tut. Vielleicht wäre es hilfreich, die Deming-Philosophie zu verwenden, bei der es um schrittweise Verbesserung geht. Deming war ein Management-Theoretiker, der Japan in den 1950-er Jahren beigebracht hat, Produkte effizient zu fertigen.

Nach dem Zweiten Weltkrieg lag die japanische Wirtschaft ja in Trümmern. Als sie mit dem Wiederaufbazu begannen, sagten sie sich: Es muss einen besseren Weg als den herkömmlichen geben. Zuvor hatten sie folgendermaßen gearbeitet: „OK, jetzt haben wir all diese Füllfederhalter produziert, jetzt schauen wir, welche in Ordnung sind und werfen wir die weg, die fehlerhaft sind.“

(ID:44562071)