Lektion 8.2

Softwarequalität, Testen, Entwurfsmuster und Benutzungsoberflächen

18 min Lesezeit

Nach einem Update stürzt die Bank-App bei manchen Nutzern ab, und eine Fahrplan-App zeigt Züge, die es nicht gibt. In beiden Fällen lief das Programm, nur nicht so, wie man es braucht. Wann ist Software also gut? Wie findet man Fehler, bevor Nutzer sie finden? Und wie baut man ein Programm, das man später noch ändern kann, ohne dass es auseinanderfällt? Darum geht es hier.

Definition

Softwarequalität, Gütekriterien und Verantwortlichkeit

Softwarequalität ist, wie gut eine Software ihre Anforderungen erfüllt. Gebräuchliche Gütekriterien:

  • Korrektheit: Sie tut, was verlangt wurde.
  • Zuverlässigkeit: Sie kommt mit Fehleingaben und Ausfällen zurecht (Robustheit).
  • Effizienz: Sie braucht angemessen wenig Zeit und Speicher.
  • Sicherheit: Sie schützt Daten und widersteht Angriffen.
  • Benutzbarkeit: Nutzer erreichen ihre Ziele leicht.
  • Wartbarkeit: Sie lässt sich verstehen, ändern und erweitern.
  • Portabilität: Sie läuft auf verschiedenen Systemen.

Die Kriterien können einander widersprechen, etwa Effizienz und Wartbarkeit. Wer Software entwickelt, trägt Verantwortung für ihre Folgen: Fehler in Fahrzeugen, Medizingeräten oder Banken können Menschen gefährden oder Geld kosten. Dazu gehören Qualitätssicherung, offener Umgang mit Risiken und der Schutz personenbezogener Daten.

Definition

Softwareergonomie, Benutzungsfreundlichkeit und Barrierefreiheit

Softwareergonomie gestaltet Oberflächen so, dass sie zu Menschen und Aufgaben passen. Benutzungsfreundlichkeit heißt: Nutzer erreichen ihre Ziele wirksam, effizient und zufrieden. Grundsätze der Dialoggestaltung (aus der Norm ISO 9241-110) sind unter anderem:

  • Aufgabenangemessenheit: Die Software unterstützt die Aufgabe ohne unnötigen Aufwand.
  • Selbstbeschreibungsfähigkeit: Nutzer erkennen, wo sie sind und was als Nächstes möglich ist.
  • Erwartungskonformität: Die Software verhält sich so, wie man es von ähnlichen Programmen gewohnt ist.
  • Steuerbarkeit: Nutzer bestimmen Tempo und können abbrechen oder zurückgehen.
  • Fehlertoleranz: Fehleingaben richten keinen Schaden an, und Meldungen sagen, wie man den Fehler behebt.

Barrierefreiheit heißt, dass auch Menschen mit Einschränkungen die Software nutzen können, etwa bei Blindheit, Farbsehschwäche, Schwerhörigkeit oder eingeschränkter Beweglichkeit. Dazu dienen Alternativtexte für Bilder (für Screenreader), ausreichender Kontrast, Bedienung allein mit der Tastatur, skalierbare Schrift, Untertitel und der Grundsatz, Informationen nie nur durch Farbe zu zeigen. Für Webseiten gibt es dazu die Web Content Accessibility Guidelines (WCAG).

Definition

Teststrategien, Unit- und Integrationstests, testgetriebene Entwicklung

Ein Test führt die Software mit gewählten Eingaben aus und vergleicht das Ergebnis mit dem erwarteten. Tests können Fehler finden, aber nicht beweisen, dass keine mehr vorhanden sind. Man testet in Stufen:

  • Unit-Test: prüft eine kleine Einheit, etwa eine Funktion oder Klasse, für sich allein.
  • Integrationstest: prüft, ob Einheiten über ihre Schnittstellen zusammenarbeiten.
  • Systemtest: prüft das ganze System gegen die Anforderungen.

