Les «préoccupations transversales» sont-elles une excuse valable pour casser SOLID / DI / IoC?

43

Mes collègues aiment dire que "la journalisation / la mise en cache / etc. Est une préoccupation transversale", puis continue en utilisant le singleton correspondant partout. Pourtant, ils aiment IoC et DI.

Est-ce vraiment une excuse valable pour casser le principe SOLI D ?

Tanière
la source
27
J'ai constaté que les principes SOLID ne sont généralement utiles que pour ceux qui ont déjà l'expérience nécessaire pour les suivre sans le savoir de toute façon.
svidgen
1
J'ai trouvé que le terme "préoccupation transversale" était un terme assez spécifique (lié à des aspects) et n'était pas nécessairement synonyme de singleton. La journalisation peut être une préoccupation transversale dans la mesure où vous souhaitez parfois journaliser un message générique à plusieurs endroits de la même manière (par exemple, enregistrez chaque appel à une méthode de service avec qui a passé l'appel ou une autre journalisation de type d'audit). Cependant, je dirais que l’exploitation forestière (au sens général) n’est pas une préoccupation transversale simplement parce qu’elle est utilisée partout. Je pense que c'est plus une "préoccupation omniprésente" bien que ce ne soit pas vraiment un terme standard.
Pace
4
@svidgen les principes SOLID sont également utiles lorsque ceux qui ne les connaissent pas révisent votre code et vous demandent pourquoi vous l'avez fait de cette façon. C'est bien de pouvoir pointer un principe et de dire: "voilà pourquoi"
candied_orange
1
Avez-vous des exemples de raisons pour lesquelles vous pensez que la journalisation est un cas particulier? C’est un canal assez simpliste pour rediriger certaines données, qui fait généralement partie du framework X que vous utilisez.
ksiimson

Réponses:

42

Non.

SOLID existe en tant que directives pour rendre compte de changements inévitables. N'allez-vous jamais vraiment changer votre bibliothèque de journalisation, votre cible, votre filtrage, votre mise en forme ou ...? N'allez-vous pas vraiment changer votre bibliothèque de cache, votre cible, votre stratégie, votre périmètre ou ...?

Bien sûr, vous êtes. À tout le moins , vous allez vouloir vous moquer de ces choses de manière saine pour les isoler aux fins de tests. Et si vous voulez les isoler pour les tester, vous allez probablement rencontrer une raison professionnelle qui les oblige à les isoler pour des raisons réelles.

Et vous obtiendrez alors l'argument que l'enregistreur lui - même gérera le changement. "Oh, si la cible / le filtrage / le formatage / la stratégie changent, alors nous allons simplement changer la configuration!" C'est des ordures. Non seulement vous avez maintenant un objet divin qui gère toutes ces choses, mais vous écrivez votre code au format XML (ou similaire) sans analyse statique, sans erreur de compilation, et sans erreur. t vraiment obtenir des tests unitaires efficaces.

Existe-t-il des cas de violation des directives SOLID? Absolument. Parfois, les choses ne changeront pas (sans exiger de toute façon une réécriture complète). Parfois, une légère violation de LSP est la solution la plus propre. Parfois, faire une interface isolée ne fournit aucune valeur.

Mais la journalisation et la mise en cache (et d’autres préoccupations transversales omniprésentes) ne sont pas ces cas. Ce sont généralement d'excellents exemples des problèmes de couplage et de conception que vous rencontrez lorsque vous ignorez les instructions.

