Wenn ich an agile Softwareentwicklung und alle Prinzipien (SRP, OCP, ...) denke, frage ich mich, wie ich mit Protokollierung umgehen soll.
Ist die Protokollierung neben einer Implementierung eine SRP-Verletzung?
Ich würde sagen, yes
weil die Implementierung auch ohne Protokollierung laufen soll. Wie kann ich die Protokollierung besser implementieren? Ich habe einige Muster überprüft und bin zu dem Schluss gekommen, dass der beste Weg, die Prinzipien nicht auf benutzerdefinierte Weise zu verletzen, sondern jedes Muster zu verwenden, das bekanntermaßen gegen ein Prinzip verstößt, die Verwendung eines Dekorationsmusters ist.
Nehmen wir an, wir haben eine Reihe von Komponenten, die keine SRP-Verletzung aufweisen, und möchten dann die Protokollierung hinzufügen.
- Komponente A
- Komponente B verwendet A
Wir möchten die Protokollierung für A durchführen, also erstellen wir eine weitere Komponente D, die mit A dekoriert ist und eine Schnittstelle I implementiert.
- Schnittstelle I
- Komponente L (Protokollierungskomponente des Systems)
- Komponente A implementiert I
- Komponente D implementiert I, dekoriert / verwendet A, verwendet L für die Protokollierung
- Komponente B verwendet ein I
Vorteile: - Ich kann A ohne Protokollierung verwenden - Testen A bedeutet, dass ich keine Protokollierungsversuche benötige - Tests sind einfacher
Nachteil: - mehr Komponenten und mehr Tests
Ich weiß, dass dies eine weitere offene Diskussionsfrage zu sein scheint, aber ich möchte wissen, ob jemand bessere Protokollierungsstrategien als ein Dekorateur oder eine SRP-Verletzung verwendet. Was ist mit statischen Singleton-Loggern, die standardmäßig NullLogger sind, und wenn Syslog-Logging gewünscht wird, ändert man das Implementierungsobjekt zur Laufzeit?
Antworten:
Ja, es ist ein Verstoß gegen SRP, da die Protokollierung ein Querschnittsthema ist.
Die korrekte Methode besteht darin, die Protokollierung an eine Protokollierungsklasse (Interception) zu delegieren, deren einziger Zweck darin besteht, die Protokollierung gemäß der SRP durchzuführen.
Unter diesem Link finden Sie ein gutes Beispiel: https://msdn.microsoft.com/en-us/library/dn178467%28v=pandp.30%29.aspx
Hier ist ein kurzes Beispiel :
Vorteile sind
quelle
TenantStoreLogger
wird es bei jederTenantStore
Änderung geändert. Sie trennen Bedenken nicht mehr als in der ursprünglichen Lösung.Ich würde sagen, dass Sie SRP viel zu ernst nehmen. Wenn Ihr Code ordentlich genug ist, dass die Protokollierung die einzige "Verletzung" von SRP darstellt, sind Sie besser als 99% aller anderen Programmierer, und Sie sollten sich auf die Schulter klopfen.
Der Sinn von SRP ist es, schrecklichen Spaghetti-Code zu vermeiden, bei dem Code, der verschiedene Dinge tut, alle miteinander verwechselt werden. Das Mischen von Protokollierung mit Funktionscode läutet für mich keine Alarmglocken.
quelle
Do you mock the logger?
Das ist genau das, was Sie tun. Sie sollten eineILogger
Schnittstelle haben, die definiert, WAS der Logger macht. Dem zu testenden Code wird ein vonILogger
Ihnen angegebener Code hinzugefügt. Zum Testen haben Sieclass TestLogger : ILogger
. Das Tolle daran istTestLogger
, dass man Dinge wie den letzten String oder den protokollierten Fehler anzeigen kann. Die Tests können überprüfen, ob der zu testende Code korrekt protokolliert wird. Zum Beispiel könnte ein Test seinUserSignInTimeGetsLogged()
, bei dem der TestTestLogger
nach dem Protokoll sucht.Nein, es ist keine Verletzung von SRP.
Die Nachrichten, die Sie an das Protokoll senden, sollten sich aus den gleichen Gründen ändern wie der umgebende Code.
Was eine Verletzung von SRP ist, ist die Verwendung einer bestimmten Bibliothek für die Protokollierung direkt im Code. Wenn Sie die Art der Protokollierung ändern möchten, gibt SRP an, dass dies keinen Einfluss auf Ihren Geschäftscode haben soll.
Eine Art von Zusammenfassung
Logger
sollte für Ihren Implementierungscode zugänglich sein, und das einzige, was Ihre Implementierung sagen sollte, ist "Diese Nachricht an das Protokoll senden", ohne Bedenken, wie es gemacht wird. Die Entscheidung über die genaue Art der Protokollierung (auch Zeitstempel) liegt nicht in der Verantwortung Ihrer Implementierung.Ihre Implementierung sollte dann auch nicht wissen, ob es sich bei dem Logger, an den sie Nachrichten sendet, um einen handelt
NullLogger
.Das gesagt.
Ich würde das Abmelden als Querschnittsthema nicht zu schnell streichen . Das Senden von Protokollen zur Verfolgung bestimmter Ereignisse in Ihrem Implementierungscode gehört zum Implementierungscode.
Ein Querschnittsthema, OTOH, ist die Ausführungsverfolgung : Die Protokollierung wird bei jeder Methode ein- und ausgeschaltet. AOP ist dafür am besten geeignet.
quelle
Login
-schnittstelle mit dem gleichen logger verziert.Da die Protokollierung häufig als Querschnittsthema betrachtet wird, würde ich vorschlagen, AOP zu verwenden, um die Protokollierung von der Implementierung zu trennen.
Abhängig von der Sprache würden Sie einen Interceptor oder ein AOP-Framework (z. B. AspectJ in Java) verwenden, um dies durchzuführen.
Die Frage ist, ob sich das wirklich lohnt. Beachten Sie, dass diese Trennung die Komplexität Ihres Projekts erhöht und nur einen geringen Nutzen bringt.
quelle
Das hört sich gut an. Sie beschreiben einen ziemlich Standard-Protokollierungsdekorateur. Du hast:
Dies hat eine Verantwortung: Protokollieren von Informationen, die an sie übergeben werden.
Dies hat eine Verantwortung: Bereitstellung einer Implementierung von Schnittstelle I (vorausgesetzt, ich bin ordnungsgemäß SRP-konform, das heißt).
Dies ist der entscheidende Teil:
Wenn es so ausgedrückt wird, klingt es komplex, aber sehen Sie es so: Komponente D macht eine Sache: A und L zusammenbringen.
Die einzige Verantwortung der Komponente D besteht darin, sicherzustellen, dass L benachrichtigt wird, wenn A verwendet wird. Die Implementierungen von A und L sind beide an anderer Stelle. Dies ist vollständig SRP-konform und gleichzeitig ein gutes Beispiel für OCP und eine weit verbreitete Verwendung von Dekorateuren.
Eine wichtige Einschränkung: Wenn D Ihre Protokollierungskomponente L verwendet, sollte dies so erfolgen, dass Sie die Art und Weise ändern können, in der Sie protokollieren. Der einfachste Weg, dies zu tun, besteht darin, eine Schnittstelle IL zu haben, die von L implementiert wird. Dann:
Auf diese Weise hängt nichts direkt von irgendetwas anderem ab, was es einfach macht, sie auszutauschen. Dies erleichtert die Anpassung an Änderungen und das Verspotten von Teilen des Systems, sodass Sie einen Komponententest durchführen können.
quelle
D implements I
. Vielen Dank für Ihre Antwort.Natürlich ist es eine Verletzung von SRP, da Sie ein Querschnittsthema haben. Sie können jedoch eine Klasse erstellen, die für die Erstellung der Protokollierung bei Ausführung einer Aktion verantwortlich ist.
Beispiel:
quelle