Testfälle wählt man systematisch. Eine Äquivalenzklasse fasst Eingaben zusammen, die gleich behandelt werden, ein Vertreter genügt. Grenzwerte liegen an den Rändern der Klassen, dort sind Fehler häufig. Bei Black-Box-Tests kennt man nur die Spezifikation, bei White-Box-Tests auch den Code. Bei der testgetriebenen Entwicklung (TDD) schreibst du zuerst einen Test, der fehlschlägt, dann gerade so viel Code, dass er besteht, und räumst danach auf. Alle Tests laufen nach jeder Änderung erneut, damit neue Fehler auffallen.

Beispiel

Unit-Tests für ein Schaltjahr

Die Funktion soll prüfen, ob ein Jahr ein Schaltjahr ist: durch 4 teilbar, aber nicht durch 100, es sei denn, es ist durch 400 teilbar. Eine erste Version:

ZeileEinrückungAnweisung
10def ist_schaltjahr(jahr):\texttt{def ist\_schaltjahr(jahr):}
21return jahr % 4 == 0\texttt{return jahr \% 4 == 0}

Welche Testfälle decken den Fehler auf?

Man wählt je einen Vertreter pro Äquivalenzklasse: normales Jahr, durch 4 teilbar, Jahrhundert ohne 400, Jahrhundert mit 400.

JahrSollwertVersion 1 liefertErgebnis
2023FalseFalsebestanden
2024TrueTruebestanden
1900FalseTruedurchgefallen
2000TrueTruebestanden

Nur der Test mit 1900 deckt den Fehler auf. Die Korrektur ist return (jahr % 4 == 0 and jahr % 100 != 0) or jahr % 400 == 0\texttt{return (jahr \% 4 == 0 and jahr \% 100 != 0) or jahr \% 400 == 0}. Danach laufen alle vier Tests erneut.

Definition

Refaktorierung und Dokumentation

Refaktorierung verbessert die innere Struktur des Codes, ohne sein Verhalten zu ändern: bessere Namen, doppelten Code in eine Methode ziehen, lange Methoden teilen. Die Tests zeigen, dass nach dem Umbau alles noch funktioniert. Dokumentation besteht aus Kommentaren, die das Warum erklären, aus Beschreibungen der Schnittstellen, einer Übersicht über den Aufbau und einem Handbuch für Nutzer. Sie muss zusammen mit dem Code gepflegt werden, sonst führt sie in die Irre.

Definition

Entwurfsmuster: Observer und Model-View-Controller

Ein Entwurfsmuster ist eine bewährte Lösung für ein wiederkehrendes Entwurfsproblem.

  • Observer: Ein Objekt, das Subjekt, führt eine Liste von Beobachtern. Ändert sich sein Zustand, ruft es bei jedem Beobachter eine Methode wie aktualisieren\texttt{aktualisieren} auf. Beobachter melden sich an und ab. Das Subjekt kennt nur die Schnittstelle der Beobachter, nicht deren Klassen, die Kopplung ist lose.
  • Model-View-Controller (MVC): Das Model hält Daten und Fachlogik, die View stellt sie dar, der Controller nimmt Eingaben entgegen und ruft das Model auf. Die View beobachtet das Model. So lassen sich Darstellung und Logik getrennt ändern und testen.
Beispiel

MVC bei einer Zähler-App

Eine App zählt Besucher. Auf dem Bildschirm steht der Zählerstand und eine Taste „+“. Welche Teile arbeiten, wenn jemand auf „+“ tippt?

  • Der Controller bekommt den Tastendruck und ruft erhoehen()\texttt{erhoehen()} am Model auf.
  • Das Model erhöht den Zählerstand und meldet die Änderung allen Beobachtern (Observer).
  • Die View ist als Beobachter angemeldet, wird aktualisiert und zeigt den neuen Stand.

Das Model weiß nichts von Bildschirm oder Tasten. Man kann es also ohne Oberfläche mit Unit-Tests prüfen und später eine zweite View anmelden, etwa eine Anzeige am Eingang.

Definition

Versionsverwaltung, Bugtracking, Schnittstellen und Modularisierung

