Zum Inhalt springen

Exceptions für Fortgeschrittene


lilith2k3

Empfohlene Beiträge

Hallo,

zunächst eine Entschuldigung an den Mod, der evtl. das Thema verschieben darf, weil hier nicht der geeignete Ort ist. Es hat nichts mit Algorithmik per se zu tun. Aber mir ist echt auch nach 5 Minuten kein Subforum eingefallen, wo ich das Thema hätte anlegen können. Soetwas wie "Softwarearchitektur" oder so gibt es ja leider nicht. Zumindest hab ich sowas nicht gefunden ;)

Meine Frage ist im Grunde eine philosophische und es gibt natürlich kein Patentrezept - das ist mir klar. Aber ich möchte mir zumindest Meinungen und Rat einholen.

Es geht darum, dass viele Softwareprojekte eben sogenannte "n-tier" oder "Multilayer" Anwendungen sind.

Zur Diskussion vielleicht folgendes Beispiel aus meiner Praxis:

Ich habe eine Webanwendung, die per REST Daten an's Backend liefert. Das ganze wird mittels MVC-Framework realisiert (welches, ist in dem Falle ja mal egal). Das heißt, nach dem Dispatching schlagen die Daten im Controller auf.

Der Controller reicht die Sachen an den Service-Layer weiter. Der Servicelayer seinerseits kümmert sich um die Validierung der Daten. Anschließend werden die Daten im DAL (Data-Access-Layer) zum Persistieren aufbereitet.

Die Frage, die sich nun stellt: Wo schmeiße ich welche Exceptions und wo fange ich die wieder auf?

Bisher werfe ich Validierungsexceptions im Service-Layer und fange sie im darüberliegenden Layer (also dem aufrufenden Controller), wo die Sachen darüber hinaus auch weggelogged werden. Aber was mache ich beispielsweise mit Exceptions aus dem DAL? Fange ich die im Service-Layer ab und werfe von da ausgehend eine für den Layer eigene Exception? Also quasi: ich fange eine SQL-Exception im Data-Layer und packe eine "Data-Layer-Exception" drumrum. Anschließend fange ich die Exception im Service-layer und packe eine "Service-Layer-Exception" drumrum und schmeiße die wieder weiter nach oben .Oder lasse ich alle Exceptions einfach "hochbubblen" und fange die im obersten Layer ab?

Fachlich richtiger wäre es wahrscheinlich die Exceptions im entsprechenden Layer aufzufangen, aber andererseits hat man dann einen Rattenschwanz an Exceptions. Das kann ja schnell Inflationär werden.

Bin gespannt auf die Diskussion.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich habe jetzt wenig bis keine Ahnung von Architekturen... aber aus einem rein pragmatischen Ansatz heraus würde ich sagen: Dort, wo sie relevant sind. Wie im richtigen Leben.

Wenn eine Exception durch eine Anwenderaktion ausgelöst wurde, sollte der Anwender davon in geeignetem Umfang Kenntnis bekommen, damit er z.B. nicht fälschlich davon ausgeht, dass seine Datenänderungen geschrieben wurden. Er sollte auch wissen, was er tun kann/sollte. Sollte er jemanden informieren? Wenn ja, welche Informationen sollte er weitergeben? Findet die Informierung bereits an anderer Stelle statt? SQL-Exception wegen nicht maximal wachsender und jetzt voller Protokolldatei... da kann dann auch gleich die nächsthöhere Schicht per EMail den Admin informieren.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Interessanter Beitrag! ... :uli

Grundsätzlich würde ich mal sagen, dass Exceptions dann geworfen werden sollen, wenn es angebracht ist (Bsp.: Fehlbedienung, fehlende Connection, etc.).

Wenn es sich bei dem Produkt um eine Client-/Serveranwendung handelt, ist es natürlich eine Überlegung wert, wem was und wie gemeldet wird, oder wie und was abgefangen wird.

