Björn Geisemeyer
Björn Geisemeyer

Warum Exceptions keine Fehler sind

Das Thema Fehlerbehandlung wird in vielen Unternehmen nicht oder ungenügend vermittelt. Ich habe an meinen Arbeitsplätzen nie eine klare Definition bekommen, was “Fehler” sind und wie ich damit umgehen sollte. So geht es offensichtlich vielen, denn diese Wissenslücke führt unter anderem zu der verbreiteten, schlechten Angewohnheit, die sich defensive Programmierung nennt. Außerdem wird eine Exception üblicher- wie fälschlicherweise als Fehler betrachtet. In zwei Beiträgen möchte ich Aufklärungsarbeit leisten und ein besseres Verständnis für Exceptions und den Umgang mit ihnen vermitteln. Im Kontext dieses Schwerpunkts werde ich auch das Thema Fehlerbehandlung näher beleuchten und zu Beginn einen kurzen Überblick über die drei Kategorien von Fehlern geben.

Einen ausführlichen Beitrag zu den Kategorien von Fehlern findest du hier.

Bedienerfehler

Ein Bedienerfehler tritt auf, wenn falsche oder fehlende Eingaben in der Benutzerschnittstelle (UI) einer Anwendung gemacht werden. Dabei spielt es keine Rolle, um welche Art von Anwendung es sich handelt, wie die Benutzerschnittstelle gestaltet ist oder wer die Benutzenden sind – seien es Personen oder andere Anwendungen. Die Benutzerschnittstelle kann verschiedene Formen annehmen, wie beispielsweise ein Kommandozeileninterface (CLI), eine Konsole, eine grafische Oberfläche (GUI), Endpunkte eines Webservices oder die öffentliche Schnittstelle eines Softwarepakets. Die Benutzerschnittstelle reflektiert die Anforderungen der Benutzerrolle an die Anwendung und dient als Portal für die verschiedenen Anwendungsfälle (Use Cases). Durch die Benutzerschnittstelle werden Daten von den Benutzenden in die Anwendung eingegeben. Es ist wichtig, diese Daten zu überprüfen, da sie fehlerhaft sein können. Bedienerfehler sind vorhersehbar, daher können wir passgenaue Lösungen für sie entwickeln.

Fehler in der Umgebung

Anwendungen sind üblicherweise mit externen Datenquellen verbunden. Beispielsweise das Dateisystem, Services, Datenbanken oder Hardware wie Messgeräte und Maschinen. Über APIs (Application Programming Interfaces) kommuniziert die Anwendung mit diesen Ressourcen und erwartet Ergebnisse. Ein API fungiert als Schnittstelle, die es der Anwendung ermöglicht, mit anderen Softwarebausteinen oder externen Diensten zu interagieren. Die gelieferten Ergebnisse können entweder die gewünschten Ergebnisse sein oder unerwünschte Ergebnisse. Ein Zugriff auf eine Datei kann scheitern, ebenso wie die Verbindung zu einer Datenbank oder einem Service. Eine angesprochene Hardware könnte abgeschaltet sein. In solchen Fällen liefert das API unter anderem Error Codes oder Exceptions als Rückmeldung. Diese bilden Zustände ab, in denen das gewünschte Ergebnis nicht geliefert werden kann. Ausnahmen werden über das API definiert. Dadurch sind sie vorhersehbar und wir können passgenaue Lösungen für sie entwickeln.

Entwicklerfehler

Entwicklerfehler sind Fehler, die wir als Entwickelnde selbst in unseren Code einbauen, indem wir in unserer Logik etwas übersehen oder vergessen. Arbeiten wir in einer Managed Runtime (bspw. CLR oder JVM), führt dies häufig zur Auslösung einer Exception. Im Gegensatz zu den Bedienerfehlern oder den Fehlern in der Umgebung sind diese Fehler für uns nicht vorhersehbar. Logischerweise kann im Gegensatz zu den anderen Kategorien hier keine passgenaue, explizite Lösung geschaffen werden. Eine Lösung für solche Fälle kann ein globaler Exception-Handler sein, der sich um alle im Programm auftretenden Exceptions kümmert, die sonst nicht behandelt werden.

Vertrauensgrenzen

Die Kategorien Bedienerfehler und Fehler in der Umgebung beschreiben, wo eine Anwendung mit Daten von außen arbeitet. UI und ressourcenseitige APIs stellen Eintritts- und Austrittspunkte zur internen Logik dar. Hier müssen Daten validiert werden. Eine vollständige Validierung an den Grenzen garantiert, dass innerhalb der Logik nur gültige Daten existieren. Es sei denn, die Entwickelnden, also wir, haben etwas übersehen und einen Entwicklerfehler eingebaut. Die Validierungen gewährleisten, dass die Bedienerfehler und Fehler in der Umgebung an den Grenzen unserer Logik verarbeitet werden. Bei der ressourcenseitigen Ergebnisprüfung spielt die Exception häufig eine große Rolle.

Was sind Exceptions?

Erfahrung mit Exceptions haben wohl alle Entwickelnden. Viele interpretieren sie als Fehler, da sie oft bei Entwicklerfehlern ausgelöst werden. Auch in der Literatur oder in diesem Beitrag geht es um das Thema Fehler, wenn von Exceptions die Rede ist. Logisch, denn Exceptions sind auch das Ergebnis von Fehlern. Letzten Endes sind sie aber genau das – ganz normale Ergebnisse. Exceptions sind Klassen, in denen Informationen definiert sind. Sie werden uns von Runtime- und Frameworkmethoden oder Paketen zurückgegeben. Also gerade bei der Nutzung von APIs sind Exceptions ein gängiges Ergebnis. Sie repräsentieren, wie der Name besagt, eine Ausnahme. Ein Beispiel:

				
					public class FileProvider
{
	public IEnumerable<string> ReadFileContent(string filename) {
		return File.ReadAllLines(filename);
	}
}

				
			

