Ist mein Code korrekt?
Das ist die Frage der Fragen – nicht nur für Anfänger in der Programmierung. Immerhin gibt es zu einer Aufgabenstellung meistens mehr als eine korrekte Lösung. Die Musterlösung ist lediglich ein Beispiel einer möglichen Lösung. Wie also können wir wissen, ob unser Code korrekt ist?
Die Fragestellung ist alt – die Antwort (vielleicht) überraschend:
es gibt keine Möglichkeit, die Korrektheit von Code eindeutig sicherzustellen. Die Theoretiker haben sich intensiv damit befasst.
Und doch verlassen wir uns mit der Digitalisierung nahezu blind darauf, dass Code richtig funktioniert.
Welch riesige Verantwortung für die Programmierer!
Was bedeutet schon ‘richtig funktionieren’? Und wer sagt, ob das Programm ‘richtig funktioniert’?
Gehen wir zunächst dieser Frage nach.
Diffuse Anforderungen erheben – Requirements Engineering
Wissen die Endanwender unserer Programme überhaupt, was sie wollen?
Diese Antwort ist einfach: nein, meistens nicht.
Jedenfalls nicht so genau oder nicht genau genug, um daraus eine eindeutige Anforderung an ein Programm zu formulieren und zwar so präzise, dass die Programmierer in jedem Fall eindeutig wissen, was zu tun ist.
Die Erhebung dieser Anforderungen ist ein langer Prozess mit einem Moving Target.
Und doch gibt es so viele gut funktionierende Programme, dass wir uns im Rahmen der Digitalisierung immer abhängiger davon machen.
Requirements Engineering ist ein Beruf geworden. Wer diesen ausübt, erhebt die Anforderungen der Auftraggeber und Endnutzer, schreibt sie auf, und formalisiert sie so, dass daraus relativ eindeutige Arbeitsaufträge abgeleitet werden können.
Sobald die Endanwender das fertige Programm sehen, werden sie viel besser sagen können, was sie eigentlich meinten und ihre Anforderungen präziser ausdrücken können.
Aus dieser Erkenntnis hat sich das agile Vorgehen herauskristallisiert: ein Team entwickelt in kurzen Zyklen kleine Teile der Funktionalität der App, so dass die Enduser anhand des fertigen Programms ihre Anforderungen präzisieren können. So wächst das Programm nach und nach.
Die Requirements Engineers sind an vorderster Front tätig und sie können’s gut mit Menschen.
Software Engineering
Software Engineers zerlegen die Requirements, also die Anforderungen, in kleine Stücke und diese wiederum in kleinere Stücke, bis ganz einfach formulierbare Einheiten (Units) daraus entstehen.
So einfach, dass sie jede Einheit gut beschreiben und auch gut testen können.
Dann programmieren sie Einheit um Einheit, testen sie, und setzen sie zusammen zu einem Großen und Ganzen, testen auch dieses und überlassen diese App den Auftraggebern.
Diese begutachten die App und stellen neue Anforderungen.
Software wird heutzutage in solchen kurzen Zyklen nach und nach entwickelt.
Das Dilemma der Anfänger
Wer Programmieren lernt, fängt an mit kleinen Aufgaben – etwa so groß wie diese Einheiten (oder Units), in die produktive Programme zerlegt werden.
Wer lernen und üben will, benötigt also viele solcher Aufgaben.
Erschwerend kommt hinzu, dass es zu einer einzelnen Aufgabe in der Regel viele mögliche und korrekte Lösungen gibt. Nicht nur die Beispiellösung, die wir vielleicht auch erhalten.
Und da entsteht die große Unsicherheit: Wie weiß ich als Anfänger, ob mein Code richtig funktioniert?
Die Antwort auf die Frage holen wir uns in der Praxis: Wie weiß ich als Profi, ob mein Code richtig funktioniert?
Im Rahmen der Entwicklungszyklen sind oft kleinste Änderungen am Code notwendig. Wie kann ich sicher sein, dass das Große Ganze noch korrekt funktioniert?
Diese Frage ist bei der Programmierung so zentral, dass ein weiteres Berufsfeld entstanden ist: Das Test Engineering.
Test Engineering
Ein Test Engineer nimmt die Vorgaben des Requirements Engineers und die Aufteilung der Aufgaben in Units der Software Engineers und schreibt daraus Testfälle – so genannte Unit-Tests.
Das sind eigenständige Programme, die den Code der Programmierer automatisch testen.
Ändere ich als Programmiererin oder Programmieren meinen Code an einer Stelle leicht ab, dann lasse ich die ganze Test-Suite laufen.
Ist sie erfolgreich, dann kann ich (ziemlich) sicher sein, dass das Gesamtprogramm weiterhin korrekt läuft.
Jedenfalls gleich korrekt wie zuvor – denn auch Test Engineers sind nicht unfehlbar.
Testfälle entwickeln ist einerseits aufwändig und andererseits ein zentraler Erfolgsfaktor bei der Software-Entwicklung.
Gerade weil die Programme zuerst in Zyklen entwickelt werden und später ständig gepflegt werden. Testfälle sichern die Qualität.
Die Berufsbilder werden nicht überall scharf getrennt und eine Person kann alle Aufgaben wahrnehmen.
TDD beim Programmieren lernen
Schreiben wir zuerst die Testfälle und erst dann den Code dazu, dann werden die Testfälle zur Spezifikation für die Programmierer.
Man spricht von Test Driven Development (TDD).
TDD ist dann auch die Antwort auf die eingangs gestellte Frage:
Wenn wir jetzt Programmieren lernen, dann können wir sicher sein, dass unser Code richtig läuft, wenn wir nicht nur viele Übungsaufgaben erhalten, und mögliche Beispiellösungen dazu, sondern auch Test-Suiten- die uns helfen sicher zu sein, dass die selbst erdachte Lösung korrekt funktioniert.
Erfahrene Coaches schenken den Unit Tests in einem Programmierkurs spezielle Aufmerksamkeit und entwickeln sie mit Sorgfalt im Hinblick auf die Aufgabenstellung.
Lernen mit Unit Tests
Das Video zeigt ein sehr einfaches Beispiel, wie Lernaufgaben in Python mit Hilfe von Unit Tests formuliert und ausgeführt werden.
Fazit:
Die Unsicherheit, ob der Code korrekt funktioniert, begleitet Programmierer durchs Berufsleben.
Funktionierende Software wird in kurzen Zyklen gemeinsam mit den Endusern und Auftraggebern entwickelt.
Gut entworfene und gepflegte Testfälle verringern die Unsicherheit, erhöhen die Code-Qualität und sind ein unverzichtbares Element bei der langfristigen Pflege von Code.
Auch Anfänger profitieren von Testfällen für ihre Trainingsaufgaben.