Daher würde ich die Überlegung anstellen, was man sofort meldet, oder was man z.B. in einer Datenbank loggen kann, damit die Administration ggf. darauf reagieren kann/muss. Bei Critical Error denn auch noch eine Information an die Administration (per Mail, SMS, etc.). Ich denke wie groß man den Aufwand betreibt, hängt 1. vom Produkt, 2. von den Vorgaben, 3. von der Quallitätssicherung, etc. ab.

Das war es mal grob/adhoc, was mir zu diesem Thema eingefallen ist.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich würde Pixie zustimmen und noch ergänzen: Exceptions sollten da gefangen werden, wo sie auch tatsächlich behandelt werden können.

Natürlich hängt es auch immer von der Sprache und dem Szenario ab: wenn ich selbst der einzige Anwender bin und jederzeit in kritische Aktionen eingreifen möchte, würde ich gar nicht werfen, sondern direkt einen Debugger öffnen, um das Problem zu lösen - besonders bei Smalltalk und Lisp-Systemen geht das ganz gut. Java und C# sind mit Quelltextersetzungen zur Laufzeit nicht so gut aufgestellt, so dass man dort häufiger neu deployen muss, wenn Fehler auftreten.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich würde Pixie zustimmen und noch ergänzen: Exceptions sollten da gefangen werden, wo sie auch tatsächlich behandelt werden können.

Ich nehme dieses Zitat mal als Ansatzpunkt, meine Problemstellung weiter zu beleuchten:

Behandeln (im Sinne von "abfangen, Fehler loggen und ggf. Fehlermeldung generieren") kann ich die Exception in jedem Layer.

Es ist die Frage, ob ich für jeden Layer eigene Exceptions generieren und werfen soll, oder ob ich alle aufkommenden Exceptions -egal von wo- im Controller fange und letztlich nur noch eine Fehlermeldung an den Benutzer mache.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Interessanter Beitrag! ... :uli

Daher würde ich die Überlegung anstellen, was man sofort meldet, oder was man z.B. in einer Datenbank loggen kann, damit die Administration ggf. darauf reagieren kann/muss. Bei Critical Error denn auch noch eine Information an die Administration (per Mail, SMS, etc.). Ich denke wie groß man den Aufwand betreibt, hängt 1. vom Produkt, 2. von den Vorgaben, 3. von der Quallitätssicherung, etc. ab.

Das war es mal grob/adhoc, was mir zu diesem Thema eingefallen ist.

Logging niemals in Datenbanken ... ;-) Anwendungen sollten außerdem Administratoren nicht informieren. Kritische Fehler sollten im Eventlog landen und vom Monitoring System weitergemeldet werden. SRP / SoC und so ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Exceptions fängt man dort ab, wo sie auftreten.

Hallo,

Fachlich richtiger wäre es wahrscheinlich die Exceptions im entsprechenden Layer aufzufangen, aber andererseits hat man dann einen Rattenschwanz an Exceptions. Das kann ja schnell Inflationär werden.

Ich weiß jetzt nicht was du meinst. Meinst du, dass du jede Menge exceptions hintereinander reinprogrammieren musst, oder, dass eine Exception nach der anderen geworfen wird, sobald eine auftritt?

Bei ersterem: Ein Gruß an diese Stelle an alle Java-Programmierer, die schmeißen ja mit unendlich Exceptions um sich ;) Bei letzterem: Normal führt man das Programm ja nicht weiter aus, darum wird nur die unterste Exception geworfen und fertig.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich würde logging nicht als Behandlung einer Exception interpretieren. So etwas kann man auch als Aspekt in den Code einweben. Wenn eine Exception bei der Eingabe von Daten durch einen Nutzer auftritt, kann der Nutzer durch eine Korrektur der Eingabe, den Fehler beheben. Wenn in einem Cluster ein Node ausfällt, kann durch einen anderen Node ein Engpass vermieden werden. In den meisten Fällen kann ich jedoch nichts machen, außer die Exception zu loggen. Das ist interessant für den Programmierer, weil es meist auf einen Bug hindeutet. So etwas würde ich auf der obersten Ebene loggen - oder noch besser: als Apsket einweben -, um der Businesslogik nicht vorzugaukeln, dass tatsächlich etwas behandelt würde.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ein Gruß an diese Stelle an alle Java-Programmierer, die schmeißen ja mit unendlich Exceptions um sich