Dieses Beispiel wird uns durch beide Teile des Beitrags begleiten. Eine Klasse FileProvider stellt eine Methode ReadFileContent zur Verfügung. Im ersten Beitrag ruft diese Methode lediglich die Runtime-Methode File.ReadAllLines auf, ohne eigene Logik zu ergänzen. Das Hauptaugenmerk liegt in der Betrachtung der Methode File.ReadAllLines und den zu erwartenden Ergebnissen. Sehen wir uns die Signatur der umschließenden Methode ReadFileContent an, können wir das erste mögliche Ergebnis ablesen. Den Use Case, bei dem der Inhalt der Datei wie gewünscht zurückgegeben wird. Die übrigen möglichen Ergebnisse finden sich in Form von Exceptions in der Dokumentation der Methode File.ReadAllLines [Abb. 1].

Exceptions Fehler
Abbildung 1

Insgesamt sind neun verschiedene Ausnahmen definiert. Die meisten beziehen sich auf den Inhalt des Parameters path, andere auf Zugriffsrechte. Alle geben über ihren Typ und eine zugehörige Message Einblick in den Grund, aus dem das gewünschte Ergebnis nicht geliefert werden kann. Diese Dokumentation verdeutlicht, dass hinter der scheinbar simplen Methodensignatur File.ReadAllLines offensichtlich viel Arbeit steckt. Das Auslesen einer Datei aus dem Dateisystem ist kein Einzeiler. Diese Methode macht den Zugriff für Nutzende vermeintlich zu einem. Doch auf dem Weg zum einfachen Rückgabewert gibt es Regeln, die erfüllt sein müssen. Sind sie es nicht, werden aussagekräftige Ausnahmen zurückgegeben. Diese Ausnahmen sind keine Fehler, sondern lediglich Abweichungen vom regulären Ergebnis der Methode. Sie repräsentieren frühe Ausstiege aus einem Workflow, Vorbedingungen, die nicht erfüllt sind. Zur Veranschaulichung des Workflows habe ich die Grafik [Abb. 2] entworfen. Sie basiert auf der Entwurfssprache Flow Design, die wir in unseren Seminaren vermitteln.

Abb. 2 File.ReadAllLines FD exceptions fehler
Abbildung 2

Die Grafik verdeutlicht, was innerhalb der Methode geschieht. Alle Schritte werden nacheinander überprüft. Wenn alle Bedingungen erfüllt sind, liefert die Methode das gewünschte Ergebnis zurück. Falls nicht, wird mittels throw eine Ausnahme generiert, die Informationen über die nicht erfüllte Bedingung liefert. Für Aufrufende der Methode entsteht ein enormer Gewinn. Es ist lediglich ein einziger Aufruf erforderlich und intern werden alle Zustände geprüft. Entwickelnde bekommen nicht ein Ergebnis, sondern zehn mögliche Zustände, zu denen eine Lösung geschaffen werden kann. Sie müssen nur dafür sorgen, dass sie damit umgehen können.

Fazit

Exceptions sind keine Fehler, sondern Ergebnisse, die nicht erfüllte Bedingungen beschreiben. Sie sind ein normaler Bestandteil eines Workflows. Eine Methode, die potenziell eine Exception liefert, liefert eben mehr als nur ein Ergebnis. Daraus ergibt sich im Programmablauf lediglich eine zustandsbedingte Fallunterscheidung. Die Runtime unterscheidet nicht zwischen richtig und falsch. Sie liefert Ergebnisse. Die Feststellung, ob ein Fehler zu einer Exception geführt hat, kann nur im Kontext beantwortet werden. Wie mit Exceptions umgegangen wird, liegt in der Verantwortung der Nutzenden der Methode. In diesem Sinne behandelt Teil 2 dieses Beitrags den Umgang mit Exceptions.

Unsere Seminare

course
Clean Code Developer Basics

Prinzipien und Tests – Das Seminar wendet sich an Softwareentwickler, die gerade beginnen, sich mit dem Thema Softwarequalität auseinanderzusetzen. Es werden die wichtigsten Prinzipien und Praktiken der Clean Code Developer Initiative vermittelt.

zum Seminar »
course
Clean Code Developer Advanced

Mit Flow Design von den Anforderungen zum Clean Code – Lernen Sie mit Flow Design einen Softwareentwicklungsprozess kennen, der Sie flüssig von den Anforderungen zum Clean Code führt.

zum Seminar »
course
Clean Code Developer Trainer

Seminare als Trainer durchführen – Dieses Seminar wendet sich an Softwareentwickler, die ihr Wissen über die Clean Code Developer Prinzipien und Praktiken bzw. über Flow Design als Trainer an andere weitergeben möchten.

zum Seminar »
course
Clean Code Developer CoWorking

Online CoWorking inkl. Coaching –
Wir werden häufig gefragt, was man als Entwickler tun könne, um kontinuierlich dran zu bleiben am Thema Clean Code Developer. Unsere Antwort: Treffen Sie sich regelmäßig wöchentlich online mit anderen Clean Code Developern.

zum Seminar »

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

de_DEGerman