Ich arbeite an einem Projekt in Delphi und erstelle ein Installationsprogramm für die Anwendung. Es gibt drei Hauptteile.
- PostgreSQL Installation / Deinstallation
- myapplication (Setup von myapplication wird mit nsi erstellt) Installation / Deinstallation.
- Erstellen von Tabellen in Postgres über ein Skript (Batch-Dateien).
Alles läuft gut und reibungslos, aber wenn etwas fehlschlägt, habe ich einen LogToFileger erstellt, der jeden Schritt des Prozesses
wie folgt protokolliert
LogToFileToFile.LogToFile('[DatabaseInstallation] : [ACTION]:Postgres installation started');
Die Funktion LogToFileToFile.LogToFile()
Hiermit wird der Inhalt in eine Datei geschrieben. Dies funktioniert gut, aber das Problem ist, dass dies den Code durcheinander gebracht hat, da es schwierig geworden ist, den Code zu lesen , da man den LogToFileToFile.LogToFile()
Funktionsaufruf nur überall im Code sehen kann
ein Beispiel
if Not FileExists(SystemDrive+'\FileName.txt') then
begin
if CopyFile(PChar(FilePathBase+'FileName.txt'), PChar(SystemDrive+'\FileName.txt'), False) then
LogToFileToFile.LogToFile('[DatabaseInstallation] : copying FileName.txt to '+SystemDrive+'\ done')
else
LogToFileToFile.LogToFile('[DatabaseInstallation] : copying FileName.txt to '+SystemDrive+'\ Failed');
end;
if Not FileExists(SystemDrive+'\SecondFileName.txt') then
begin
if CopyFile(PChar(FilePathBase+'SecondFileName.txt'), PChar('c:\SecondFileName.txt'), False) then
LogToFileToFile.LogToFile('[DatabaseInstallation] : copying SecondFileName.txt to '+SystemDrive+'\ done')
else
LogToFileToFile.LogToFile('[DatabaseInstallation] : copying SecondFileName.txt to '+SystemDrive+'\ Failed');
end;
Wie Sie sehen, gibt es viele LogToFileToFile.LogToFile()
Anrufe,
bevor es war
if Not FileExists(SystemDrive+'\FileName.txt') then
CopyFile(PChar(FilePathBase+'FileName.txt'), PChar(SystemDrive+'\FileName.txt'), False)
if Not FileExists(SystemDrive+'\SecondFileName.txt') then
CopyFile(PChar(FilePathBase+'SecondFileName.txt'), PChar('c:\SecondFileName.txt'), False)
Dies ist jetzt in meinem gesamten Code der Fall.
es ist schwer zu lesen.
Kann mir jemand einen guten Weg vorschlagen, um die Aufrufe von LogToFile übersichtlich zu gestalten?
mögen
Einrücken des Aufrufs 'LogToFileToFile.LogToFile ()'
wie folgtif Not FileExists(SystemDrive+'\FileName.txt') then begin if CopyFile(PChar(FilePathBase+'FileName.txt'), PChar(SystemDrive+'\FileName.txt'), False) then {Far away--->>} LogToFileToFile.LogToFile(2,'[DatabaseInstallation] : [ACTION]:copying FileName.txt to '+SystemDrive+'\ sucessful') else {Far away--->>} LogToFileToFile.LogToFile(2,'[DatabaseInstallation] : [ACTION]:copying FileName.txt to '+SystemDrive+'\ Failed'); end;
Separate Einheit wie
LogToFileger
Diese Einheit enthält alle LogToFile-Nachrichten in einerswitch case
ähnlichen FormFunction LogToFilegingMyMessage(LogToFilegMessage : integer) begin case LogToFilegMessage of 1 : LogToFileToFile.LogToFile(2,'[DatabaseInstallation] : [ACTION]:copying FileName.txt to '+SystemDrive+'\ sucessful'); 2 : LogToFileToFile.LogToFile(2,'[DatabaseInstallation] : [ACTION]:copying FileName.txt to '+SystemDrive+'\ Failed'); 150 : LogToFileToFile.LogToFile(2,'[somthing] : [ACTION]: somthing important); end;
Daher kann ich einfach die LogToFilegingMyMessage (1) aufrufen, wo immer dies erforderlich ist.
Kann mir jemand sagen, welcher Ansatz für LogToFileging auf diese Weise besser und sauberer ist?
quelle
logBook.log()
anzutreffen ist.Antworten:
Beim Hinzufügen der Protokollierung haben Sie zwei Dinge eingeführt:
Jedes dieser Probleme hat seine eigene, relativ einfache Lösung:
Teilen Sie den Code in kleinere Funktionen auf. Anstatt eine riesige Funktion zu haben, die alle Ihre Kopien sowie Protokollmeldungen für Fehler / Erfolg enthält, könnten Sie eine Funktion "CopyFile" einführen, die genau eine Datei kopiert und das eigene Ergebnis protokolliert. Auf diese Weise würde Ihr Hauptcode nur aus CopyFile-Aufrufen bestehen und leicht lesbar bleiben.
Sie könnten Ihren Logger schlauer machen. Anstatt eine riesige Zeichenfolge mit vielen sich wiederholenden Informationen zu übergeben, können Sie Aufzählungswerte übergeben, die die Dinge klarer machen. Oder Sie können speziellere Log () -Funktionen definieren, z. B. LogFileCopy, LogDbInsert ... Was auch immer Sie häufig wiederholen, sollten Sie dies in eine eigene Funktion einbeziehen.
Wenn Sie (1) folgen, könnten Sie Code haben, der so aussieht:
Dann benötigt Ihre CopyFile () nur wenige Codezeilen, um die Aktion auszuführen und das Ergebnis zu protokollieren, sodass Ihr gesamter Code präzise und leicht lesbar bleibt.
Ich würde mich von Ihrem Ansatz Nr. 2 fernhalten, da Sie Informationen, die zusammen bleiben sollten, in verschiedene Module aufteilen. Sie fragen nur nach Ihrem Hauptcode, damit er nicht mehr mit Ihren Protokollanweisungen synchronisiert wird. Aber wenn Sie sich LogMyMessage (5) ansehen, werden Sie das nie erfahren.
UPDATE (Antwort auf einen Kommentar): Ich kenne die genaue Sprache, die Sie verwenden, nicht. Daher muss dieser Teil möglicherweise etwas angepasst werden. Es scheint, dass alle Ihre Protokollnachrichten drei Dinge identifizieren: Komponente, Aktion, Ergebnis.
Ich denke, das ist ziemlich genau das, was MainMa vorgeschlagen hat. Definieren Sie Konstanten, anstatt die eigentliche Zeichenfolge zu übergeben (in C / C ++ / C # wären sie Teil des Aufzählungstyps enum). So können Sie beispielsweise für Komponenten Folgendes haben: DbInstall, AppFiles, Registry, Shortcuts ... Alles, was den Code verkleinert, erleichtert das Lesen.
Es wäre auch hilfreich, wenn Ihre Sprache die Übergabe variabler Parameter unterstützen würde und nicht sicher wäre, ob dies möglich ist. Wenn die Aktion beispielsweise "FileCopy" lautet, können Sie für diese Aktion zwei zusätzliche Benutzerparameter definieren: Dateiname und Zielverzeichnis.
Ihre Dateikopierzeilen würden also ungefähr so aussehen:
* Hinweis: Es gibt auch keinen Grund, die Protokollzeile zweimal zu kopieren / einzufügen, wenn Sie das Ergebnis der Operation in einer separaten lokalen Variablen speichern und diese Variable einfach an Log () übergeben können.
Sie sehen das Thema hier, richtig? Weniger sich wiederholender Code -> besser lesbarer Code.
quelle
you could pass in enumerations values
?Sieht so aus, als müssten Sie das Konzept einer "LoggableAction" abstrahieren. In Ihrem Beispiel wird ein Muster angezeigt, bei dem alle Aufrufe einen Bool zurückgeben, um Erfolg oder Misserfolg anzuzeigen. Der einzige Unterschied besteht in der Protokollnachricht.
Es ist Jahre her, seit ich Delphi geschrieben habe, also ist dies ziemlich c # -inspirierter Pseudocode, aber ich hätte gedacht, dass Sie so etwas wollen
Dann wird Ihr Anrufcode
Ich kann mich nicht an die Delphi-Syntax für Funktionszeiger erinnern, aber unabhängig von den Implementierungsdetails scheint eine Art Abstraktion um die Protokollroutine das zu sein, wonach Sie suchen.
quelle
LoggableAction()
das ist schön, ich kann den zurückgegebenen Wert direkt schreiben, anstatt zu überprüfen und zu schreiben.Ein möglicher Ansatz besteht darin, den Code mithilfe von Konstanten zu reduzieren.
würde werden:
Dies hat ein besseres Verhältnis von Protokollcode zu anderem Code, wenn die Anzahl der Zeichen auf dem Bildschirm gezählt wird.
Dies kommt dem nahe, was Sie in Punkt 2 Ihrer Frage vorgeschlagen haben, außer dass ich nicht so weit gehen würde:
Log(9257)
ist offensichtlich kürzer alsLog(2, SqlInstal, Action, CopyMapSuccess, sOSdrive)
, aber auch ziemlich schwer zu lesen. Was ist 9257? Ist es ein Erfolg? Eine Handlung? Bezieht es sich auf SQL? Wenn Sie in den letzten zehn Jahren an dieser Codebasis arbeiten, lernen Sie diese Zahlen auswendig (wenn es eine Logik gibt, dh 9xxx sind Erfolgscodes, x2xx beziehen sich auf SQL usw.), aber für einen neuen Entwickler, der dies entdeckt Die Codebasis, Short Codes, wird ein Albtraum sein.Sie können noch weiter gehen, indem Sie die beiden Ansätze mischen: Verwenden Sie eine einzelne Konstante. Persönlich würde ich das nicht tun. Entweder werden Ihre Konstanten größer:
oder die Konstanten bleiben kurz, aber nicht sehr explizit:
Dies hat auch zwei Nachteile. Sie müssen:
Führen Sie eine separate Liste, in der die Protokollinformationen den jeweiligen Konstanten zugeordnet sind. Mit einer einzigen Konstante wächst es schnell.
Finden Sie einen Weg, um ein einzelnes Format in Ihrem Team durchzusetzen. Was ist zum Beispiel, wenn stattdessen
T2SSQ
jemand beschließt, zu schreibenST2SQL
?quelle
log
Aufruf, aber können Sie mir mehr erklären, was es nicht verstanden hatLog(2, SqlInstal, Action, CopyMapFailure, sOSdrive)
, Sie wollen sagen,SqlInstal
wird meine definierte Variable sein wieSqlInstal:=[POSTGRESQL INSTALLATION]
?SqlInstal
kann alles sein, zum Beispiel ein Wert3
. InLog()
wird dieser Wert dann effektiv übersetzt,[POSTGRESQL INSTALLATION]
bevor er mit anderen Teilen der Protokollnachricht verkettet wird.single format in your team
ist eine gute / gute OptionVersuchen Sie, eine Reihe kleiner Funktionen zu extrahieren, um all die unordentlich aussehenden Dinge zu handhaben. Es gibt viele wiederholte Codes, die sehr einfach an einem einzigen Ort ausgeführt werden können. Beispielsweise:
Der Trick besteht darin, nach Duplikaten in Ihrem Code zu suchen und Möglichkeiten zu finden, diese zu entfernen. Verwenden Sie viele Leerzeichen und nutzen Sie den Anfang / das Ende zu Ihrem Vorteil (mehr Leerzeichen und leicht zu findende / faltbare Codeblöcke). Es sollte wirklich nicht zu schwierig sein. Diese Methoden könnten Teil Ihres Loggers sein ... es liegt wirklich an Ihnen. Aber das scheint ein guter Anfang zu sein.
quelle
success := CopyFile()
LogIfFileDoesNotExist
Kopien kopieren?Ich würde sagen, dass die Idee hinter Option 2 die beste ist. Ich denke jedoch, dass die Richtung, in die Sie gegangen sind, die Dinge noch schlimmer macht. Die Ganzzahl bedeutet nichts. Wenn Sie sich den Code ansehen, werden Sie sehen, dass etwas protokolliert wird, aber Sie wissen nicht, was.
Stattdessen würde ich so etwas tun:
Dadurch bleibt die Nachrichtenstruktur erhalten, Ihr Code kann jedoch flexibel sein. Sie können nach Bedarf konstante Zeichenfolgen für die Phasen definieren und diese nur als Phasenparameter verwenden. Auf diese Weise können Sie an einer Stelle Änderungen am eigentlichen Text vornehmen und alles bewirken. Der andere Vorteil der Hilfsfunktion besteht darin, dass der wichtige Text mit dem Code verknüpft ist (als wäre es ein Kommentar), der Text, der nur für die Protokolldatei wichtig ist, jedoch entfernt wird.
Dies ist nichts, was Sie in Ihrer Frage erwähnt haben, aber ich habe etwas über Ihren Code bemerkt. Ihre Einrückung ist nicht konsistent. Das erste Mal, wenn Sie es verwenden
begin
, wird nicht eingerückt, aber das zweite Mal. Sie machen eine ähnliche Sache mitelse
. Ich würde sagen, das ist viel wichtiger als die Protokollzeilen. Wenn die Einrückung nicht konsistent ist, ist es schwierig, den Code zu scannen und dem Ablauf zu folgen. Viele sich wiederholende Protokollzeilen lassen sich beim Scannen leicht herausfiltern.quelle
Wie wäre es mit etwas in dieser Richtung:
Die NewEntry () -Methode würde die Textzeile erstellen (einschließlich des Hinzufügens von [&] um die richtigen Einträge) und diese warten, bis die Methoden success () oder failed () aufgerufen werden, die die Zeile mit 'success' oder anhängen 'Fehler', und geben Sie dann die Zeile in das Protokoll ein. Sie können auch andere Methoden festlegen, z. B. info (), wenn der Protokolleintrag nicht für Erfolg / Misserfolg bestimmt ist.
quelle