Ja. Ich liebe diese Stacktraces:rolleyes:

Aber genau um sowas geht es mir.

Bei letzterem: Normal führt man das Programm ja nicht weiter aus, darum wird nur die unterste Exception geworfen und fertig.

Warum führt man das Programm nicht weiter aus?

Beispiel:

Exceptions zur Validierung...

Illegale Objektzustände können so vermieden werden. Es kommt zu einer Validierungsexception und nach einer Benutzerinfo geht's wieder weiter im Programm.

Oder Mehrstufiges Beispiel:

SQL-Exception wird im DAL gefangen und in einer "DatabaseException" gekapselt und weitergereicht.

Auffangen könnte man die an der "Oberfläche" und den Benutzer informieren, dass die Datenbank schrott ist, oder man fängt sie im Service-Layer auf und packt nochmal eine Service-Exception drum, die dann letzten Endes auch wieder an der Oberfläche ankäme, wo sie ähnlich behandelt würde. Allerdings hätte man das Designprinzip für Layer insoweit verletzt, als dass ein Layer nur einen Anknüpfungspunkt zum nächsten darunterliegenden haben sollte.

Ich würde logging nicht als Behandlung einer Exception interpretieren.

Fachlich gesehen gebe ich Dir recht; umgangssprachlich ist logging auch eine Art der Behandlung ;)

Es ging darum, den Fehlerfall zu dokumentieren. Und nicht in jedem Fall ist ein Programmabbruch bei einer Exception nötig, vorallem, wenn es sich um Custom-Exceptions handelt.

Das ist interessant für den Programmierer, weil es meist auf einen Bug hindeutet. So etwas würde ich auf der obersten Ebene loggen - oder noch besser: als Apsket einweben -, um der Businesslogik nicht vorzugaukeln, dass tatsächlich etwas behandelt würde.

Aber es könnte dennoch wert sein, den Benutzer darüber zu informieren, oder?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Anderer Ansatz ist auch, muss für jeden Fehler wirklich auch eine exception geworfen werden. Exceptions sind teuer.

Wie sähe denn der "andere Ansatz" konkret aus?

Wir können ja mal ein konkretes Beispiel durchspielen. Ich fang mal an und Du kannst mir ja Verbesserungsvorschläge geben:

Konkretes Szenario: Lagerverwaltung (nicht, dass ich derzeit eine entwickeln muss *g*).

Es gibt Lagerhallen (L1,L2,L3,L4 etc.), Gänge (01,02,03,04 etc.), Regale (01,02,03,04 etc.), Regalreihen (01,02,03,04 etc.) Fachnummern (01,02,03,04 etc.).

Für einen Lagerort bedeutet das, das er eindeutig durch einen 5-Tupel aus den Mengen gekennzeichnet ist:

L101010101 wäre quasi der erste Lagerort im Lager 01.

Folgendes Anwendungsszenario:

Der Benutzer möchte das Lager initialisieren. Er möchte gern in einer Bulk-Operation das Lager von L101010101 bis L110101010 vorbereiten. Das kann alles im Frontend geklärt werden. Die Operation wird mittels POST an einen REST-Endpunkt übermittelt.

Dort ist auch mein konkreter Ausgangspunkt oder das, was ich als "Oberfläche" bezeichne.

Dort findet ein Aufruf statt, der sich in etwa so liest:

 LagerverwaltungsService.erzeuge(Lagerorte);

Fertig.

Im Lagerverwaltungsservice befindet sich folgendes Transaktionsskript:


MassenJobValidator.validiere(Anforderung)
...
[/php]

Dort kommt es schon zu einer Reihe von ungewünschten Zuständen:

1) Die Range ist komplett verkehrt herum - also alle Angaben auf "von" sind größer als alle Angaben von "bis"

2) Es gibt diverse Maxima, die nicht überschritten werden dürfen.

3) Lagerorte sind unbekannt (e.g. "Ö1" gibts nicht, das wäre ein Tippfehler)