Telastyn
la source
22
Quelle alternative as-tu alors? Injecter un ILogger dans chaque classe que vous écrivez? Écrire un décorateur pour chaque classe qui a besoin d'un enregistreur?
Robert Harvey
16
Ouais. Si quelque chose est une dépendance, faites-en une dépendance . Et si cela signifie trop de dépendances, ou si vous passez un enregistreur quelque part, cela ne devrait pas aller - bon , maintenant vous pouvez corriger votre conception.
Telastyn
20
Le véritable problème que j'ai avec IoC dogmatique est que pratiquement tout le code moderne dépend de quelque chose qui n'est ni injecté ni extrait. Si vous écrivez C #, par exemple, vous allez pas souvent à l' abstrait Stringou Int32ou même Listde votre module. Il y a juste une mesure pour laquelle il est raisonnable et sain d' esprit de planifier le changement. Et, au-delà des types de «noyau» les plus évidents, discerner ce que vous pourriez changer est vraiment une question d'expérience et de jugement.
svidgen
6
@svidgen - J'espère que vous n'avez pas lu ma réponse, qui préconise l'IoC dogmatique. Et ce n'est pas parce que nous ne faisons pas abstraction de ces types de base (et d'autres choses prudentes) que nous pouvons avoir un List / String / Int / etc global.
Telastyn
38

Oui

C’est l’essentiel de l’expression "préoccupation intersectorielle" - cela signifie quelque chose qui ne correspond pas parfaitement au principe SOLID.

C'est ici que l'idéalisme rencontre la réalité.

Les personnes semi-nouvelles dans SOLID et transversales se heurtent souvent à ce défi mental. C'est bon, ne panique pas. S'efforcer de tout mettre en termes de SOLID, mais il y a quelques endroits comme la journalisation et la mise en cache où SOLID n'a tout simplement pas de sens. Coupe transversale est le frère de SOLID, ils vont de pair.

Klom Dark
la source
9
Une réponse raisonnée, pratique et non dogmatique.
user1936
11
Pouvez-vous nous dire pourquoi les cinq principes SOLID sont brisés par des préoccupations transversales? J'ai du mal à comprendre cela.
Doc Brown
4
Ouais. Je pourrais potentiellement penser à une bonne raison de "casser" chaque principe individuellement; mais pas une seule raison de casser tous les 5!
svidgen
1
Ce serait idéal pour moi de ne pas avoir à me cogner la tête contre le mur chaque fois que je dois me moquer d'un enregistreur / cache singleton pour un test unitaire. Imaginez ce que ce serait de tester à l'unité une application Web sans l'avoir HttpContextBase(introduite précisément pour cette raison). Je sais pour sûr que ma réalité serait vraiment mauvaise sans cette classe.
devnull
2
@devnull c'est peut-être le problème alors, plutôt que les problèmes transversaux eux-mêmes ...
Boris l'Araignée
25

Pour l'enregistrement, je pense que c'est. La journalisation est omniprésente et généralement sans rapport avec la fonctionnalité du service. Il est courant et bien compris d'utiliser les modèles de singleton du cadre de journalisation. Si vous ne le faites pas, vous créez et injectez des enregistreurs partout et vous ne le souhaitez pas.

Un problème de ce qui précède est que quelqu'un dira "mais comment puis-je tester la journalisation?" . Mes pensées sont que je ne teste pas normalement la journalisation, à part affirmer que je peux réellement lire les fichiers de log et les comprendre. Lorsque j'ai vu la journalisation testée, c'est généralement parce que quelqu'un a besoin d'affirmer qu'une classe a réellement fait quelque chose et qu'elle utilise les messages du journal pour obtenir ce retour. Je préférerais de loin inscrire un auditeur / observateur dans cette classe et affirmer dans mes tests que cela s'appelle. Vous pouvez ensuite placer la journalisation de vos événements dans cet observateur.

Je pense que la mise en cache est un scénario complètement différent, cependant.

Brian Agnew
la source
3
Après avoir un peu touché à FP, je suis maintenant très intéressé par l’utilisation de la composition de fonctions (peut-être monadique) pour intégrer des éléments tels que la journalisation, la gestion des erreurs, etc. voir fsharpforfunandprofit.com/rop )
sara
5
L'enregistrement ne devrait pas être omniprésent. Si c'est le cas, vous vous connectez beaucoup trop et vous ne faites que créer du bruit lorsque vous devez consulter ces journaux. En injectant la dépendance de l'enregistreur, vous êtes obligé de penser à la nécessité de consigner ou non quelque chose.
RubberDuck
12
@RubberDuck - Dites-moi que "la journalisation ne devrait pas être omniprésente" lorsque je reçois un rapport de bogue sur le terrain et que la seule capacité de débogage dont j'ai besoin pour comprendre ce qui s'est passé est ce fichier journal que je ne voulais pas rendre omniprésent. Leçon apprise, l'exploitation forestière devrait être "omniprésente", très omniprésente.
Dunk
15
@RubberDuck: Avec le logiciel serveur, la journalisation est le seul moyen de survivre. C'est la seule façon de résoudre un bug qui s'est passé il y a 12 heures au lieu d'être présent sur votre propre ordinateur portable. Ne vous inquiétez pas du bruit. Utilisez un logiciel de gestion des journaux pour pouvoir interroger votre journal (idéalement, vous devriez également configurer des alarmes qui vous
enverront un
6
Notre personnel de support m'appelle et me dit "le client cliquait sur certaines pages et une erreur s'est produite". Je leur demande ce que l'erreur a dit, ils ne savent pas. Je demande à quoi le client a cliqué, il ne sait pas. Je leur demande s'ils peuvent se reproduire, ils ne peuvent pas. Je conviens que la journalisation peut principalement être réalisée avec des enregistreurs bien déployés dans quelques points clés, mais les petits messages étranges ici et là sont également inestimables. La peur de se connecter conduit à un logiciel de qualité inférieure. Si vous vous retrouvez avec trop de données, élaguez-le. Ne pas optimiser prématurément.
Pace
12

