50 votes

Quel est l'intérêt d'une façade d'exploitation forestière ?

Il existe un grand nombre de bibliothèques de journalisation différentes, chacune ayant ses propres particularités et avantages. ( Exemples .NET : log4net, System.Diagnostics.TraceSource, NLog, etc.)

La tendance naturelle est de faire abstraction de ces particularités et d'utiliser une façade d'enregistrement. (exemples : Castle.Services.Logging , Logging.commun , Facade de journalisation simple ) De cette façon, si le cadre de journalisation que vous utilisez devient obsolète ou si un autre cadre est en vogue, vous pouvez simplement changer l'implémentation et laisser le code intact.

Mais il existe de multiples façades d'exploitation forestière parmi lesquelles choisir. Étant donné que la réponse aux nombreuses implémentations disparates de journalisation était l'abstraction, pourquoi ne pas utiliser une façade de journalisation ? Si cela semble ridicule, qu'est-ce qui le rend plus ridicule que la façade de journalisation originale ? Qu'est-ce qui fait qu'une couche supplémentaire d'abstraction au-dessus de la structure de journalisation est le nombre magique ?

12 votes

0 votes

@brian Je ne suis pas sûr que votre hypothèse sur l'inclinaison naturelle des gens soit vraie. Insistez sur le fait que la plupart des développeurs n'y pensent même pas.

67voto

wageoghe Points 14676

Je parlerai principalement du point de vue de l'utilisation de l'abstraction pour isoler le code d'application d'un cadre de journalisation particulier. Il existe d'autres facteurs qui peuvent affecter le choix d'un cadre de journalisation ou le choix (et les exigences) d'une abstraction.

J'ai récemment passé beaucoup de temps à évaluer divers cadres de journalisation ainsi que des abstractions de journalisation tierces.

Certaines personnes estiment qu'il est utile d'isoler le code de leur application d'un cadre de journalisation spécifique. Vous trouverez ici de nombreux messages sur les SO comme este y este y este (et il y en a d'autres) où la journalisation est discutée et où de nombreuses personnes considèrent comme une évidence que le cadre de journalisation doit être enveloppé/abstrait.

Cela vous permet évidemment de ne pas être lié à un cadre spécifique. Est-ce important ? Allez-vous vraiment changer de framework de journalisation ? Eh bien, il y a aussi beaucoup de gens qui ne mentionnent pas l'habillage ou qui le déconseillent. Si vous regardez certains des exemples de code d'enveloppement de framework de journalisation qui ont été postés ici, vous pouvez également voir de nombreux exemples de la raison pour laquelle au moins certaines personnes ne devraient pas envelopper leur framework de journalisation !

Si vous avez commencé un projet récemment, vous avez peut-être examiné les cadres de journalisation et, peut-être, réduit à deux finalistes : log4net et NLog. Chacun a des arguments en sa faveur. log4net est clairement un favori, probablement LE favori de ceux qui ont exprimé une opinion. NLog offre des capacités très similaires. Si l'on en juge par la popularité, log4net pourrait être le choix évident. Sur la base des capacités, ils semblent très similaires. Sur la base de "l'activité récente" (comme indiqué par les checkins à leurs dépôts de code source par l'activité du blog ou le manque de celle-ci), NLog est le choix clair. Si vous deviez choisir il y a un an, vous pourriez opter pour log4net car c'était le choix "sûr". La date de sortie de NLog n'était pas claire. Dans l'année qui s'est écoulée depuis, NLog a traversé un cycle de développement assez important, avec la sortie d'une version bêta il y a quelques jours seulement.

Lequel choisir il y a un an ? Lequel choisir maintenant ? L'un était-il clairement le meilleur choix à l'époque ? Le premier est-il le meilleur choix aujourd'hui ?

