Einzelnen Beitrag anzeigen

Furtbichler
(Gast)

n/a Beiträge
 
#5

AW: Übergabe Datenbankschnittstelle (Transaction, etc.)

  Alt 3. Jan 2014, 19:34
Wenn du Exceptions loggen möchtest, dann lass die einfach durchrauschen und erledige das Loggen im Delphi-Referenz durchsuchenTApplication.OnException Event mit einer Routine (DRY).
Das ist etwas zu DRY.

Vielleicht ein wenig richtiger ist: in jeder Schicht (Transport, Datenbank, Business, View, UI) sollten die Exceptions abgefangen und geloggt werden. Anschließend werden sie interpretiert und für den Aufrufer verständlich weitergeleitet. Es interessiert die Business-Schicht nicht, das der Transport aufgrund eines TCP-Stackfehlers nicht funktioniert oder ein Deadlock eingetreten ist, oder der FK falsch ist (aua!). Er funktioniert nicht und fertig. Die Datenbankschicht muss alle Exceptions der Transportschicht abfangen, ggf. Reparaturmaßnahmen einleiten (nochmal probieren z.B.) und als 'EDatabaseException' weiterleiten. Da hat man dann eine gewisse Redundanz, aber eigentlich ist das keine, denn das ist ein 'Pattern' (Sonst würdest du bei jeder For-Schleife ja auch 'DRY' schreien). Also vielleicht so:
Delphi-Quellcode:
Procedure TMyLayer.MyPublicMethod();
Begin
  While true do
    Try
      SubLayer.DoInternalStuff();
      Break;
    Except
      On E:EMyLayerException do begin
        LogException('MyLayer','MyPublicMethod',E);
        Raise E;
      end;
   
      On E:ESubLayerException Do
        If Not ExceptionIsReparable(E) then
          Raise EMyLayerException.Create(E);

      On E:Exception Do begin
        LogFatal('MyLayer','MyPublicMethod',E);
        Raise EMyLayerException.Create(E);
      end;
    End
  End
End;
Natürlich kann die Exceptionbehandlung besser aussehen (Verhindern unendlicher Wiederholversuche z.B.), aber es geht hier ums Prinzip: Jede Schicht loggt die eigenen und unvorhergesehene Exceptions. Alle werden interpretiert und weitergeleitet, wenn sie nicht repariert werden können.

Das wird in jeder Schicht entsprechend umgesetzt (so viele sind es ja nicht). Vorteil: 'MyLayer' muss sich nur um eigene sowie die Exceptions kümmern, die vom 'SubLayer' geworfen wurden. Alles andere sind schwere Vergehen und dürfen nicht auftreten (natürlich werden sie entsprechend behandelt).

Dieses Pattern kann man auch über Prozedurvariablen DRY-Technisch aufbessern, sodaß die entsprechende Exceptionbehandlungslogik nicht zu oft wiederholt wird. Allerdings ist es ausnahmsweise auch erlaubt, hier auf DRY zu verzichten, denn die individuelle Exceptionbehandlung, Konfliktauflösung usw. ist im Einzelfall doch unterschiedlich.

Im Idealfall hat man hier zwei Klassen pro Schicht: Eine reine Arbeitsklasse, die die Logik enthält und ausführt (mit den public Methoden A, B und C. Diese Klasse ist nach außen hin nicht sichtbar. Darüber stülpt man die Klasse, die sichtbar ist, und für jede Public Methode (A,B,C) die Exceptionbehandlung durchführt. So kann man einerseits die Logik testen und andererseits den Exception/Securitywrapper.

Hier kann es sinnvoll sein, viele einzelne Logik/Businessklassen zu haben, jedoch nur eine 'Schnittstelle nach außen', nämlich den Securitywrapper, aber das muss im Einzelfall entschieden werden.

Alternativ gibt es noch die Möglichkeit, die Exceptions abzufangen, zu interpretieren, zu verpacken (wenn sie nicht aufgelöst werden können) und weiterzuleiten, also ohne Logging (Sieht man leider immer wieder). Aber davon halte ich nichts, denn Exceptions werden ja doch abgefangen und verschluckt (Deadlock-Problematik beim DB-Layer, Verbindung bricht ab, kann aber wieder hersgestellt werden z.B.). Genau die will ich aber loggen. Das geht dann nicht, wenn alles bis kurz unter die Oberfläche gespült wird.
  Mit Zitat antworten Zitat