Mes 2 centimes ...

Oui et non.

Vous ne devriez jamais vraiment violer les principes que vous adoptez. mais vos principes doivent toujours être nuancés et adoptés au service d'un objectif plus élevé. Ainsi, avec une compréhension correctement conditionnée, certaines violations apparentes peuvent ne pas être de véritables violations de "l'esprit" ou du "corps de principes dans son ensemble".

Les principes SOLID en particulier, en plus de nécessiter beaucoup de nuances, sont finalement inféodés à l’objectif de «fournir un logiciel fonctionnel et maintenable». Ainsi, adhérer à un principe SOLID particulier est contre-productif et contradictoire lorsque cela entre en conflit avec les objectifs de SOLID. Et ici, je constate souvent que la prestation des atouts maintenabilité .

Alors, qu'en est-il du D dans SOLID ? Cela contribue à augmenter la maintenabilité en rendant votre module réutilisable relativement agnostique par rapport à son contexte. Et nous pouvons définir le "module réutilisable" comme "une collection de code que vous prévoyez d'utiliser dans un autre contexte distinct". Et cela s'applique à des fonctions, classes, ensembles de classes et programmes uniques.

Et oui, le fait de changer les implémentations de l'enregistreur place probablement votre module dans un "autre contexte distinct".

Alors, laissez-moi vous proposer mes deux grandes mises en garde :

Premièrement: tracer des lignes autour des blocs de code qui constituent "un module réutilisable" relève du jugement des professionnels. Et votre jugement est nécessairement limité à votre expérience.

Si vous n'envisagez pas actuellement d'utiliser un module dans un autre contexte, il est probablement acceptable qu'il en dépende impuissant. La mise en garde à la mise en garde: Vos plans sont probablement faux - mais c'est aussi OK. Plus vous écrivez, module après module, plus vous serez intuitif et précis: "J'aurai besoin de ça un jour de plus". Mais vous ne pourrez probablement jamais dire rétrospectivement: «J'ai tout modulé et tout découplé dans toute la mesure du possible, mais sans excès ».

Si vous vous sentez coupable de vos erreurs de jugement, allez à la confession et passez à autre chose ...

Deuxièmement: Inverser le contrôle n’équivaut pas à des dépendances d’injection .

Cela est particulièrement vrai lorsque vous commencez à injecter des dépendances ad nauseam . L'injection de dépendance est une tactique utile pour la stratégie globale d'IoC. Mais, je dirais que l' efficacité de l' ID est inférieure à celle d'autres tactiques - comme l'utilisation d'interfaces et d'adaptateurs - de points uniques d'exposition au contexte depuis le module.

Et concentrons-nous vraiment sur cela une seconde. Parce que, même si vous injectez une Logger annonce , vous devez écrire du code sur l' Loggerinterface. Vous ne pouviez pas commencer à utiliser un nouveau Loggerfournisseur différent qui prend des paramètres dans un ordre différent. Cette capacité provient du codage, au sein du module, d’une interface existante dans le module et comportant un seul sous-module (adaptateur) permettant de gérer la dépendance.

