![]() |
AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?
Zitat:
Aber die 'Benutzterverwaltung' ist hier auch viel zu fett. Ich brauch an der Stelle keine Verwaltung, sondern nur den Scope/Kontext, der weiß, mit welchen Rechten gearbeitet wird. Zitat:
Da imho jede sauber designte Klasse gut (ohne Mocks) testbar ist, aber nicht jede gut testbare Klasse automatisch sauber designt ist, würde ich das Argument 'lässt sich gut/schlecht testen' etwas nach hinten schieben, aber wirklich nur ein wenig. Wichtiger ist für mich: Ist die Klasse flexibel, erweiterbar, robust und wiederverwendbar? Halten wir also fest: 1. Globale Abhängigkeiten auch auf Kosten der Tipparbeit durch DI auflösen. 2. Die nun umständlichen Instantiierungen über eine Factory abbilden und damit den Overhead verbergen. 3. Abhängigkeiten nur durch Interfaces abbilden. So sieht das doch wirklich gut aus. Im Falle des 'Users/Permission' sieht es in der Praxis ganz einfach so aus: Das Businessobjekt (oder einfacher: die konkrete Aktion) kann in der Anwendung nur von einem Benutzer mit ausreichenden Rechten ausgeführt werden. Fein. Aber in einem Batchprozess möchte ich gerne (oder ich muss) auf diese Rechte pfeifen. Ich will mir keinen Batchuser zusammenfriemeln, der bestimmte Rechte hat, wobei meine 'Benutzerverwaltung' vielleicht so gemein ist, aus Sicherheitsgründen zu verbieten, das jemand zwei bestimmte Rechte gleichzeitig innehat und das genau die sind, die ich gerade benötige. Also baue ich mir in meinem Batchprozess meinen Pseudouser (also eine Klasse, die das IUser/IPermissions-Interface implementiert) nach und habe genau das, was ich wollte: Einerseits ein BO, das im Kontext der Anwendung und Aufgerufen durch ein Kommando genau die Sicherheit bietet, die ich brauche, aber sonst eine extrem flexible Klasse, deren Abhängigkeiten im Konstruktor für jeden sichtbar sind und die ich so flexibel wie möglich verwenden kann. Wirklich? Fast, denn die Schnittstelle (hier wirklich: das Interface) der Abhängigkeiten sollte nur genau die Properties beinhalten, die für die Durchführung dieser Aufgabe wirklich notwendig ist. |
AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?
Das Thema entwickelt ja langsam eine echte Dynamik ;)
Um es mal vorweg zu schicken, da ich das immer in Verbindung mit diesem Thema (Test- und wartbarer Code) sage: Es geht nicht um den Selbstzweck, sondern da steckt immer hinter, dass man etwas am Code ändert oder ihn in einer gewissen Form schreibt, damit er test- und wartbar bleibt. Mit testbar ist hier nicht gemeint, dass ich hinterher 10 Minuten durch die Anwendung klicke bis ich an der Stelle bin, die mich eigentlich interessiert und eventuell noch nen Server und Datenbank aufsetzen muss dafür mit speziellen Daten. Sondern es geht um Unitests. Bei diesen teste ich isoliert ein bestimmtes Modul (meist eine Klasse) ohne externe Abhängigkeiten. Und wenn dann an meiner Klasse noch wie ein riesiges Wurzelwerk noch meine halbe Anwendung dran hängt, ist das große Sch.... Schöne Code Beispiele - da sie auf verschiedenen Ebenen einige Fehler aufzeigen. Erster Fall. Die Aktion soll überprüfen, ob sie ausgeführt werden darf oder nicht. Was hat damit ein Benutzer zu tun? Also neben der globalen Abhängigkeit noch eine LoD Verletzung, die es noch schlimmer macht. Um das Teil zu testen muss ich nicht nur irgendwie den globalen User bei einem Test austauschen sondern dem Benutzer auch noch entsprechende Berechtigungen verpassen oder die IsGranted Funktion ausmocken, damit sie mir das erwartete Ergebnis mitteilt. Übrigens wurde auch noch das SRP verletzt, denn die Aufgabe meiner Klasse ist nicht die Rechteüberprüfung sondern höchstwahrscheinlich irgendwas anders. Zweiter Fall, die Kopplung an die GUI - hier sollte man sich überlegen, was genau von meinem Code benötigt GUI Interaktion. Wahrscheinlich habe ich irgendetwas, was durch GUI ausgelöst wird und was Meldungen zurück liefert. Aber auch in diesem Fall ist das die eine Aufgabe dieser Einheit: das Zwischenspiel von GUI und Programmlogik. Wenn ich nunmal die VCL verwende, dann ist es auch nicht böse, in einer solchen Klasse, VCL Elemente zu benutzen. Aber bitte nicht in der Programmlogik, die erstmal nix mit GUI am Hut hat. D.h. der dritte Fall ergibt sich oft gar nicht, da man für diese GUI-Interaktionsklasse an die entsprechende GUI anpasst. Hier gibt es so viele Möglichkeiten, dass ich nur einfach mal die Begriffe MVP, MVC oder MVVM in den Raum werfe (die zu diskutieren wäre wohl eher ein eigener Thread). Wenn dann die Anforderungen so implementiert werden, wie du es mit dem Logging, Reporting und Speichern in der Datenbank skizzierst, würde ich mir ernsthaft erneut Gedanken über die Verletzung des SRP machen. Zumindest Persistenz lässt sich prima in eine eigene Klasse zum Speichern auslagern. Logging schreit meist nach AOP, was wir in Delphi aber nicht so nativ haben, wie andere Sprachen. Hier handelt es sich eher um eine optionale Abhängigkeit, die man durchaus per Property Injection angeben kann. Und auch die ReportEngine muss hier wohl kaum mit angegeben werden, wohlmöglich kann man ein irgendwie geartetes Ergebnis der Aktion an das Dingen weitergeben. Deshalb braucht aber die Klasse an sich noch keine Abhängigkeit auf das Teil. Oft resultieren also augenscheinlich Probleme, denen man sich konfrontiert sieht, und denen man mit Verletzungen von irgendwelchen Prinzipien entgegnen "muss" aus vorrausgehenden Verletzungen dieser oder anderer Prinzipien. Aber wie schon eingangs gesagt, man muss immer abwägen, was erreicht man und welchen Aufwand hat man. Zitat:
![]() |
AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?
Zitat:
Gruß K-H |
AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?
Zitat:
Allerdings, wenn für die Aktion TuWas die Berechtigungen egal sind, dann prüft diese Aktion die Berechtigungen einfach nicht. |
AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?
[QUOTE=Sir Rufo;1259345]
Zitat:
Zitat:
Zitat:
1. Testbar = Unittests 2. Mock <> Fake (Mock=nachträgliches Ändern von Verhalten. Fake = Hilfsklasse, um Abhängigkeiten zu kontrollieren) 3. Wartbar = Änderungen ohne Seiteneffekte vornehmen. 4. Robust = Schrotteingaben => wohldefinierte Exceptions. "Keine Überraschungen" 5. Erweiterbar = Erweitern, ohne sich einen Wolf zu tippen. Zitat:
1. Soll das BO die Rechte prüfen? Normalerweise nicht, das macht ein Szenario. Aber wenn die Rechteabfrage systemimmanent ist, z.B. in einer Bank integraler Bestandteil der Aktion ist, dann schon (finde ich). Aber mit Sicherheit nicht so banal wie hier. Insofern => richtig, SRP verletzt. Zitat:
Zitat:
Die restlichen Abhängigkeiten.. Nun ja, klar. Da ich vielleicht doch einen "IoC-Container" habe, der das globale Gedöns schön verbirgt, sollte man das noch anständig herunterbrechen können. Nur muss ich mir dann meinen IoC-Container mocken/faken, was auch kein Zuckerschlecken ist. Allerdings: Das Kommando hat nun einmal diese Abhängigkeiten: Es wird geprüft, gespeichert, gedruckt und interagiert. Und mit DI müsste das dann entsprechend ausarten, weil in meinem Fall das Kommando nun einmal die 'oberste Instanz ist', die die logische Aktion 'TuWas, aber mit allem Drum und dran' ausführt. Zitat:
|
AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?
Zitat:
Aber abgesehen davon, ist das meiner Meinung nach Schusseligkeit beim Design oder aber die allgegenwärtige Nachfrickelei. (bevor mir jetzt hier der kragen platzt sehe ich mal zu, daß ich meine Arbeit gemacht kriege) Gruß K-H |
AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?
Das mit dem BULK LOAD ist sauber nur durch eine Mittelschicht abzubilden (so wie auch die gesamte Berechtigungs-Verwaltung wer wie wann wo was machen darf, bis runter auf Datensatz-/Feld-Ebene runter)
Die Anwendung kommt mit dem SQL-Server gar nicht in Berührung, sondern spricht mit der Mittelschicht. Die Mittelschicht spricht mit dem SQL-Server und darf dort eh alles (ok, fast alles). Ok, aber das weiter zu vertiefen sprengt wohl den Rahmen globale Abhängigkeiten |
AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?
Zitat:
![]() ![]() ![]() zu 4. robust eher im Sinne von wenn ich am Code an Stelle a etwas ändere krachts nicht an Stelle b, die auf der anderen Seite des Programms ist (geht auch ein bisschen Richtung Punkt 5) zu 5. es geht nicht nur ums tippen sondern darum, dass man durch Erweiterungen nicht sein halbes System umstricken muss (Stichworte: OCP, LSP, ISP) Zitat:
Zitat:
![]() ![]() |
AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?
Zitat:
Zitat:
Zitat:
Zitat:
Aber dann verstehe ich deinen Einwand auch nicht: Ich habe ein Kommando als oberste Instanz. Dies führt eine Aktion und alle damit verbundenen weiteren Aktionen aus (Speichern, loggen, drucken, validieren etc.) Dem muss ich doch alle Abhängigkeiten übergeben, oder wie geht das sonst? |
AW: Globale Variablen/Abhängigkeiten = Böse... Und nu?
Zitat:
![]() Zitat:
Ich hab mir das ja auch nicht selber ausgedacht, man kann das auch oft in Artikeln zu dem Thema lesen. Erstmal die Prinzipien und vor allem das DIP verstehen und manuell anwenden, bevor man sich einem IoC Container zuwendet. Ansonsten wird man nämlich ganz schnell ziemlich böse davon überfahren und benutzt nen IoC Container am Ende als ![]() Zitat:
![]() Eins steht aber auf jeden Fall fest - und das mag für manche befremdlich sein: man muss recht viel stumpfen Code für die Erstellung und Zusammentackerei schreiben. Und das ist am Ende das, was der IoC Container einem abnehmen kann. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:15 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz