È possibile mantenere il codice di registrazione completamente al di fuori della logica aziendale?


12

Con l'aiuto di AOP, posso rimuovere il codice di registrazione dalla mia logica aziendale. Ma penso che possa essere utilizzato solo per registrare cose semplici (ad es. Immissione / uscita del metodo di registrazione e valori dei parametri).

Tuttavia, cosa succede se devo registrare qualcosa nella mia logica aziendale? per esempio

public void SomeDomainMethod(string id)
{
   //Get user by Id
   User user = Users.Get(id);
   if (user == null)
   {
      Log.Warn("user is not existed");        //<----------------- Log A
      throw new InvalidOperationException("user is not existed");
   }

   //Step 1 
   while(true)
   {
       //do something
   }
   Log.Info("Step 1 is completed");            //<----------------- Log B

   //Step 2
   while(true)
   {
       //do something
   }
   Log.Info("Step 2 is completed");            //<----------------- Log C

}

Il metodo di esempio sopra potrebbe non essere abbastanza chiaro, quello che voglio mostrare qui è che il metodo dovrebbe essere trattato come la più piccola unità dal punto di vista del dominio. Non dovrebbe essere diviso in pezzi più piccoli.

È possibile spostare oltre il codice di registrazione 3 fuori dal metodo? Qual è la migliore pratica per tale situazione?


Sono abbastanza sicuro che i log "Step1" e "Step2" del tuo esempio debbano far parte di una traccia di controllo della logica aziendale e la prima di una registrazione tecnica. Vorrei prima ordinare questo ...
fino al

Risposte:


1

Sicuro!

Ma nella mia esperienza, ci sono due tipi generali di registrazione utile :

Tutti i registri: registri creati tramite le API di profilazione. Buono per identificare problemi di prestazioni e segnalare eccezioni. Molto rumoroso.

Registri eventi aziendali : registri richiamati nella logica aziendale. Qualunque cosa possa interessare all'azienda. Rumore minimo. Notevoli, logici, eventi "commerciali". Buono per auditing e KPI ...

Quindi, consiglio vivamente due cose. Innanzitutto, fai quello che fanno gli altri strumenti di monitoraggio, come New Relic, e usa l'API di profilazione .NET 1 . In secondo luogo, registra gli eventi aziendali logici nella tua logica aziendale . Tenere traccia di determinati eventi è una logica aziendale.

E normalmente non suggerirei AOP per nessuno dei due tipi di registrazione 2 . Nella mia esperienza, o vuoi tutto , il che significa che stai utilizzando un profiler o vuoi eventi logici / aziendali. E in quest'ultimo caso, penso che sia più semplice invocare il logger nella logica aziendale.


1. Ma seriamente, risparmia migliaia di ore nello sforzo e usa solo uno strumento di profiler esistente ...

2. Naturalmente, questo presuppone che tu condivida la mia opinione che un aspetto non sia un ottimo posto per nascondere le regole aziendali!


Sono abbastanza d'accordo sui "Registri eventi aziendali" e, proprio come le risposte degli altri, manterrò il codice registro nella logica aziendale. E per la parte "Tutto registra", preferisco usare la soluzione AOP poiché seguirà l'SRP e non inquinerà la mia logica aziendale. Comunque, darò un'occhiata prima all'API di profilazione.
Charlie,

10

Certo, puoi facilmente usare AOP per questo. Rifattorizzare semplicemente le parti

  • Ottieni utente per ID
  • passo 1
  • passo 2

in metodi separati (come avresti dovuto fare per rendere il tuo codice più pulito). Ora puoi facilmente configurare il tuo framework AOP per registrare le chiamate di metodo che preferisci ( come mostrato qui ). L'eccezione può essere registrata direttamente dal chiamante, non è necessario utilizzare AOP per uscire dalla logica aziendale.

Per la tua modifica:

Voglio mostrare qui che il metodo dovrebbe essere trattato come la più piccola unità dal punto di vista del dominio. Non dovrebbe essere diviso in pezzi più piccoli

Perché non dovrebbe? Se, in un "contesto di logica aziendale", si desidera registrare "qualcosa" che vale la pena registrare e se a questo "qualcosa" può essere assegnato un nome ragionevole, nella maggior parte dei casi ha senso trasformare il codice in un metodo su proprio. Se si desidera utilizzare AOP, è necessario strutturare il codice in un modo che probabilmente è necessario strutturare indipendentemente dal requisito di registrazione. Puoi interpretarlo come uno svantaggio di AOP, oppure puoi interpretarlo come un vantaggio, poiché ti dà un feedback in cui la struttura del tuo codice può essere migliorata.


