Le cosiddette "preoccupazioni trasversali" sono una valida scusa per rompere SOLID / DI / IoC?


43

Ai miei colleghi piace dire "logging / caching / etc. È una preoccupazione trasversale" e quindi procedere usando il singleton corrispondente ovunque. Tuttavia amano IoC e DI.

È davvero una scusa valida per violare il principio SOLI D ?


27
Ho scoperto che i principi SOLID sono principalmente utili solo per coloro che hanno già l'esperienza necessaria per seguirli inconsapevolmente.
svidgen,

1
Ho trovato il termine "preoccupazione trasversale" per essere un termine piuttosto specifico (legato agli aspetti) e non necessariamente essere sinonimo di singleton. La registrazione può essere una preoccupazione trasversale, nel senso che a volte si desidera registrare un messaggio generico in più posizioni nello stesso modo (ad esempio, registrare ogni chiamata a un metodo di servizio con chi ha effettuato la chiamata o un altro tipo di registrazione del controllo). Tuttavia, direi che il disboscamento (in senso generale) non è una preoccupazione trasversale solo perché viene utilizzato ovunque. Penso che questa sia più una "preoccupazione onnipresente" anche se non è un termine standard.
Pace

4
@svidgen i principi SOLID sono utili anche quando chi non li conosce rivede il tuo codice e ti chiede perché l'hai fatto in quel modo. È bello poter indicare un principio e dire "ecco perché"
candied_orange

1
Hai qualche esempio perché pensi che la registrazione sia un caso speciale? È un canale abbastanza semplicistico per reindirizzare alcuni dati, di solito parte di qualunque framework X che si sta utilizzando.
Ksiimson,

Risposte:


42

No.

SOLID esiste come linee guida per tenere conto dell'inevitabile cambiamento. Stai veramente mai andare a cambiare la vostra libreria di registrazione, o di destinazione, o filtrando, o la formattazione, o ...? Stai davvero non ha intenzione di cambiare la vostra libreria di caching, o di destinazione, o di una strategia, o di scoping, o ...?

Certo che lo sei. Per lo meno , vorrai deridere queste cose in modo sano per isolarle per i test. E se vuoi isolarli per i test, probabilmente ti imbatterai in un motivo commerciale in cui li vuoi isolare per motivi di vita reale.

E otterrai quindi l'argomento secondo cui il logger stesso gestirà la modifica. "Oh, se il target / il filtro / la formattazione / la strategia cambiano, cambieremo semplicemente la configurazione!" Questa è spazzatura. Non solo hai un oggetto God che gestisce tutte queste cose, stai scrivendo il tuo codice in XML (o simile) in cui non ottieni analisi statiche, non ricevi errori di compilazione e non ottengo davvero test unitari efficaci.

Esistono casi per violare le linee guida SOLID? Assolutamente. A volte le cose non cambieranno (senza richiedere comunque una riscrittura completa). A volte una leggera violazione di LSP è la soluzione più pulita. A volte creare un'interfaccia isolata non fornisce alcun valore.

Ma la registrazione e la memorizzazione nella cache (e altre onnipresenti preoccupazioni trasversali) non sono questi casi. Di solito sono ottimi esempi dei problemi di accoppiamento e di progettazione che si verificano quando si ignorano le linee guida.


22
Che alternativa hai allora? Iniettare un ILogger in ogni classe che scrivi? Scrivere un decoratore per ogni classe che ha bisogno di un logger?
Robert Harvey,

16
Si. Se qualcosa è una dipendenza, falla diventare una dipendenza . E se questo significa troppe dipendenze, o stai passando un logger da qualche parte non dovrebbe andare - bene , ora puoi correggere il tuo design.
Telastyn,


