web-dev-qa-db-fra.com

La journalisation est-elle à côté d'une implémentation d'une violation SRP?

En pensant au développement logiciel agile et à tous les principes (SRP, OCP, ...) Je me demande comment traiter la journalisation.

est une journalisation à côté d'une implémentation d'une violation SRP?

Je dirais que yes parce que la mise en œuvre devrait également pouvoir fonctionner sans enregistrer. Alors, comment puis-je mettre en œuvre la journalisation d'une meilleure façon? J'ai vérifié certains modèles et est arrivé à une conclusion que la meilleure façon de ne pas violer les principes de manière définie par l'utilisateur, mais d'utiliser tout modèle connu pour violer un principe consiste à utiliser un motif de décorateur.

Disons que nous avons un tas de composants complètement sans violation SRP et nous voulons ensuite ajouter une exploitation forestière.

  • composant
  • composant B utilise un

Nous voulons de vous connecter à un, nous créons donc un autre composant D décoré avec une interface I.

  • interface i
  • composant L (composant de journalisation du système)
  • composant un instrument i
  • composant D implémente i, décorations/utilise a, utilise l pour la journalisation
  • composant b utilise un i

Avantages: - Je peux utiliser un sans journalisation - Testez un moyen que je n'ai pas besoin de des simulacres d'enregistrement - les tests sont plus simples

Inconvénient: - Plus de composants et plus de tests

Je sais que cela semble être une autre question de discussion ouverte, mais je veux réellement savoir si quelqu'un utilise de meilleures stratégies de journalisation qu'un décorateur ou une violation SRP. Qu'en est-il de l'enregistreur statique Singleton qui sont comme valeur par défaut NullLlogger et si la journalisation SysLog est souhaitée, on modifie l'objet de mise en œuvre au moment de l'exécution?

19
Aitch

Oui, il s'agit d'une violation de SRP car la journalisation est une préoccupation transversale.

La bonne voie est de Déléguer la journalisation à une classe d'enregistrement (Interception) Le seul but est de se connecter - respectueux du SRP.

Voir ce lien pour un bon exemple: https://msdn.microsoft.com/en-us/library/dn178467%28v=pandp.30%29.aspx

Voici un Exemple court :

public interface ITenantStore
{
    Tenant GetTenant(string tenant);
    void SaveTenant(Tenant tenant);
}

public class TenantStore : ITenantStore
{
    public Tenant GetTenant(string tenant)
    {....}

    public void SaveTenant(Tenant tenant)
    {....}
} 

public class TenantStoreLogger : ITenantStore
{
    private readonly ILogger _logger; //dep inj
    private readonly ITenantStore _tenantStore;

    public TenantStoreLogger(ITenantStore tenantStore)
    {
        _tenantStore = tenantStore;
    }

    public Tenant GetTenant(string tenant)
    {
        _logger.Log("reading tenant " + tenant.id);
        return _tenantStore.GetTenant(tenant);
    }

    public void SaveTenant(Tenant tenant)
    {
        _tenantStore.SaveTenant(tenant);
        _logger.Log("saving tenant " + tenant.id);
    }
}

Les avantages comprennent

  • Vous pouvez tester cela sans enregistrer - true Test de l'unité
  • vous pouvez facilement basculer la connexion/off - même au moment de l'exécution
  • vous pouvez remplacer la journalisation pour d'autres formes de journalisation, sans jamais avoir à modifier le fichier TenantStore.
0
z0mbi3

Je dirais que vous prenez SRP beaucoup trop au sérieux. Si votre code est suffisamment bien rangé, la journalisation est la seule "violation" de SRP, vous prenez mieux à 99% de tous les autres programmeurs, et vous devriez vous tapoter sur le dos.

Le point de SRP est d'éviter un code spaghetti horrible où le code qui fait différentes choses est tout mélangé ensemble. Mélanger la journalisation avec le code fonctionnel ne sonne pas des cloches d'alarme pour moi.

61
grahamparks