Et si vous codez sur un adaptateur, le fait qu’il Loggersoit injecté dans cet adaptateur ou découvert par celui-ci est en général assez insignifiant pour l’objectif de maintenabilité global. Et plus important encore, si vous avez un adaptateur de niveau module, il est probablement absurde de l'injecter dans n'importe quoi. C'est écrit pour le module.

tl; dr - Arrêtez de vous préoccuper des principes sans vous soucier de la raison pour laquelle vous les utilisez. Et, plus concrètement, construisez simplement un Adaptermodule pour chaque module. Utilisez votre jugement lorsque vous décidez où vous tracez les limites du "module". Dans chaque module, allez-y et consultez directement le Adapter. Et bien sûr, injectez le vrai enregistreur dans le Adapter- mais pas dans tout ce qui pourrait en avoir besoin.

svidgen
la source
4
Man ... J'aurais donné une réponse plus courte, mais je n'avais pas le temps.
svidgen
2
+1 pour utiliser un adaptateur. Vous devez isoler les dépendances des composants tiers afin de leur permettre d'être remplacés dans la mesure du possible. La journalisation est une cible facile pour cela. De nombreuses implémentations de journalisation existent et ont généralement des API similaires. Par conséquent, une simple implémentation d'adaptateur peut vous permettre de les modifier très facilement. Et aux personnes qui disent que vous ne changerez jamais votre fournisseur d’enregistrement: j’ai dû le faire, et cela a été très pénible, car je n’utilisais pas d’adaptateur.
Jules
"Les principes de SOLID en particulier, en plus de nécessiter beaucoup de nuances, sont finalement inféodés à l'objectif de" fournir un logiciel fonctionnel et maintenable. "" - C'est l'une des meilleures déclarations que j'ai vues. En tant que codeur modérément OCD, j'ai eu ma part de luttes entre idéalisme et productivité.
DVK
Chaque fois que je vois un +1 ou un commentaire sur une ancienne réponse, je relis ma réponse et découvre à nouveau que je suis un écrivain terriblement désorganisé et peu clair ... J'apprécie cependant le commentaire, @DVK.
svidgen
Les adaptateurs permettent de sauver des vies, ils ne coûtent pas cher et vous facilitent la vie, en particulier lorsque vous souhaitez appliquer SOLID. Les tests sont un jeu d'enfant avec eux.
Alan
8

L'idée que l'exploitation forestière doit toujours être implémentée en tant que singleton est un de ces mensonges qui a été dit si souvent qu'il a gagné du terrain.

Depuis que les systèmes d’exploitation modernes existent, il est reconnu que vous voudrez peut-être vous connecter à plusieurs endroits en fonction de la nature de la sortie .

Les concepteurs de systèmes doivent constamment s'interroger sur l'efficacité des solutions antérieures avant de les inclure aveuglément dans de nouvelles solutions. S'ils ne font pas preuve d'une telle diligence, ils ne font pas leur travail.

Robbie Dee
la source
2
Quelle est votre solution proposée alors? Est-ce qu'il injecte un ILogger dans chaque classe que vous écrivez? Qu'en est-il d'utiliser un motif de décorateur?
Robert Harvey
4
Pas vraiment répondre à ma question maintenant, est-ce? J'ai cité les modèles simplement à titre d'exemple ... Ce ne sont pas nécessairement ceux-là si vous avez quelque chose de mieux à l'esprit.
Robert Harvey
8
Je ne comprends pas vraiment cette réponse, en termes de propositions concrètes
Brian Agnew
3
@RobbieDee - Vous dites donc que la journalisation devrait être mise en œuvre de la manière la plus compliquée et la plus gênante par la "chance" que nous pourrions vouloir vous connecter à plusieurs endroits? Même si un changement de ce type se produisait, pensez-vous vraiment que l'ajout de cette fonctionnalité à l'instance existante de Logger demandera plus de travail que de déployer tous les efforts nécessaires pour faire passer ce Logger entre les classes et modifier les interfaces lorsque vous décidez que vous voulez un Logger ou non? les dizaines de projets où cette journalisation multiple ne se produira jamais?
Dunk
2
Re: "vous souhaiterez peut-être vous connecter à plusieurs endroits en fonction de la nature du résultat": Bien sûr, le meilleur moyen de le gérer consiste à utiliser le framework de journalisation plutôt que d'essayer d'injecter plusieurs dépendances de journalisation distinctes. (Les cadres de coupe communs supportent déjà cela.)
Ruakh,
4