20
Il vero problema che ho con l'IoC dogmatico è che praticamente tutto il codice moderno dipende da qualcosa che non viene né iniettato né sottratto. Se scrivi C #, per esempio, spesso non stai andando in astratto Stringo Int32o addirittura Listfuori dal tuo modulo. C'è solo una misura in cui è ragionevole e ragionevole pianificare un cambiamento. E, al di là dei tipi "core" per lo più ovvi, discernere cosa potresti probabilmente cambiare è davvero solo una questione di esperienza e giudizio.
svidgen,

6
@svidgen - Spero che tu non abbia letto la mia risposta come sostenitrice dell'IoC dogmatico. E solo perché non riusciamo a sottrarre questi tipi di core (e altre cose dove prudente) non significa che va bene avere un Elenco / String / Int / etc globale.
Telastyn,

38

Questo è l'intero punto del termine "preoccupazione trasversale" - significa qualcosa che non si adatta perfettamente al principio SOLID.

È qui che l'idealismo incontra la realtà.

Le persone semi-nuove di SOLID e trasversali spesso affrontano questa sfida mentale. Va bene, non andare fuori di testa. Cerca di mettere tutto in termini di SOLID, ma ci sono alcuni posti come la registrazione e la memorizzazione nella cache in cui SOLID non ha senso. Il taglio trasversale è il fratello di SOLID, vanno di pari passo.


9
Una risposta ragionata, pratica, non dogmatica.
user1936

11
Puoi dirci perché tutti e cinque i principi SOLID vengono violati da preoccupazioni trasversali? Ho dei problemi per capirlo.
Doc Brown,

4
Si. Potrei potenzialmente pensare a una buona ragione per "infrangere" ciascun principio individualmente; ma non un solo motivo per rompere tutti e 5!
svidgen,

1
Sarebbe l'ideale per me non dover sbattere la testa contro il muro ogni volta che ho bisogno di deridere un logger / cache singleton per un test unitario. Immagina come sarebbe testare l'unità di un'applicazione web senza averla HttpContextBase(che è stata introdotta proprio per questo motivo). So per certo che la mia realtà sarebbe davvero acida senza questa classe.
Devnull,

2
@devnull forse è questo il problema allora, piuttosto che il taglio trasversale riguarda se stessi ...
Boris the Spider

25

Per il logging penso che lo sia. La registrazione è pervasiva e generalmente non correlata alla funzionalità del servizio. È comune e ben compreso l'utilizzo dei modelli singleton del framework di registrazione. In caso contrario, stai creando e iniettando logger ovunque e non lo desideri.

Un problema di cui sopra è che qualcuno dirà "ma come posso testare la registrazione?" . Il mio pensiero è che normalmente non collaudo la registrazione, oltre ad affermare che posso effettivamente leggere i file di registro e comprenderli. Quando ho visto il logging testato, di solito è perché qualcuno ha bisogno di affermare che una classe ha effettivamente fatto qualcosa e stanno usando i messaggi di log per ottenere quel feedback. Preferirei di gran lunga registrare un ascoltatore / osservatore su quella classe e affermare nei miei test che viene chiamato. È quindi possibile inserire la registrazione degli eventi all'interno di tale osservatore.

Penso che la memorizzazione nella cache sia uno scenario completamente diverso, tuttavia.


3
Dopo essermi dilettato un po 'in FP ormai sono arrivato a coltivare un grande interesse nell'uso della composizione di funzioni (forse monadiche) per incorporare elementi come la registrazione, la gestione degli errori ecc. Nei casi d'uso senza inserirli nella logica aziendale principale ( vedi fsharpforfunandprofit.com/rop )
sara,

5
La registrazione non dovrebbe essere pervasiva. Se lo è, allora stai registrando troppo e stai solo creando rumore per te stesso quando devi effettivamente andare a guardare quei registri. Iniettando la dipendenza del logger, sei costretto a pensare se devi effettivamente registrare qualcosa.
RubberDuck,

12
@RubberDuck - Dimmi che "la registrazione non dovrebbe essere pervasiva" quando ricevo una segnalazione di bug dal campo e l'unica possibilità di debug che devo capire cosa è successo è quel file di registro che non volevo rendere pervasivo. Insegnamento appreso, la registrazione dovrebbe essere "pervasiva", molto pervasiva.
Dunk,