È un peccato che il mio esempio non sia abbastanza chiaro. Quello che in realtà voglio mostrare nell'esempio è che il metodo è l'unità più piccola dal punto di vista del dominio che non dovrebbe essere divisa in pezzi più piccoli.
Charlie,

@ Charlie: l'esempio è perfettamente chiaro. Il tuo malinteso qui è probabilmente pensi che potrebbe essere una buona idea avere metodi più grandi di passaggi. E questo è IMHO sbagliato, non è una buona idea. Avere diversi passaggi che vale la pena registrare è un chiaro segno che questi passaggi dovrebbero avere un'astrazione, un nome a sé stante, quindi un metodo a sé stante.
Doc Brown,

@Charlie niente ti impedisce di fare 3 metodi privati ​​chiamati dalla tua unità o lavoro. In questo modo dall'esterno è rimasto lo stesso ma ora hai l'astrazione richiesta per la registrazione.
Rémi,

Questo approccio va bene se si desidera guidare la struttura del codice registrando le preoccupazioni. A volte, però, vuoi guidarlo con qualcos'altro.
John Wu,

@JohnWu: la struttura del codice dovrebbe riflettere le diverse preoccupazioni / fasi, indipendentemente dal requisito di registrazione. Questo è ciò che guida la struttura del codice qui. Una volta risolto questo problema, AOP può fare il logging, che è più un "effetto collaterale" nel dare al codice una struttura migliore. Quindi penso che non sia la preoccupazione di registrazione che guida la struttura del codice, è più che il requisito di utilizzare AOP per la registrazione rende più trasparente il fatto che al codice manchi qualche struttura che dovrebbe avere.
Doc Brown,

3

A meno che il materiale di registrazione non faccia parte dei requisiti aziendali, è meglio, come dici tu, tenerlo completamente fuori dal codice.

Ciò significa che davvero non vuoi registrare cose come "passaggio 1 completo". Anche se inizialmente potrebbe essere utile per il debug, in produzione genererà gigabyte di rifiuti che non vedrai mai.

Se Step1Complete è una sorta di evento aziendale che richiede ulteriori azioni, può essere esposto attraverso un buon evento vecchio stile senza forzarti a iniettare un ILogger o simile nella tua classe


Questo è quello che stavo pensando. Non riesco a trovare un caso ragionevole per accedere a un dominio / modello di business POCO. La registrazione è qualcosa che tende a integrarsi naturalmente al di fuori dei modelli di business principali, l'IMO.
jleach

2

Con l'aiuto di alcuni schemi comuni è possibile estrarre il codice di registrazione dalla logica aziendale. Tuttavia potresti non valerne la pena farlo

Ad esempio, usando l'ascoltatore (creandone uno manualmente o usando il bus degli eventi, ecc.), Il tuo codice sarà simile

public void SomeDomainMethod(string id)
{
   //Get user by Id
   User user = Users.Get(id);
   if (user == null)
   {
      listener.OnUserNotFound(userId);
      throw new InvalidOperationException("user is not existed");
   }

   //Step 1 
   while(true)
   {
       //do something
   }
   listener.OnStep1Finished(......);

   ...

}

Implementando la registrazione nel listener, la logica di registrazione non è più nella logica aziendale.

Tuttavia potresti scoprire che questo non è sempre realistico in quanto potresti non essere sempre in grado di definire un evento significativo della tua logica.

