Je travaille un projet à delphi et je crée un installateur pour l'application, il y a trois parties principales.
- Installation / désinstallation de PostgreSQL
- myapplication (la configuration de myapplication est créée à l'aide de nsi) installation / désinstallation.
- Création de tables dans Postgres via script (fichiers batch).
Tout se passe bien et sans problème, mais si quelque chose échoue, j'ai créé un LogToFileger qui enregistrera chaque étape du processus,
comme ceci
LogToFileToFile.LogToFile('[DatabaseInstallation] : [ACTION]:Postgres installation started');
La fonction LogToFileToFile.LogToFile()
Ceci écrit le contenu dans un fichier. Cela fonctionne bien, mais le problème est que cela a foiré le code car il est devenu difficile de lire le code car on ne voit que l' LogToFileToFile.LogToFile()
appel de fonction partout dans le code
un exemple
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;
comme vous pouvez le voir, il y a eu beaucoup d' LogToFileToFile.LogToFile()
appels
avant
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)
c'est le cas dans tout mon code maintenant.
c'est difficile à lire.
quelqu'un peut-il me suggérer une bonne façon de désencombrer les appels à LogToFile?
comme
Indenter l'appel «LogToFileToFile.LogToFile ()`
comme ceciif 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;
Unité distincte comme
LogToFileger
Cette unité aura tous les messages LogToFile dans unswitch case
comme celui-ciFunction 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;
donc je peux simplement appeler LogToFilegingMyMessage (1) là où cela est nécessaire.
Quelqu'un peut-il me dire quelle est la meilleure et plus propre approche de LogToFileging de cette façon?
la source
logBook.log()
on le rencontre.Réponses:
Lorsque vous avez ajouté la journalisation, vous avez introduit deux choses:
Chacun de ces problèmes a sa propre solution, relativement simple:
Divisez le code en fonctions plus petites. Au lieu d'avoir une fonction géante qui contient toutes vos copies ainsi que des messages de journal pour les erreurs / succès, vous pouvez introduire une fonction "CopyFile", qui copierait exactement un fichier et enregistre son propre résultat. De cette façon, votre code principal serait simplement composé d'appels CopyFile et resterait facile à lire.
Vous pourriez rendre votre enregistreur plus intelligent. Au lieu de passer dans une chaîne géante qui contient beaucoup d'informations répétitives, vous pouvez passer des valeurs d'énumération qui rendraient les choses plus claires. Ou vous pouvez définir des fonctions Log () plus spécialisées, c'est-à-dire LogFileCopy, LogDbInsert ... Quoi que vous répétiez souvent, envisagez de le prendre en compte dans sa propre fonction.
Si vous suivez (1), vous pourriez avoir un code qui ressemble à ceci:
Ensuite, votre CopyFile () n'a besoin que de quelques lignes de code pour effectuer l'action et enregistrer son résultat, de sorte que tout votre code reste concis et facile à lire.
Je resterais loin de votre approche # 2 car vous détachez des informations qui devraient rester ensemble dans différents modules. Vous demandez simplement que votre code principal ne soit plus synchronisé avec vos instructions de journal. Mais en regardant LogMyMessage (5), vous ne le saurez jamais.
MISE À JOUR (réponse au commentaire): Je ne connais pas la langue exacte que vous utilisez, donc cette partie devra peut-être être adaptée un peu. Il semble que tous vos messages de journal identifient 3 choses: composante, action, résultat.
Je pense que c'est à peu près ce que MainMa a suggéré. Au lieu de passer une chaîne réelle, définissez des constantes (en C / C ++ / C #, elles feraient partie du type d'énumération énumération). Ainsi, par exemple pour les composants, vous pourriez avoir: DbInstall, AppFiles, Registry, Shortcuts ... Tout ce qui réduit le code le rendra plus facile à lire.
Il serait également utile que votre langue prenne en charge le passage des paramètres variables, vous ne savez pas si c'est possible. Par exemple, si l'action est "FileCopy", vous pouvez définir cette action pour avoir deux paramètres utilisateur supplémentaires: le nom de fichier et le répertoire de destination.
Ainsi, vos lignes de copie de fichiers ressembleraient à ceci:
* Remarque, il n'y a également aucune raison de copier / coller la ligne de journal deux fois si vous pouvez stocker le résultat de l'opération dans une variable locale distincte et simplement passer cette variable dans Log ().
Vous voyez le thème ici, non? Code moins répétitif -> code plus lisible.
la source
you could pass in enumerations values
ce sujet ?Il semble que vous ayez besoin d'abstraire le concept d'une "action logique". Je vois un modèle dans votre exemple où tous les appels renvoient un booléen pour indiquer le succès ou l'échec et la seule différence est le message de journal.
Cela fait des années que j'ai écrit delphi donc c'est à peu près un pseudo-code inspiré de c # mais j'aurais pensé que vous vouliez quelque chose comme
Ensuite, votre code d'appel devient
Je ne me souviens pas de la syntaxe Delphi pour les pointeurs de fonction, mais quels que soient les détails de l'implémentation, une sorte d'abstraction autour de la routine de journal semble être ce que vous recherchez.
la source
LoggableAction()
c'est bien, je peux directement écrire la valeur retournée au lieu de vérifier et d'écrire.Une approche possible consiste à réduire le code en utilisant des constantes.
deviendrait:
qui a un meilleur rapport code de connexion / autre code lors du comptage du nombre de caractères à l'écran.
Ceci est proche de ce que vous avez suggéré dans le point 2 de votre question, sauf que je n'irais pas aussi loin:
Log(9257)
est évidemment plus court queLog(2, SqlInstal, Action, CopyMapSuccess, sOSdrive)
, mais aussi assez difficile à lire. Qu'est-ce que 9257? Est-ce un succès? Une action? Est-ce lié à SQL? Si vous travaillez sur cette base de code au cours des dix dernières années, vous apprendrez ces chiffres par cœur (s'il y a une logique, c'est-à-dire que 9xxx sont des codes de réussite, x2xx sont liés à SQL, etc.), mais pour un nouveau développeur qui découvre la base de code, les codes courts seront un cauchemar.Vous pouvez aller plus loin en mélangeant les deux approches: utilisez une seule constante. Personnellement, je ne ferais pas ça. Soit vos constantes vont grossir:
ou les constantes resteront courtes, mais peu explicites:
Cela présente également deux inconvénients. Tu devras:
Conservez une liste distincte associant les informations de journal à leurs constantes respectives. Avec une seule constante, il se développera rapidement.
Trouvez un moyen d'appliquer un format unique dans votre équipe. Par exemple, si au lieu de
T2SSQ
, quelqu'un décide d'écrireST2SQL
?la source
log
appel clair , mais pouvez-vous m'expliquer davantage qu'il n'a pas comprisLog(2, SqlInstal, Action, CopyMapFailure, sOSdrive)
, vous voulez dire queSqlInstal
sera ma variable définie commeSqlInstal:=[POSTGRESQL INSTALLATION]
?SqlInstal
peut être n'importe quoi, par exemple une valeur3
. Ensuite, dansLog()
, cette valeur sera effectivement traduite en[POSTGRESQL INSTALLATION]
avant d'être concaténée avec d'autres parties du message de journal.single format in your team
est une bonne / excellente optionEssayez d'extraire une série de petites fonctions pour gérer toutes les choses en désordre. Il y a beaucoup de code répété qui pourrait très facilement être fait en un seul endroit. Par exemple:
L'astuce consiste à examiner toute duplication dans votre code et à trouver des moyens de la supprimer. Utilisez beaucoup d'espace, et utilisez le début / fin à votre avantage (plus d'espace, et des blocs de code faciles à trouver / plier). Cela ne devrait vraiment pas être trop difficile. Ces méthodes pourraient faire partie de votre enregistreur ... cela dépend vraiment de vous. Mais cela semble être un bon point de départ.
la source
success := CopyFile()
merci pour l'idée, cela réduira certaines lignes de code inutiles dans mon casLogIfFileDoesNotExist
copie de fichiers?Je dirais que l'idée derrière l'option 2 est la meilleure. Cependant, je pense que la direction que vous avez prise aggrave les choses. L'entier ne veut rien dire. Lorsque vous regardez le code, vous verrez que quelque chose est enregistré, mais vous ne savez pas quoi.
Au lieu de cela, je ferais quelque chose comme ceci:
Cela conserve la structure du message mais permet à votre code d'être flexible. Vous pouvez définir des chaînes constantes selon les besoins des phases et les utiliser uniquement comme paramètre de phase. Cela vous permet de modifier le texte réel en un seul endroit et de tout effectuer. L'autre avantage de la fonction d'assistance est que le texte important est avec le code (comme s'il s'agissait d'un commentaire), mais le texte qui n'est important que pour le fichier journal est résumé.
Ce n'est pas quelque chose que vous avez mentionné dans votre question, mais j'ai remarqué votre code. Votre indentation n'est pas cohérente. La première fois que vous l'utilisez,
begin
ce n'est pas en retrait, mais la deuxième fois. Vous faites une chose similaire avecelse
. Je dirais que c'est beaucoup plus important que les lignes de journal. Lorsque l'indentation n'est pas cohérente, il est difficile de scanner le code et de suivre le flux. De nombreuses lignes de journal répétitives sont faciles à filtrer lors de la numérisation.la source
Que diriez-vous quelque chose le long de cette ligne:
La méthode NewEntry () construirait la ligne de texte (y compris en ajoutant le [&] autour des entrées appropriées) et maintiendrait cela en attendant que les méthodes success () ou failure () soient appelées, qui ajoutent la ligne avec 'success' ou «échec», puis affichez la ligne dans le journal. Vous pouvez également créer d'autres méthodes, telles que info () lorsque l'entrée du journal concerne autre chose que succès / échec.
la source