15
@RubberDuck: con il software server, la registrazione è l'unico modo per sopravvivere. È l'unico modo per capire un bug che si è verificato 12 ore fa anziché in questo momento sul tuo laptop. Non preoccuparti del rumore. Utilizza il software di gestione dei log in modo da poter eseguire una query del log (idealmente dovresti anche impostare allarmi che ti
invieranno

6
Il nostro staff di supporto mi chiama e mi dice "il cliente stava facendo clic su alcune pagine e si è verificato un errore". Chiedo loro cosa ha detto l'errore, non lo sanno. Chiedo a cosa specificamente hanno fatto clic i clienti, che non sanno. Chiedo se possono riprodursi, non possono. Sono d'accordo che il logging può essere realizzato principalmente con logger ben distribuiti in alcuni punti cardine chiave, ma i piccoli messaggi dispari qua e là sono anche preziosi. La paura della registrazione porta a software di qualità inferiore. Se finisci con troppi dati, elimina. Non ottimizzare prematuramente.
Pace

12

I miei 2 centesimi ...

Sì e no.

Non dovresti mai davvero violare i principi che adotti; ma, i tuoi principi dovrebbero sempre essere sfumati e adottati al servizio di un obiettivo più elevato. Quindi, con una comprensione adeguatamente condizionata, alcune apparenti violazioni potrebbero non essere vere e proprie violazioni dello "spirito" o del "corpus di principi nel suo insieme".

I principi SOLID in particolare, oltre a richiedere molte sfumature, sono in definitiva subordinati all'obiettivo di "fornire software funzionante e gestibile". Pertanto, aderire a un particolare principio SOLID è autolesionista e contraddittorio quando lo fa è in conflitto con gli obiettivi di SOLID. E qui, noto spesso che offrire la manutenibilità di briscole .

Quindi, per quanto riguarda la D in SOLID ? Bene, contribuisce ad aumentare la manutenibilità rendendo il tuo modulo riutilizzabile relativamente agnostico al suo contesto. E possiamo definire il "modulo riutilizzabile" come "una raccolta di codice che prevedi di utilizzare in un altro contesto distinto". E questo vale per singole funzioni, classi, serie di classi e programmi.

E sì, cambiare l'implementazione del logger probabilmente mette il tuo modulo in un "altro contesto distinto".

Quindi, lasciami offrire i miei due grandi avvertimenti :

In primo luogo: tracciare le linee attorno ai blocchi di codice che costituiscono "un modulo riutilizzabile" è una questione di giudizio professionale. E il tuo giudizio è necessariamente limitato alla tua esperienza.

Se non si dispone attualmente prevede di utilizzare un modulo in un altro contesto, è probabilmente OK per esso dipenda impotente su di esso. L'avvertimento al avvertimento: I vostri piani sono probabilmente sbagliato - ma questo è anche OK. Più a lungo scrivi un modulo dopo l'altro, più sempre più intuitivo e preciso sarà il tuo senso se "un giorno ne avrò bisogno di nuovo". Ma probabilmente non sarai mai in grado di dire in modo retrospettivo: "Ho modulare e disaccoppiato tutto nella massima misura possibile, ma senza eccessi ".

Se ti senti in colpa per i tuoi errori di giudizio, vai alla confessione e vai avanti ...

Secondo: invertire il controllo non equivale a iniettare dipendenze .

Ciò è particolarmente vero quando si inizia a iniettare dipendenze e nausea . L'iniezione di dipendenza è una tattica utile per la strategia IoC globale. Ma direi che DI è di minore efficacia rispetto ad altre tattiche - come usare interfacce e adattatori - singoli punti di esposizione al contesto dall'interno del modulo.

E concentriamoci davvero su questo per un secondo. Perché, anche se si inietta un Logger annuncio nauseam , è necessario scrivere codice Loggersull'interfaccia. Non è possibile iniziare a utilizzare un nuovo Loggerdi un fornitore diverso che accetta parametri in un ordine diverso. Tale capacità deriva dalla codifica, all'interno del modulo, rispetto a un'interfaccia esistente all'interno del modulo e che contiene un singolo sottomodulo (Adapter) per gestire la dipendenza.

E se stai codificando un adattatore, che Loggersia iniettato in quell'adattatore o scoperto dall'adattatore è generalmente dannatamente insignificante rispetto all'obiettivo generale di manutenibilità. E, soprattutto, se si dispone di un adattatore a livello di modulo, è probabilmente assurdo iniettarlo in qualsiasi cosa. È scritto per il modulo.

tl; dr - Smetti di preoccuparti dei principi senza considerare il motivo per cui stai usando i principi. E, più praticamente, crea un Adaptermodulo per ogni modulo. Usa il tuo giudizio quando decidi dove disegnare i confini del "modulo". Dall'interno di ciascun modulo, andare avanti e fare riferimento direttamente a Adapter. E sicuramente, iniettare il vero logger nel Adapter- ma non in ogni piccola cosa che potrebbe averne bisogno.


4
Amico ... Avrei dato una risposta più breve, ma non avevo tempo.
svidgen,

2
+1 per l'utilizzo di un adattatore. È necessario isolare le dipendenze dai componenti di terze parti per consentire loro di essere sostituiti ove possibile. La registrazione è un obiettivo facile per questo - esistono molte implementazioni di registrazione e per lo più hanno API simili, quindi una semplice implementazione dell'adattatore può consentire di modificarle molto facilmente. E per le persone che dicono che non cambierai mai il tuo provider di log: ho dovuto farlo e questo ha causato un vero dolore perché non stavo usando un adattatore.
Jules,

"I principi SOLID in particolare, oltre a richiedere molte sfumature, sono in definitiva subordinati all'obiettivo di" fornire software funzionante e mantenibile "." "- Questa è una delle migliori dichiarazioni che abbia mai visto. Come programmatore lievemente OCD, ho avuto la mia parte di lotte tra idealismo e produttività.
DVK,

Ogni volta che vedo un +1 o un commento su una vecchia risposta, rileggo di nuovo la mia risposta e scopro, ancora una volta, che sono uno scrittore terribilmente disorganizzato e poco chiaro ... Apprezzo comunque il commento, @DVK.
svidgen,

Gli adattatori sono salvavita, non costano molto e rendono la vita molto più semplice, specialmente quando si desidera applicare SOLID. Il test è un gioco da ragazzi con loro.
Alan,

8

L'idea che il logging debba sempre essere implementato come singleton è una di quelle bugie a cui è stato detto così spesso che ha guadagnato trazione.

Fino a quando i moderni sistemi operativi sono stati informati, è stato riconosciuto che potresti voler accedere a più posti a seconda della natura dell'output .

I progettisti di sistemi dovrebbero costantemente mettere in discussione l'efficacia delle soluzioni passate prima di includerle alla cieca in nuove. Se non svolgono tale diligenza, non stanno facendo il loro lavoro.


2
Qual è la tua soluzione proposta, allora? Inietta un ILogger in ogni classe che scrivi? Che dire dell'utilizzo di un motivo Decoratore?
Robert Harvey,

4
Non rispondo davvero alla mia domanda adesso, vero? Ho indicato gli schemi semplicemente come esempi ... Non devono essere quelli se hai in mente qualcosa di meglio.
Robert Harvey,

8
Non capisco davvero questa risposta, in termini di proposte concrete
Brian Agnew,

3
@RobbieDee - Quindi stai dicendo che la registrazione dovrebbe essere implementata nel modo più contorto e scomodo dalla "off-chance" che potremmo voler accedere a più luoghi? Anche se si verificasse un cambiamento del genere, pensi davvero che aggiungere quella funzionalità all'istanza di Logger esistente sarà più lavoro di tutto lo sforzo di passare quel Logger tra le classi e cambiare le interfacce quando decidi di volere un Logger o meno le dozzine di progetti in cui la registrazione di più luoghi non avverrà mai?
Dunk,

2
Ri: "Potresti voler accedere a più posti a seconda della natura dell'output": Sicuro, ma il modo migliore per gestirlo è nel framework di registrazione , piuttosto che provare a iniettare più dipendenze di registrazione separate. (I framework di registrazione comuni supportano già questo.)
ruakh

4

La registrazione è davvero un caso speciale.

@Telastyn scrive:

Non hai mai intenzione di cambiare la tua libreria di registrazione, o destinazione, filtro, formattazione o ...?

Se si prevede che potrebbe essere necessario modificare la libreria di registrazione, è necessario utilizzare una facciata; cioè SLF4J se sei nel mondo Java.

Per il resto, una libreria di registrazione decente si occupa di cambiare dove va la registrazione, quali eventi vengono filtrati, come gli eventi di registro vengono formattati usando i file di configurazione del logger e (se necessario) le classi di plugin personalizzate. Esistono numerose alternative standard.

In breve, questi sono problemi risolti ... per la registrazione ... e quindi non è necessario utilizzare Dependency Injection per risolverli.

L'unico caso in cui DI potrebbe essere utile (rispetto agli approcci di registrazione standard) è se si desidera sottoporre la registrazione dell'applicazione a test di unità. Tuttavia, sospetto che la maggior parte degli sviluppatori direbbe che la registrazione non fa parte della funzionalità di una classe e non è qualcosa che deve essere testato.

@Telastyn scrive:

E otterrai quindi l'argomento secondo cui il logger stesso gestirà la modifica. "Oh, se il target / il filtro / la formattazione / la strategia cambiano, cambieremo semplicemente la configurazione!" Questa è spazzatura. Non solo hai un oggetto God che gestisce tutte queste cose, stai scrivendo il tuo codice in XML (o simile) in cui non ottieni analisi statiche, non ricevi errori di compilazione e non ottengo davvero test unitari efficaci.

Temo che sia un ripost molto teorico. In pratica, alla maggior parte degli sviluppatori e degli integratori di sistema piace il fatto che sia possibile configurare la registrazione tramite un file di configurazione. E gli piace il fatto che non si prevede che testeranno l'unità la registrazione di un modulo.

Certo, se si riempiono le configurazioni di registrazione, è possibile che si verifichino problemi, ma si manifesteranno come l'applicazione non riuscita durante l'avvio o una registrazione troppo / troppo scarsa. 1) Questi problemi possono essere facilmente risolti correggendo l'errore nel file di configurazione. 2) L'alternativa è un ciclo completo di compilazione / analisi / test / distribuzione ogni volta che si modifica i livelli di registrazione. Non è accettabile