Un altro approccio è attraverso meccanismi come Dtrace in Solaris che ti consentono di iniettare nei processi in esecuzione (credo che ci sia modo di fare cose simili in C #?) In modo che le registrazioni di dati statistici e di registrazione possano essere definite in fase di esecuzione. Ci sono ancora altri inconvenienti.


Un problema che AOP sta cercando di risolvere è il problema del codice che diventa illeggibile del codice non aziendale (come le chiamate di registrazione) intrecciate con il "codice aziendale". Sostituire un "logger" con un "ascoltatore" non risolve questo problema, la leggibilità del codice non viene modificata,
Doc Brown

2

Un altro approccio è quello di separare la registrazione aziendale e la registrazione tecnica. Quindi possiamo chiamare la registrazione aziendale "Audit" e applicare un insieme specifico di regole di business come i termini di archiviazione e le regole di elaborazione come Business Activity Monitoring.

D'altra parte, la registrazione tecnica, o semplicemente "Registrazione", è un mezzo di ultima istanza per lasciare una traccia del problema tecnico. Dovrebbe essere asincrono, veloce, tollerante alla mancata persistenza del messaggio di registro. Inoltre, i messaggi di registro dovrebbero passare attraverso il minor numero di proxy possibile per essere vicini alla fonte del problema.

La logica di The Logging è abbastanza variabile ed è strettamente associata all'implementazione, quindi è davvero necessario separarla dal codice?

La logica dell'Audit dovrebbe essere considerata una logica di dominio e gestita di conseguenza.

Ad esempio, in Hexagonal Architecture potrebbero esserci porte di controllo insieme a porte Client, Storage e MQ (e, possibilmente, metriche e controllo). Sarebbe una porta secondaria, ovvero l'attività su questa porta è innescata dal core aziendale, piuttosto che da sistemi esterni.


Sono molto d'accordo con te sul fatto che esistono due tipi di registrazione. Ma la logica di The Logging non è abbastanza variabile ed è strettamente associata all'implementazione , intendi la registrazione tecnica qui? Per la registrazione tecnica, penso che sia usato per registrare i valori di entrata / uscita del metodo e dei parametri che è meglio sedersi al di fuori del metodo.
Charlie,

@Charlie Sì, per "The Logging" intendo la registrazione tecnica. La registrazione dei valori di entrata / uscita / parametro è sufficiente nel caso di funzioni pure. Quindi, o ovviamente, potresti usare un aspetto o una monade Logger. Ma le funzioni pure sono fantastiche in quanto sono testabili. Quindi, è probabile che i problemi, il logger debba tracciare, possano essere risolti durante lo sviluppo / debug. Con le funzioni impure, in cui la registrazione tecnica è più utile, si desidera registrare tutti i parametri / risultati delle chiamate con effetti collaterali, ogni eccezione.
iTollu

1

Modi per evitare la registrazione diretta in una classe o metodo:

  1. Genera un'eccezione ed esegui la registrazione in un blocco catch più in alto nella struttura delle chiamate. Se è necessario acquisire un livello di registro, è possibile generare un'eccezione personalizzata.

  2. Effettuare chiamate a metodi che sono già strumentati per la registrazione.


1
La registrazione è dove è stato dimostrato di essere un problema e ne vale la pena "riparare"?
whatsisname

1

È davvero necessario separare la registrazione dalla logica aziendale? La registrazione in corso è in corrispondenza della logica aziendale scritta e quindi ha senso essere nella stessa classe / funzione. Ancora più importante, facilita la leggibilità del codice.

Tuttavia, nel caso in cui si desideri davvero separare la registrazione dalla propria logica aziendale, è necessario considerare la possibilità di generare eccezioni personalizzate e di consegnarle per la registrazione.


0

No, non in c #

OP, la risposta alla tua domanda specifica è no, non in c #. Potrebbero esserci altri linguaggi AOP più nativi là fuori, ma tutti gli approcci ad AOP in c # che ho visto possono applicare solo comportamenti previsti nel contesto di un punto di unione , il che significa che deve esserci un flusso di controllo tra un blocco di codice e un altro. I comportamenti controllati non verranno eseguiti nel mezzo di un metodo, tranne ovviamente chiamando un altro metodo.

È possibile "prevedere" alcuni bit di registrazione

Detto questo, potresti estrarre alcune preoccupazioni legate alla registrazione, ma non alla scrittura del registro. Ad esempio, un punto di interruzione eseguito all'entrata in un metodo potrebbe impostare un contesto di registrazione e generare tutti i parametri di input, e all'uscita potrebbe catturare le eccezioni o salvare un registro nella memoria permanente, quel genere di cose.

La scrittura del registro non è comunque un aspetto

Vorrei aggiungere che la scrittura dei registri non è in realtà una preoccupazione trasversale, comunque. Almeno non la registrazione di debug. La mia prova per questo è che non è possibile scrivere un requisito trasversale che spieghi completamente cosa farebbe questo aspetto: è specifico per ogni singolo caso, perché lo scopo di scrivere il registro è riflettere ciò che sta succedendo con il la logica e la logica di ciascun metodo dovrebbero essere ragionevolmente uniche (vedi DRY ).

In altre parole, esiste una dipendenza logica inestricabile tra la scrittura dei registri e le cose di cui si sta scrivendo. Non puoi generalizzare.

Ma l'auditing è

Se si dispone di una sorta di requisito di registrazione funzionale (ad esempio la registrazione di controllo a supporto di un requisito di non ripudio ) alcuni sosterrebbero (e sarei d'accordo) che se ti ritrovi a dover eseguire queste scritture nel mezzo di un metodo, non hai strutturato il tuo codice in modo coerente con il pensiero orientato all'aspetto. In questo caso, è necessario estrarre il codice in metodi separati fino ad ottenere il livello di granularità necessario.

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.