Dafür habe ich jeweils eigene Exceptions. Entweder liefert der Validatorservice ein "True" oder es fliegt eine entsprechende Exception. Und "Nein!", ich finde [i]return[/i]-Values unzweckmäßig. Returns können ignoriert werden, Exceptions nicht.

Des weiteren im Skript:

[php]
...
Lagerort ort=generiereLagerOrt();
...
Lagerort generiereLagerOrt(){
Lagerhalle halle=LagerHallenService.holeHalleMitId(hallenId);
if(Lagerhalle==null) throw new AmArschKeineLagerhalleDaException();
return Lagerhalle
}

Und dergleichen mehr. Also quasi gibt es hier einen Haufen Exceptions, die ich zur "intelligenten" Fehlerbehandlung eingebaut habe.

Wie sähe denn ein gegenentwurf aus?

Bearbeitet von lilith2k3
Link zu diesem Kommentar
Auf anderen Seiten teilen

Gast runtimeterror

Ich bin ganz klar dafür, Exceptions in jeder Ebene zu wrappen. D.h. Exception fangen, ggf. Loggen und (falls für die darüberliegende Ebene relevant) erneut zu werfen (mit der verursachenden Exception als Cause).

Das Argument mit der Performance halte ich für irrelevant. Mit der Entscheidung für MVC stellt man bereits eine saubere Architektur über die Performance.

Warum sollte ich in den oberen Ebenen IOExceptions behandeln, wenn die Implementierung in den Ebenen darunter austauschbar ist?

Meinen Chef interessiert nur, dass ich zu spät zur Arbeit erscheine; Cause:

Verkehrsstau, Cause:

Unfall, Cause:

Schlechte Sicht, Cause:

Nebel, Cause:

Wetteranomalie, Cause:

Klimaerwärmung, Cause:

CO2-Emissionen, Cause:

Verbrennungsmotoren, ...

Wenn ich meinem Chef jetzt mit "Klimaerwärmung" als Grund für meine Verspätung komme wird der mich zurecht für bekloppt halten.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Meinen Chef interessiert nur, dass ich zu spät zur Arbeit erscheine; Cause:

Verkehrsstau, Cause:

Unfall, Cause:

Schlechte Sicht, Cause:

Nebel, Cause:

Wetteranomalie, Cause:

Klimaerwärmung, Cause:

CO2-Emissionen, Cause:

Verbrennungsmotoren, ...

Wenn ich meinem Chef jetzt mit "Klimaerwärmung" als Grund für meine Verspätung komme wird der mich zurecht für bekloppt halten.

Danke für das schöne Beispiel. :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Gast runtimeterror

MVC erhöht die Übersichtlichkeit und Wiederverwendbarkeit durch die Einführung einer Abstraktionsebene. Diese bringt naturgemäß Schnittstellen mit, welche ohne die Abstraktion nicht erforderlich wären. Schnittstellen erhöhen die Tiefe eines Stacktraces und damit den Overhead beim Aufruf von Methoden der unteren Ebenen, was Performance-Einbußen mit sich bringt.

Spaghetticode und flach strukturierter Code sind in der Regel schneller als die Implementierung generischer Ansätze - mit ihren eigenen Vor- und Nachteilen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich hab den Thread jetzt nur mal überflogen.

Es ist die Frage, ob ich für jeden Layer eigene Exceptions generieren und werfen soll, oder ob ich alle aufkommenden Exceptions -egal von wo- im Controller fange und letztlich nur noch eine Fehlermeldung an den Benutzer mache.

Das mag einem im ersten Moment vielleicht sauber vorkommen, aber im Endeffekt erzeugst du damit einen sehr großen Overhead an Code der dir keinen praktischen Nutzen bringt.

Von daher ist die Aussage das man Exceptions nur da fangen sollte wo man sie auch behandelt schon richtig. Das heißt je nach Framework/Technologie auch das du sie evtl. nur auf dem Client abfängst um dort eine Meldung für den Benutzer auszugeben da das durchreichen bis dorthin automatisch geschieht.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...