3

e no !

Sì: penso che sia ragionevole che sottosistemi diversi (o livelli o librerie semantici o altre nozioni di raggruppamento modulare) accettino ciascuno (lo stesso o) logger potenzialmente diverso durante la loro inizializzazione piuttosto che tutti i sottosistemi che fanno affidamento sullo stesso singleton condiviso comune .

Tuttavia,

No: è allo stesso tempo irragionevole parametrizzare la registrazione in ogni piccolo oggetto (per metodo di costruzione o istanza). Per evitare un gonfiamento inutile e inutile, le entità più piccole dovrebbero usare il logger singleton del loro contesto racchiuso.


Questo è uno dei tanti motivi per pensare alla modularità nei livelli: i metodi sono raggruppati in classi, mentre le classi sono raggruppate in sottosistemi e / o livelli semantici. Questi fasci più grandi sono preziosi strumenti di astrazione; dovremmo dare considerazioni diverse all'interno dei confini modulari rispetto a quando li attraversiamo.


3

Innanzitutto inizia con una forte cache singleton, le prossime cose che vedi sono forti singleton per il livello di database che introducono stato globale, API non descrittive di classes e codice non verificabile.

Se decidi di non avere un singleton per un database, probabilmente non è una buona idea avere un singleton per una cache, dopo tutto, rappresentano un concetto molto simile, l'archiviazione dei dati, usando solo meccanismi diversi.