Versionsverwaltung (zum Beispiel Git) speichert jede Änderung als Version, den Commit, mit Autor, Zeit und Nachricht. So kann man zu früheren Ständen zurückgehen. In Branches entwickelt man Linien parallel und führt sie per Merge zusammen. Das Repository enthält die ganze Geschichte. Bugtracking verwaltet Fehler als Tickets mit Beschreibung, Schritten zum Nachstellen, Priorität, Zuständigem und Status.

Eine Schnittstelle (API) legt fest, wie man einen Teil von außen benutzt (Methoden, Parameter, Rückgaben), ohne seine Umsetzung zu kennen. Modularisierung zerlegt ein System in Module mit hoher Kohäsion (ein Modul, eine Aufgabe) und loser Kopplung (wenige Abhängigkeiten), die nur über Schnittstellen zusammenarbeiten. Module lassen sich einzeln testen, austauschen und im Team verteilen.

Häufige Fehler

Alle Tests bestanden heißt fehlerfrei

„Alle Tests laufen grün, also hat die Software keine Fehler.“

Richtig ist

Tests zeigen nur, dass die geprüften Fälle richtig sind. Im Beispiel hätten 2023, 2024 und 2000 allein den Fehler nicht gefunden. Gute Tests decken Äquivalenzklassen und Grenzwerte ab, bleiben aber eine Stichprobe.

Häufige Fehler

Refaktorierung heißt neue Funktionen einbauen

„Beim Refaktorieren baue ich gleich noch die gewünschte Suchfunktion ein.“

Richtig ist

Refaktorierung ändert nur die Struktur, nicht das Verhalten. Eine neue Funktion ist eine Erweiterung. Trenne beides, damit ein Test, der nach dem Umbau fehlschlägt, eindeutig auf den Umbau zeigt.

Zusammenfassung

  • Softwarequalität zeigt sich in Kriterien wie Korrektheit, Zuverlässigkeit, Sicherheit, Benutzbarkeit und Wartbarkeit. Entwicklerinnen und Entwickler tragen Verantwortung für die Folgen.

  • Softwareergonomie fragt nach Aufgabenangemessenheit, Selbstbeschreibung, Erwartungskonformität, Steuerbarkeit und Fehlertoleranz. Barrierefreiheit ermöglicht Menschen mit Einschränkungen die Nutzung.

  • Unit-Tests prüfen Einheiten, Integrationstests ihr Zusammenspiel. Testfälle wählt man nach Äquivalenzklassen und Grenzwerten. Bei TDD steht der Test vor dem Code.

  • Refaktorierung verbessert die Struktur ohne Änderung des Verhaltens, Tests sichern sie ab. Dokumentation erklärt Schnittstellen, Aufbau und Gebrauch.

  • Der Observer meldet Zustandsänderungen an angemeldete Beobachter. MVC trennt Daten (Model), Darstellung (View) und Eingabe (Controller).

  • Versionsverwaltung, Bugtracking, Schnittstellen und Modularisierung machen Teamarbeit und spätere Änderungen beherrschbar.

Übungen

Aufgabe 1Multiple Choice

Welche Testart prüft, ob zwei Klassen über ihre Schnittstellen richtig zusammenarbeiten?

Aufgabe 2Multiple Choice

Eine Funktion soll Alterswerte von 14 bis 18 (einschließlich) akzeptieren. Welche Testwerte sind Grenzwerte?

Aufgabe 3Multiple Choice

In einer App tippt jemand auf „Löschen“. Welcher Teil des MVC-Musters nimmt diese Eingabe entgegen?

Aufgabe 4Numerisch

Ein Sensor hat zuerst 3 angemeldete Beobachter. Er ändert seinen Wert zweimal. Dann meldet sich ein vierter Beobachter an, und der Sensor ändert seinen Wert noch dreimal. Wie oft wird insgesamt die Methode aktualisieren aufgerufen?

Aufgabe 5Freitext

Eine Lern-App zeigt falsche Antworten nur durch einen roten Rahmen. Nenne zwei Gründe, warum das nicht barrierefrei ist, und eine bessere Lösung.