Non, ce n'est pas une violation de SRP.

Les messages que vous envoyez au journal doivent changer pour les mêmes raisons que le code environnant.

Qu'est-ce que IS Une violation de SRP utilise une bibliothèque spécifique pour la journalisation directement dans le code. Si vous décidez de modifier le mode de journalisation, SRP indique qu'il ne faut pas avoir d'impact sur votre code d'entreprise.

Une sorte d'abstrait Logger doit être accessible à votre code de mise en œuvre, et la seule chose que votre implémentation devrait dire est "Envoyer ce message au journal", sans préoccupation WRT comment c'est fait. Décider de la manière exacte de la journalisation (même horodatage) n'est pas la responsabilité de votre implémentation.

Votre implémentation devrait également ne pas savoir si l'enregistreur qu'il envoie des messages est un NullLogger.

Cela dit.

Je ne brosserais pas la déconnexion comme une préoccupation transversale trop rapide. Émettre des journaux pour tracer des événements spécifiques survenant dans votre code de mise en œuvre appartient au code de mise en œuvre.

Qu'est-ce qu'une préoccupation transversale, OTOH, est Execution TRACing: la journalisation entre et sort dans chaque méthode. AOP est mieux placé pour faire cela.

15
Laurent LA RIZZA

Comme la journalisation est souvent considérée comme une préoccupation transversale, je suggérerais d'utiliser un AOP pour la séparation de la journalisation de la mise en œuvre.

En fonction de la langue, vous utiliseriez un intercepteur ou un certain AOP Cadre (E.G. AspectJ en Java) pour effectuer cela.

La question est de savoir si cela vaut vraiment le tracas. Notez que cette séparation augmentera la complexité de votre projet tout en offrant très peu d'avantages.

7
Oliver Weiler

Cela semble bien. Vous décrivez un décorateur de journalisation assez standard. Tu as:

composant L (composant de journalisation du système)

Cela a une responsabilité: des informations de journalisation qui lui sont transmises.

composant un instrument i

Cela a une responsabilité: fournir une mise en œuvre de l'interface I (en supposant que je suis correctement conforme à SRP, c'est-à-dire).

C'est la partie cruciale:

composant D implémente i, décorations/utilise a, utilise l pour la journalisation

Lorsque cela indiquait de cette façon, cela semble complexe, mais le regarde de cette façon: le composant d compte un chose: amenant A et L ensemble.

  • Le composant D ne se connecte pas; il déléguait que
  • Le composant D ne met pas en œuvre i même; il déléguait que à un

Le seulement Responsabilité que le composant D a pour but de s'assurer que L est notifié lorsqu'il est utilisé. Les implémentations d'A et L sont les deux ailleurs. Ceci est entièrement conforme à SRP, tout en étant un exemple soigné d'OCP et une utilisation assez courante des décorateurs.

ne mise en garde importante : Lorsque D utilise votre composant de journalisation L, il devrait le faire d'une manière qui vous permet de changer Comment Vous êtes enregistré. Le moyen le plus simple de le faire est d'avoir une interface IL qui est mise en œuvre par L. ALORS:

  • Le composant D utilise un IL pour se connecter; Une instance de L est fournie
  • Le composant D utilise un I pour fournir des fonctionnalités; Une instance d'A est fournie
  • Composant B utilise un I; Une instance de D est fournie

De cette façon, rien ne dépend directement de quoi que ce soit d'autre, ce qui facilite la sauvegarde. Cela facilite l'adaptation pour changer, et facile à simuler des parties du système afin que vous puissiez passer un test.

5
anaximander

Bien sûr, c'est une violation de SRP lorsque vous avez une préoccupation transversale. Vous pouvez toutefois créer une classe responsable de la composition de la journalisation avec l'exécution de toute action.

exemple:

class Logger {
   ActuallLogger logger;
   public Action ComposeLog(string msg, Action action) {
      return () => {
          logger.debug(msg);
          action();
      };
   }
}
1
Paul Nikonowicz