L'uso di un singleton in una classe trasforma una classe che ha una quantità specifica di dipendenze in una classe che ne ha, teoricamente , un numero infinito, perché non si sa mai cosa è realmente nascosto dietro il metodo statico.

Nell'ultimo decennio ho trascorso la programmazione, c'è stato solo un caso in cui ho assistito ad uno sforzo per cambiare la logica di registrazione (che è stata poi scritta come singleton). Quindi, anche se amo le iniezioni di dipendenza, il disboscamento non è davvero una preoccupazione così grande. La cache, d'altra parte, farei sicuramente sempre una dipendenza.


Sì, la registrazione cambia raramente e di solito non deve essere un modulo scambiabile. Tuttavia, una volta ho provato a testare un'unità di una classe helper di registrazione, che aveva una dipendenza statica dal sistema di registrazione. Ho deciso che il meccanismo più semplice per renderlo testabile sarebbe quello di eseguire la classe sotto test in un processo separato, configurare il suo logger per scrivere su STDOUT e analizzare quell'output nel mio caso di test ಠ_ಠ Ho avuto un'esperienza simile con gli orologi in cui tu ' ovviamente non avrei mai voluto altro che il tempo reale, giusto? Tranne quando si testano i casi limite di fuso orario / ora legale, ovviamente ...
amon

