Wie gut, dass es Regressionstests gibt. Anfang dieser Woche hatte ich ein wirklich gutes Gefühl, was den neuen Code angeht, den ich geschrieben und (wie ich dachte) fehlerfrei gemacht hatte. Ich bin gerade dabei, die OpenVOS-POSIX-Funktionen zu verbessern, die binäre Zeitwerte in die aufgeschlüsselte Zeitstruktur ("struct tm" für C-Experten) umwandeln. Damals, 1998, als ich diese Routinen modifizierte, damit sie in der POSIX-Umgebung funktionieren, nahm ich eine Abkürzung und rief die zugrunde liegenden VOS-Kernel-Subroutinen auf. Dieser Ansatz war schnell und einfach, aber er bedeutete, dass unsere POSIX-Laufzeiten keine Daten zwischen 1970 und 1980 verarbeiten konnten, weil VOS diese Daten nicht verarbeitet. In letzter Zeit habe ich mehrere große neue Open-Source-Pakete auf OpenVOS 17.0 portiert. Ich entdeckte, dass eine Reihe von Tests fehlschlugen, weil wir diesen Datumsbereich nicht handhaben konnten. Also habe ich mich an die Aufgabe gemacht, den Code so zu ändern, dass er alle Datumsangaben sowohl in der VOS- als auch in der UNIX-Epoche (1970 bis 2048) verarbeiten kann. Ich wusste, dass diese Aufgabe fehleranfällig sein würde, und ich war entschlossen, einen Weg zu finden, alle Fehler aus dem Code zu entfernen. Einer der Vorteile bei der Arbeit mit Datumsangaben ist, dass die Menge endlich ist. Und da moderne Computer recht schnell sind, ist es nicht so schwer, sie einfach alle möglichen Kombinationen durchspielen zu lassen und zu sehen, was passiert. Aus Gründen, die ich hier nicht näher erläutern möchte, wollte ich sichergehen, dass ich den Bereich des Codes, der die Jahre 1970 und 1971 behandelt, testen kann. Also schrieb ich einen Test, der 2 Mal pro Tag umrechnete, beginnend am 1. Januar 1970 und bis zur Gegenwart. Er verbrauchte nur den Bruchteil einer Sekunde an CPU-Zeit. Natürlich fand ich einen Zaunpfahlfehler in meinem Code. Ich korrigierte den Fehler und der Test war erfolgreich. Ich hatte ein gutes Gefühl bei diesem Prozess, meine Prüfer bestätigten die Änderungen, und ich dachte, ich sei fertig. Dann ließ ein Kollege von mir die Regressionstestsuite über meine Änderungen laufen. Das machen wir nach jeder Änderung an den Compilern und ihren Laufzeiten, um sicherzustellen, dass wir nicht versehentlich etwas kaputt machen. Leider schlugen mehrere der Regressionstests fehl. Als ich herausfand, warum meine Tests trotz der offensichtlichen Gründlichkeit der Tests das Problem nicht erkannt hatten, stellte ich fest, dass die Probleme erst im Jahr 2038 auftraten. Ich hatte zwar die Dekade von 1970 bis 1980 in die Zeitroutinen eingefügt, aber die Dekade von 2038 bis 2048 gestrichen. Als ich zurückging und jeden Tag in diesem Bereich testete, stellte ich fest, dass mein Test das Problem erkannt hätte, wenn ich ihn nur darum gebeten hätte.
Was ist die Lehre daraus? Die offensichtlichste ist wohl, dass man, wenn man alle Kombinationen testen kann, auch wirklich alle Kombinationen testen sollte. Eine vielleicht noch wichtigere Lehre ist, dass man sich die Zeit nehmen sollte, eine Regressionstestsuite zu erstellen. Sie sind die Zeit und den Aufwand wert. Sie können die Kosten senken und die Zeit für das Auffinden und Beheben von Problemen verkürzen, wenn Sie Ihren Code verbessern. Sie müssen nicht sehr viele von Kunden gemeldete Probleme vermeiden, um die Kosten für die Erstellung einer Regressionstestsuite zu rechtfertigen. Ich schätze, dass die Kosten für die Behebung eines Softwareproblems mit jeder zusätzlichen Phase im Prozess um eine Größenordnung ansteigen. Da es in jedem Prozess mindestens 4 Phasen gibt (Entwurf, Code, Test, Bereitstellung), wird es schnell teuer.