La journalisation est vraiment un cas particulier.

@Telastyn écrit:

N'allez-vous jamais vraiment changer votre bibliothèque de journalisation, votre cible, votre filtrage, votre mise en forme ou ...?

Si vous prévoyez que vous devrez peut-être modifier votre bibliothèque de journalisation, vous devriez utiliser une façade. Soit SLF4J si vous êtes dans le monde Java.

Pour le reste, une bonne bibliothèque de journalisation se charge de changer l’emplacement de la journalisation, les événements filtrés, leur formatage à l’aide des fichiers de configuration du consignateur et (si nécessaire) de classes de plug-in personnalisées. Il existe un certain nombre d'alternatives disponibles dans le commerce.

En bref, ce sont des problèmes résolus ... pour la journalisation ... et il n’est donc pas nécessaire d’utiliser Dependency Injection pour les résoudre.

Le seul cas où l'ID pourrait être bénéfique (par rapport aux approches de journalisation standard) est si vous souhaitez soumettre la journalisation de votre application à des tests unitaires. Cependant, j'imagine que la plupart des développeurs diraient que la journalisation ne fait pas partie des fonctionnalités d'une classe et ne doit pas être testée.

@Telastyn écrit:

Et vous obtiendrez alors l'argument que l'enregistreur lui-même gérera le changement. "Oh, si la cible / le filtrage / le formatage / la stratégie changent, alors nous allons simplement changer la configuration!" C'est des ordures. Non seulement vous avez maintenant un objet divin qui gère toutes ces choses, mais vous écrivez votre code en XML (ou similaire) sans analyse statique, sans erreur de compilation et sans erreur. t vraiment obtenir des tests unitaires efficaces.

Je crains que ce soit une riposte très théorique. En pratique, la plupart des développeurs et intégrateurs de systèmes aiment le fait que vous puissiez configurer la journalisation via un fichier de configuration. Et ils aiment le fait qu'ils ne sont pas censés tester à l'unité la journalisation d'un module.

Bien sûr, si vous compliquez la configuration de la journalisation, vous pouvez avoir des problèmes, mais ils se manifesteront par le fait que l'application échouera au démarrage ou trop ou trop peu de journalisation. 1) Ces problèmes sont facilement résolus en corrigeant l'erreur dans le fichier de configuration. 2) L'alternative consiste en un cycle complet de génération / analyse / test / déploiement à chaque modification des niveaux de journalisation. Ce n'est pas acceptable.

Stephen C
la source
3

Oui et non !

Oui: Je pense qu'il est raisonnable que différents sous-systèmes (ou couches sémantiques ou bibliothèques ou autres notions de groupement modulaire) acceptent chacun un enregistreur (identique ou potentiellement différent) lors de leur initialisation plutôt que tous les sous-systèmes utilisant le même singleton partagé commun .

cependant,