@amon: gli orologi sono come il log in che esiste già un altro meccanismo che ha lo stesso scopo di DI, vale a dire Joda-Time e le sue numerose porte. (Non che ci sia qualcosa di sbagliato nell'utilizzare DI invece; ma è più semplice usare Joda-Time direttamente che provare a scrivere un adattatore iniettabile personalizzato, e non ho mai visto nessuno pentirsi di averlo fatto.)
ruakh

@amon "Ho avuto un'esperienza simile con gli orologi in cui ovviamente non avresti mai voluto altro che il tempo reale, giusto? Tranne quando provavi i casi di fuso orario / DST, ovviamente ..." - o quando ti rendi conto che un bug ha corrotto il database e l'unica speranza di recuperarlo è analizzare il registro eventi e riprodurlo a partire dall'ultimo backup ... ma all'improvviso è necessario che tutto il codice funzioni in base alla data / ora della voce di registro corrente anziché a quella corrente tempo.
Jules,

3

Sì e No, ma principalmente No

Suppongo che la maggior parte della conversazione si basi sull'istanza statica vs iniettata. Nessuno propone che la registrazione rompa l'SRP che presumo? Parliamo principalmente del "principio di inversione di dipendenza". Tbh concordo principalmente con la non risposta di Telastyn.

Quando va bene usare la statica? Perché chiaramente a volte va bene. Le risposte Sì indicano i vantaggi dell'astrazione e le risposte "No" indicano che sono qualcosa per cui paghi. Uno dei motivi per cui il tuo lavoro è difficile è che non esiste una risposta che puoi scrivere e applicare a tutte le situazioni.

Prendere: Convert.ToInt32("1")

Preferisco questo a:

private readonly IConverter _converter;

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

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

Perché? Sto accettando che avrò bisogno di refactoring del codice se ho bisogno della flessibilità per scambiare il codice di conversione. Sto accettando che non sarò in grado di deridere questo. Credo che la semplicità e la tenesseness valgano questo commercio.

Osservando l'altra estremità dello spettro, se IConverterfosse un SqlConnection, sarei abbastanza inorridito nel vederlo come una chiamata statica. I motivi per cui sono falliti ovvi. Vorrei sottolineare che a SQLConnectionpuò essere abbastanza "trasversale" in un applciation, quindi non avrei usato quelle parole esatte.

La registrazione è più simile a un SQLConnectiono Convert.ToInt32? Direi più come 'SQLConnection`.

Dovresti prendere in giro la registrazione . Parla con il mondo esterno. Quando scrivo un metodo usando Convert.ToIn32, lo sto usando come uno strumento per calcolare qualche altro output testabile separatamente della classe. Non è necessario verificare che sia Convertstato chiamato correttamente quando si verifica che "1" + "2" == "3". La registrazione è diversa, è un output completamente indipendente della classe. Suppongo sia un risultato che ha valore per te, il team di supporto e il business. La tua classe non funziona se la registrazione non è corretta, quindi i test unitari non dovrebbero superare. Dovresti testare ciò che registra la tua classe. Penso che questo sia l'argomento killer, potrei davvero fermarmi qui.

Penso anche che sia qualcosa che molto probabilmente cambierà. Una buona registrazione non solo stampa stringhe, è una visione di ciò che l'applicazione sta facendo (sono un grande fan della registrazione basata su eventi). Ho visto la registrazione di base trasformarsi in UI di reporting piuttosto elaborate. Ovviamente è molto più facile andare in questa direzione se la tua registrazione sembra _logger.Log(new ApplicationStartingEvent())e meno simile Logger.Log("Application has started"). Si potrebbe sostenere che questo sta creando inventario per un futuro che potrebbe non accadere mai, questa è una richiesta di giudizio e penso che ne valga la pena.

In effetti, in un mio progetto personale, ho creato un'interfaccia utente senza registrazione puramente usando il _loggerper capire cosa stava facendo l'applicazione. Ciò significava che non dovevo scrivere codice per capire cosa stesse facendo l'applicazione e alla fine ho ottenuto un registro solido. Mi sento come se il mio atteggiamento nei confronti del disboscamento fosse semplice e immutabile, quell'idea non mi sarebbe venuta in mente.

Quindi concordo con Telastyn per il caso della registrazione.


È così che accedo per caso . Vorrei collegarmi a un articolo o qualcosa del genere, ma non riesco a trovarne uno. Se ti trovi nel mondo .NET e cerchi la registrazione degli eventi, troverai Semantic Logging Application Block. Non usarlo, come la maggior parte del codice creato dal team "pattern and practice" di MS, ironicamente, è un antipattern.
Nathan Cooper,

3

In primo luogo le preoccupazioni trasversali non sono elementi costitutivi importanti e non dovrebbero essere trattate come dipendenze in un sistema. Un sistema dovrebbe funzionare se, ad esempio, Logger non è inizializzato o la cache non funziona. Come renderai il sistema meno accoppiato e coeso? Ecco dove SOLID entra in scena nella progettazione del sistema OO.

Mantenere l'oggetto come singleton non ha nulla a che fare con SOLID. Questo è il tuo ciclo di vita dell'oggetto per quanto tempo vuoi che l'oggetto viva nella memoria.

Una classe che necessita di una dipendenza per l'inizializzazione non dovrebbe sapere se l'istanza della classe fornita è singola o temporanea. Ma tldr; se stai scrivendo Logger.Instance.Log () in ogni metodo o classe, allora è un codice problematico (odore di codice / accoppiamento duro) davvero disordinato. Questo è il momento in cui le persone iniziano ad abusare di SOLID. E altri sviluppatori come OP iniziano a fare domande autentiche come questa.


2

Ho risolto questo problema usando una combinazione di ereditarietà e tratti (chiamati anche mixin in alcune lingue). I tratti sono super utili per risolvere questo tipo di preoccupazione trasversale. Di solito è una caratteristica della lingua, quindi penso che la vera risposta sia che dipende dalle caratteristiche della lingua.


Interessante. Non ho mai svolto alcun lavoro significativo utilizzando un linguaggio che supporti i tratti, ma ho preso in considerazione l'uso di tali linguaggi per alcuni progetti futuri, quindi mi sarebbe utile se puoi approfondire questo, e mostrare come i tratti risolvono il problema.
Jules,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.