Une abstraction vous permet de repousser la décision de choisir l'un ou l'autre (vous n'êtes même pas obligé de choisir JAMAIS, bien que vous le souhaitiez probablement si vous prévoyez de livrer le cadre de journalisation avec votre produit). Vous pouvez en tester un, puis l'autre, et vous faire une idée de la façon dont ils fonctionnent avec votre application, avec votre équipe, dans votre environnement. En utilisant quelque chose comme Logging.commun o SLF permet de commencer à écrire du code maintenant, en codant pour une interface/API de journalisation, et de mettre en place votre code de journalisation. Si vous pensez que l'interface/API fournie par l'abstraction est suffisante pour votre travail (et, pourquoi ne le serait-elle pas puisqu'elle est essentiellement la même que l'interface/API fournie par log4net et NLog), alors il n'y a pas grand danger à utiliser l'abstraction. Au fur et à mesure que vous avancez dans le cycle de développement, vous pouvez trouver qu'un framework ou l'autre répond mieux à vos besoins. Après avoir codé en fonction de l'abstraction, vous êtes libre de faire ce choix à tout moment, jusqu'au moment où votre produit est mis sur le marché.

Vous pensez peut-être même, au fond de vous, que vous pourriez écrire une bibliothèque de journalisation à partir de zéro. Encore une fois, si vous pensez que l'interface/API de log4net et/ou NLog est suffisante, vous pourriez implémenter votre bibliothèque de journalisation avec une API similaire. Si vous pensez cela, cela pourrait être une autre raison d'utiliser une abstraction. Encore une fois, vous pouvez commencer à écrire du code (pour votre produit, pas pour votre logithèque) dès aujourd'hui, en utilisant un autre framework de logging jusqu'à ce que votre logithèque "from scratch" soit prête. Peut-être voulez-vous vraiment utiliser System.Diagnostics.TraceSource et Diagnostic de l'Ukadc. (pour obtenir des capacités de formatage de sortie similaires à log4net ou NLog) afin d'obtenir une "meilleure" intégration avec la journalisation que Microsoft a implémentée dans certaines de ses plateformes en utilisant TraceSources. Il pourrait être assez facile d'écrire un "logger" en termes de TraceSources et ensuite d'écrire l'abstraction de sorte que vous puissiez le brancher dans Common.Logging ou SLF. (Si l'interface/API est suffisante, vous pourriez simplement écrire votre "logger" en termes d'interface de la bibliothèque d'abstraction et ne pas avoir à écrire une couche d'abstraction supplémentaire).

Avec des arguments aussi convaincants que ceux-ci, pourquoi quelqu'un n'utiliserait-il jamais une abstraction ? Ha ha, je plaisante !

Si une abstraction est bonne, faut-il écrire la sienne ou utiliser une abstraction existante ? Si vous en écrivez une vous-même, alors vous devez évidemment l'écrire. Comment le faire ? Eh bien, vous pouvez simplement définir une interface et envelopper un cadre (faites attention et enveloppez-le correctement !). Plus tard, si vous décidez de changer, vous pouvez envelopper ce framework. Si vous faites attention, vous n'aurez pas à modifier le code de l'application, sauf peut-être à l'endroit où vous créez les objets du framework sous-jacent. C'est peut-être une bonne chose. Vous avez évité de dépendre d'une abstraction tierce pour le "petit" prix de l'implémentation d'un seul wrapper sur un seul framework. Cependant, il y a un coût. Tant que vous n'avez pas écrit votre abstraction, vous ne pouvez pas vraiment écrire beaucoup de code d'application contenant de la journalisation, à moins que vous n'ayez une bonne stratégie pour le faire passer à votre abstraction. Il devient également plus difficile de tester deux ou plusieurs frameworks pour décider lequel fonctionne le mieux pour vous. Chaque framework que vous voulez "essayer" nécessite un autre travail d'enveloppement. Si vous voulez passer facilement d'un framework à l'autre (au moins pendant le cycle de développement), vous devez faire en sorte que cela soit facile. Les frameworks tiers offrent cette possibilité dès le départ.

Wow ! Maintenant je suis vendu ! Donnez-moi de l'abstraction forestière, ou donnez-moi la mort !

Les abstractions d'enregistrement ne sont-elles que de la sauce ? Y a-t-il un inconvénient ? Elles ne peuvent pas être si géniales, n'est-ce pas ?

Comme toujours, quand on "achète" quelque chose ou qu'on obtient quelque chose gratuitement, on prend ce qui est disponible. Les abstractions de journalisation ne sont pas différentes. Ni Common.Logging ni SLF n'exposent au moins un ensemble très important de capacités de log4net/NLog - les capacités de contexte de journalisation (GDC, MDC, NDC). Celles-ci peuvent être essentielles pour obtenir des informations adéquates enregistrées et formatées afin de vous permettre de tirer le meilleur parti de votre système. Le FSL ne fournit pas d'abstraction TraceSource. Il ne fournit pas non plus de fonctions IsXXXEnabled. Common.Logging fournit une abstraction TraceSource. Castle.Logging EXPOSE GDC/MDC/NDC pour log4net et NLog. Il fournit également une abstraction TraceSource. L'abstraction TraceSource de Castle améliore également la journalisation TraceSource en fournissant une capacité de nommage "hiérarchique", similaire à celle fournie par log4net et NLog. C'est plutôt cool !

En outre, ces projets sont tous des logiciels libres sous une forme ou une autre. Ainsi, en fonction de l'abstraction, les développeurs peuvent avoir plus ou moins d'intérêt à la maintenir à jour et à ajouter de nouvelles fonctionnalités. Common.Logging est passé par plusieurs versions et est utilisé, AFAIK, dans Spring.Net. Il semble raisonnablement actif, du moins historiquement. Castle.Logging est utilisé dans le framework Castle. Ils ont donc apparemment de "vrais" clients et sont utilisés dans le "monde réel", ce qui, espérons-le, favorisera la mise en œuvre de nouvelles fonctionnalités. SLF, pour autant que je sache, n'est pas utilisé dans le cadre d'une "vraie" plate-forme de développement, il est donc difficile de dire dans quelle mesure il est exercé.

La feuille de route de ces plateformes n'est pas claire. Common.Logging a quelques fonctionnalités à venir listées sur leur site web, mais pas d'indication claire quand elles seront disponibles. Le site web dit "Juin", mais de quelle année ? A quelle fréquence la liste de diffusion est-elle contrôlée ? Pour le FSL, à quelle fréquence leur codeplex est-il contrôlé ? Quelle est la priorité de ces projets "gratuits" par rapport aux emplois rémunérés des développeurs ? Pouvez-vous vous permettre qu'une abstraction tierce implémente une fonctionnalité dont vous avez besoin ? Seront-ils réceptifs si vous implémentez quelque chose et que vous le soumettez à nouveau pour qu'il soit inclus dans le produit ?

D'un point de vue positif, toutes les sources de ces abstractions sont disponibles, ce qui vous permet d'en assumer la responsabilité et d'apporter les corrections ou les améliorations que vous souhaitez, sans avoir à consacrer du temps et de l'énergie à la création d'une abstraction à partir de zéro. Vous aimez Common.Logging mais vous voulez vraiment log4net/NLog GDC/MDC/NDC ? Prenez l'implémentation de Castle et ajoutez-la à Common.Logging. Et voilà ! Une abstraction de journalisation qui contient presque 100% de l'API de journalisation de log4net/NLog. Vous préférez SLF mais vous aimeriez qu'il ait IsXXXEnabled ? Il n'y a pas beaucoup de travail pour l'implémenter. Allez-y et ajoutez les GDC/MDC/NDC tant que vous y êtes. Vous aimez Castle ? (Je ne suis pas très familier avec lui, je ne suis pas sûr de sa facilité d'utilisation en dehors de Castle, si cela a de l'importance) Attention, je ne l'ai pas utilisé, mais en regardant les sources sur git, on dirait que l'abstraction de logger NLog pourrait ne pas retenir les informations sur le site d'appel.

Est-il éthique de prendre des parties de plusieurs projets open source et de les combiner pour en faire un "super" projet (pour votre usage personnel ou celui de votre entreprise) ? Est-il mauvais de prendre Common.Logging et de l'augmenter avec l'implémentation GDC/MDC/NDC de Castle ? Je ne sais pas. Je vais laisser quelqu'un d'autre répondre à cette question.

J'ai presque fini...

Certaines abstractions de journalisation tierces fournissent d'autres capacités. Vous pouvez utiliser une bibliothèque qui est implémentée en termes de, disons, log4net. Il se peut que vous ne souhaitiez pas utiliser log4net, ou du moins que vous ne souhaitiez pas y être lié. Common.Logging (et peut-être SLF) vous permet de capturer relativement facilement les messages de journalisation de log4net et de les réacheminer à travers l'abstraction afin qu'ils soient capturés dans le flux de journalisation du cadre de journalisation sous-jacent de l'abstraction. Le FSL pourrait fournir quelque chose de similaire. Bien sûr, vous pourriez être en mesure de faire quelque chose de similaire avec les cadres de journalisation existants, soit à partir de la boîte ou en écrivant un log4net Appender personnalisé, NLog Target, ou System.Diagnostics TraceListener. Ces fonctionnalités n'ont pas fait l'objet d'une attention particulière dans mon évaluation de l'opportunité d'utiliser une abstraction de journalisation tierce sur mon projet, car je suis principalement intéressé par l'aspect abstraction.

Alors, où en suis-je ? Je pense qu'il est utile de garder le code de votre application isolé d'un cadre de journalisation spécifique. Pour moi, Common.Logging semble être un choix d'abstraction solide, bien que certaines fonctionnalités importantes soient manquantes (GDC/MDC/NDC) et qu'il ne soit pas compatible avec Silverlight. Ce serait formidable si ces fonctionnalités devenaient bientôt disponibles. Je suis à l'aise avec l'implémentation de GDC/MDC/NDC si je dois le faire. Le rendre compatible avec Silverlight demanderait probablement plus d'efforts, principalement parce que je ne suis pas particulièrement expérimenté avec C#/.NET/Silverlight. Jusqu'à ce que ces problèmes soient résolus, nous pourrions écrire beaucoup de code d'application avec Common.Logging en place. Nous pouvons passer notre temps à développer notre application plutôt que de développer encore une autre bibliothèque de journalisation ou une bibliothèque d'abstraction. Si nous finissons par devoir ajouter ces fonctionnalités manquantes nous-mêmes, eh bien, nous aurions dû faire beaucoup de choses si nous avions implémenté une bibliothèque de journalisation ou une bibliothèque d'abstraction nous-mêmes.

3 votes

Un article d'une telle ampleur ! Je suis d'accord avec tout, +1 certainement, mais peut-être pourrait-il être simplifié/formaté un peu ? Je vois beaucoup de choses énoncées plusieurs fois, par exemple. De plus, étant donné que cet article est très ancien, avez-vous des idées plus récentes à ce sujet ? Est-ce que quelque chose a changé entre-temps qui justifierait qu'on en discute à nouveau ?

1 votes

Je n'ai rien à ajouter par rapport à mon message initial. À l'époque où j'ai écrit ce texte, j'étais en train d'apprendre tout ce que je pouvais sur l'exploitation forestière. Dans le cas de mon organisation, nous avons décidé d'utiliser l'approche de la façade de journalisation, en particulier Common.Logging for .Net. Nous avons également choisi NLog comme système de journalisation sous-jacent, bien qu'en raison de la façade, nous ne dépendions pas directement de NLog.

0 votes

FWIW : Je suis récemment tombé sur une LibLog qui n'est qu'un fichier et non une dépendance.

9voto

azheglov Points 3548

Je pense que ce qui fait de Un (niveau d'abstraction) le chiffre magique ici, c'est que Zéro est trop peu et que Deux est trop.

L'échange d'un enregistreur derrière une façade d'enregistreur (nombre de niveaux : 1) peut éventuellement donner lieu à un avantage pour l'utilisateur, par exemple le nouvel enregistreur peut faire quelque chose que l'ancien enregistreur ne peut pas faire. J'imagine qu'il peut s'agir de performances, de la prise en charge de certains types d'appenders, etc.

Il est beaucoup plus difficile d'imaginer l'avantage pour l'utilisateur de changer la façade d'un enregistreur (nombre de niveaux : 2).

(Et si le nombre de niveaux est de 0, alors c'est probablement juste une mauvaise conception orientée objet : vous aurez des milliers d'endroits dans votre code où le logger est référencé et que se passera-t-il s'il y a un changement de rupture dans la prochaine version du logger).

En ce qui concerne les façades de bûcherons, il semble que vous deviez choisir l'une des options proposées par des tiers ou créer la vôtre et vous préparer à la conserver pendant longtemps.

5voto

christopheml Points 1880

Une utilisation importante d'une façade de journalisation est lorsque vous écrire une bibliothèque . L'intégration de dépendances dans une bibliothèque est toujours quelque chose qui demande un peu de soin, et la journalisation encore plus.

En bref, vous ne voulez pas imposer votre mise en œuvre de la journalisation aux utilisateurs de votre bibliothèque. . L'utilisation d'une façade bien choisie signifie qu'ils seront en mesure de gérer les journaux de votre bibliothèque avec le framework de leur choix et qu'ils n'auront pas à passer par des exclusions de dépendances et des échappatoires bizarres pour faire coexister votre framework de journalisation et le leur.

3voto

nrjohnstone Points 115

Jusqu'à ce que NLog et log4net fournissent une interface qui peut être utilisée à la place des classes concrètes, je les ai toujours abstraites derrière ma propre interface et ma propre classe wrapper.

Pourquoi ?

Pour obtenir la meilleure couverture de test de toutes les exigences de l'utilisateur, en particulier lorsque ces exigences couvrent la journalisation.

Lorsque toute votre journalisation passe par une interface plutôt que par une classe concrète, il devient très facile de fournir un objet fantaisie avec l'interface de journalisation (choisissez la façon dont vous le faites, injection de dépendance, etc.) pour enregistrer tous les appels de journalisation effectués pendant un scénario de test particulier.

Ceux-ci peuvent alors être affirmés et si un changement de code brise la journalisation, vos tests unitaires le couvriront.

Si NLog ou log4Net devaient fournir une interface pour leurs enregistreurs, je n'aurais pas besoin de fournir une interface et une classe d'enveloppe, puisque je pourrais simplement simuler leur interface pour les tests.

3voto

Stas Berkov Points 614

Dans mon projet, j'utilise System.Diagnostics.Trace.TraceError(...) , System.Diagnostics.Debug.Print(...) comme façade pour l'exploitation forestière. Pour organiser (écrire) les journaux, j'utilise NLog, c'est-à-dire que dans app.config j'ai une configuration pour NLog et une redirection de la trace de .net vers NLog.

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <targets>
     <target name="file" xsi:type="File"
      layout="${longdate:universalTime=true}Z [${threadid}] ${pad:padding=5:inner=${level:uppercase=true}} ${logger} ${message}"
      fileName="${basedir}/App_Data/logfile.txt"...
   </targets>
</nlog>
<system.diagnostics>
  <trace>
    <listeners>
      <add name="nlog" type="NLog.NLogTraceListener, NLog" />
    </listeners>
  </trace>
</system.diagnostics>

Cela ne me lie à aucun enregistreur. Lorsque j'envoie mes composants aux clients, ils peuvent utiliser le logger de leur choix. L'utilisation d'un logger particulier dans une application peut causer des problèmes, par exemple, vous pouvez utiliser nlog mais vos clients utilisent log4net.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X