Non: il est en même temps déraisonnable de paramétrer la journalisation dans chaque petit objet (par constructeur ou méthode d'instance). Pour éviter des pertes de temps inutiles et inutiles, les petites entités doivent utiliser le consignateur unique du contexte qui les entoure.


C'est une raison parmi beaucoup d'autres de penser à la modularité en niveaux: les méthodes sont regroupées dans des classes, tandis que les classes sont regroupées dans des sous-systèmes et / ou des couches sémantiques. Ces paquets plus importants sont de précieux outils d’abstraction; nous devrions donner des considérations différentes dans les limites modulaires que lorsque nous les traversons.

Erik Eidt
la source
3

Tout d’abord, cela commence par un cache singleton fort, puis les objets singletons forts de la couche base de données qui introduisent l’état global, des API non descriptives d’ classes et du code non testable.

Si vous décidez de ne pas avoir un singleton pour une base de données, ce n'est probablement pas une bonne idée d'avoir un singleton pour un cache, après tout, ils représentent un concept très similaire, le stockage de données, utilisant uniquement des mécanismes différents.

L'utilisation d'un singleton dans une classe transforme une classe ayant un nombre spécifique de dépendances en une classe ayant théoriquement un nombre infini d'entre elles, car vous ne savez jamais ce qui est réellement caché derrière la méthode statique.

Au cours des dix dernières années, j’ai passé à la programmation. Dans un cas seulement, j’ai assisté à un effort visant à modifier la logique d’exploitation forestière (qui était alors écrit singleton). Donc, bien que j'aime les injections de dépendance, la journalisation n'est vraiment pas une préoccupation majeure. Cache, par contre, je le ferais toujours comme dépendance.

Andy
la source
Oui, la journalisation change rarement et ne nécessite généralement pas d'être un module échangeable. Cependant, j’ai une fois essayé de tester d’une manière générale une classe d’aide à la journalisation, qui dépendait de manière statique du système de journalisation. J'ai décidé que le mécanisme le plus simple pour le rendre testable serait d'exécuter la classe sous test dans un processus séparé, de configurer son enregistreur pour écrire dans STDOUT, et d'analyser cette sortie dans mon scénario de test: «J'ai eu une expérience similaire avec des horloges où vous ' d ne veulent évidemment jamais que du temps réel, non? Sauf lors du test de fuseau horaire / heure d' été cas limites, bien sûr ...
amon
@amon: Les horloges sont comme une connexion, à savoir qu'il existe déjà un autre mécanisme ayant le même objectif que DI, à savoir Joda-Time et ses nombreux ports. (Il n'y a rien de mal à utiliser DI au lieu de cela, mais il est plus simple d'utiliser Joda-Time directement que d'essayer d'écrire un adaptateur injectable personnalisé, et je n'ai jamais vu personne regretter de l'avoir fait.)
Ruakh,
@amon "J'ai eu une expérience similaire avec des horloges où vous ne voudriez évidemment jamais rien d'autre que le temps réel, non? Sauf en cas de test de cas d'extrémité de fuseau horaire / DST, bien sûr…" - ou lorsque vous réalisez qu'un bogue a corrompu votre base de données et le seul espoir de le récupérer est d'analyser votre journal des événements et de le rejouer à partir de la dernière sauvegarde ... mais du coup, tout votre code doit fonctionner en fonction de l'horodatage de l'entrée de journal actuelle temps.
Jules
3

Oui et non, mais surtout non

Je suppose que la majeure partie de la conversation est basée sur une instance statique vs une instance injectée. Personne ne propose que l'enregistrement coupe le SRP, je suppose? Nous parlons principalement du "principe d'inversion de dépendance". Je suis surtout d'accord avec la non-réponse de Telastyn.

Quand est-il possible d'utiliser la statique? Parce qu'il est clair que parfois ça va. Les réponses positives des avantages de l'abstraction et les réponses "non" indiquent qu'elles sont payantes. Une des raisons pour lesquelles votre travail est difficile est qu'il n'y a pas une seule réponse que vous puissiez écrire et appliquer à toutes les situations.

Prendre: Convert.ToInt32("1")

Je préfère ceci à:

private readonly IConverter _converter;

public MyClass(IConverter converter)
{
   Guard.NotNull(converter)
   _converter = conveter
}

.... 
var foo = _converter.ToInt32("1");

Pourquoi? J'accepte le fait que je devrai refactoriser le code si j'ai besoin de la souplesse nécessaire pour échanger le code de conversion. J'accepte le fait que je ne pourrai pas me moquer de ça. Je crois que la simplicité et la concision valent ce métier.

À l'autre extrémité du spectre, si IConverterc'était un SqlConnection, je serais assez horrifié de voir cela comme un appel statique. Les raisons pour lesquelles l'échec est évident. Je ferais remarquer qu'un SQLConnectionmot peut être assez "transversal" dans une application, de sorte que je n'aurais pas utilisé ces mots exacts.

La journalisation ressemble-t-elle davantage à un SQLConnectionou Convert.ToInt32? Je dirais plus comme 'SQLConnection`.

Vous devriez vous moquer de la journalisation . Il parle au monde extérieur. Lorsque j'écris une méthode en utilisant Convert.ToIn32, je l'utilise comme outil pour calculer une autre sortie de la classe pouvant être testée séparément. Je n'ai pas besoin de vérifier que l' Convertappel a été correctement effectué en vérifiant que "1" + "2" == "3". La journalisation est différente, c'est une sortie totalement indépendante de la classe. Je suppose que c'est un résultat qui a de la valeur pour vous, l'équipe de support et l'entreprise. Votre classe ne fonctionne pas si la journalisation n'est pas correcte; les tests unitaires ne doivent donc pas réussir. Vous devriez tester ce que vos journaux de classe. Je pense que c'est l'argument tueur, je pourrais vraiment m'arrêter ici.

Je pense aussi que c'est quelque chose qui va très probablement changer. Une bonne journalisation n'imprime pas que des chaînes, c'est une vue de ce que fait votre application (je suis un grand fan de la journalisation basée sur les événements). J'ai vu des opérations de journalisation de base se transformer en interfaces de création de rapports très élaborées. Évidemment, il est beaucoup plus facile d'aller dans cette direction si votre exploitation forestière ressemble _logger.Log(new ApplicationStartingEvent())et moins Logger.Log("Application has started"). On pourrait dire que cela crée un inventaire pour un avenir qui pourrait ne jamais se produire, ceci est un jugement et je pense que cela en vaut la peine.

En fait, dans un de mes projets personnels, j’ai créé une interface utilisateur ne se connectant pas à l’enregistrement uniquement à l’aide de l’ _loggeraffichage du contenu de l’application. Cela signifiait que je n'avais pas à écrire de code pour comprendre ce que faisait l'application, et je me suis retrouvé avec une journalisation solide. J'ai l'impression que si mon attitude vis-à-vis de l'exploitation forestière était que c'était simple et immuable, cette idée ne me serait pas venue à l'esprit.

Je suis donc d'accord avec Telastyn pour le cas de la journalisation.

Nathan Cooper
la source
C'est comme ça que je me connecte accidentellement . J'aimerais créer un lien vers un article ou quelque chose, mais je n'en trouve pas. Si vous êtes dans le monde .NET et que vous consultez la journalisation des événements, vous trouverez Semantic Logging Application Block. Ne l'utilisez pas, comme la plupart du code créé par l'équipe "patterns and practice" de MS, ironiquement, c'est un anti-modèle.
Nathan Cooper
3

Premièrement, les problèmes intersectoriels ne sont pas des éléments constitutifs majeurs et ne doivent pas être traités comme des dépendances dans un système. Un système devrait fonctionner si, par exemple, Logger n’est pas initialisé ou si le cache ne fonctionne pas. Comment allez-vous rendre le système moins couplé et cohésif? C’est là que SOLID entre en scène dans la conception du système OO.

Garder objet en tant que singleton n'a rien à voir avec SOLID. C'est le cycle de vie de votre objet pendant combien de temps vous voulez que l'objet vive en mémoire.

Une classe qui a besoin d'une dépendance pour s'initialiser ne doit pas savoir si l'instance de classe fournie est singleton ou transitoire. Mais tldr; si vous écrivez Logger.Instance.Log () dans chaque méthode ou classe, le code qui pose problème (odeur de code / couplage dur) est vraiment désordonné. C'est le moment où les gens commencent à abuser de SOLID. Et les autres développeurs comme OP commencent à poser de véritables questions comme celle-ci.

vendettamit
la source
2

J'ai résolu ce problème en utilisant une combinaison d'héritage et de traits (également appelée mixins dans certaines langues). Les traits sont très pratiques pour résoudre ce type de problème transversal. Il s’agit généralement d’une fonctionnalité linguistique, alors je pense que la vraie réponse est qu’elle dépend des fonctionnalités linguistiques.

RibaldEddie
la source
Intéressant. Je n'ai jamais effectué de travail important en utilisant un langage qui prenne en charge les traits, mais j'ai envisagé d'utiliser de tels langages pour des projets futurs. Il serait donc utile pour moi de développer ceci et de montrer comment les traits résolvent le problème.
Jules