Il mio livello di mediatore è un modo ragionevole per gestire questo scenario utilizzando il principio di responsabilità singola?

4

Non sono sicuro di come iniziare a spiegare la mia domanda, ma qui va.

Abbiamo appena terminato un'applicazione MVC che colpisce 2 servizi WCF. Ma c'è stato un po 'di disaccordo tra coloro che hanno lavorato al progetto e alcuni che non hanno usato il design. Quello che abbiamo sono due servizi WCF, uno su ciascun sito (dati specifici del sito) e un altro presso la sede centrale (dati condivisi / comuni tra tutti i siti). Normalmente avremmo due app, una per il sito e un'altra per la sede centrale. In questo caso ho deciso da un punto di vista di UX che sarebbe stato meglio averlo come un'app dal punto di vista dell'utente in modo che non avrebbero bisogno di conoscere due URL. Fondamentalmente, l'utente non sa se sta colpendo il sito o la sede centrale.

Ora arriva la decisione progettuale che ha causato i disaccordi. L'app MVC ha controller che devono raggiungere un servizio wcf del sito o un servizio WCF della sede centrale. Pertanto, per evitare che i controller dovessero essere a conoscenza dei due livelli di comunicazione WCF e convertire i risultati WCF in un modello utilizzabile dai controller, ho creato un livello tra i controller e i proxy WCF. Che accetta una richiesta da un controller, quindi chiama il sito appropriato o la chiamata proxy WCF centrale, quindi, se necessario, converte il risultato WCF in un modello che il controller può utilizzare.

Questo strato, ho chiamato un mediatore, ma dopo molte discussioni, sono dell'opinione che non è la descrizione corretta per questo. Ad ogni modo, la ragione di questo livello è quando si cerca di attenersi ai principi orientati agli oggetti di SOILD, in particolare il Principio di Responsabilità Unica. La responsabilità del controller è gestire le richieste dei client e restituire una vista / risultato. Non dovrebbe essere necessario conoscere o gestire un proxy WCF e convertirne il risultato. (Potrebbe andare direttamente a un database invece di una chiamata WCF ma il controller non dovrebbe essere responsabile o nemmeno a conoscenza di ciò perché è responsabile della vista) Lo stesso vale per il proxy WCF, non dovrebbe sapere cosa sta consumando il suo risultato e che il contratto di dati WCF deve essere convertito in un modello specifico per ciascun controllore. Il livello intermedio intermedio è ciò che decide quale servizio WCF e quale metodo chiamare, quindi tramite un metodo di estensione o un gestore specifico converte il risultato in un modello che il controller può utilizzare. (a volte possono essere necessarie diverse chiamate WCF per creare il modello).

Controller1 -> Mediator -> HeadOfficeWCFProxy
Controller2 -> Mediator -> SiteWCFProxy
  • Quindi il controller richiede dati (non sapendo da dove proviene)
  • Il mediatore converte e passa la richiesta al / ai proxy / i WCF appropriato
  • I proxy WCF effettuano le chiamate attraverso il filo e restituiscono i risultati.
  • Il mediatore converte quindi i risultati in un modello (se necessario) tramite un metodo di estensione e lo restituisce al controllore.
  • Il controller esegue il rendering della vista utilizzando detto modello.

Ora quello che ho descritto qui era solo sul lato MVC. Ho una configurazione simile sul lato del servizio WCF ma i benefici dei mediatori sono più chiari.

Nel servizio WCF della sede centrale

WCFListener -> Mediator -> DataLayer (LinqToSQL)
                        -> SiteSyncHandler (sends change to all sites asyncronously)
                        -> ThirdPartyContentManagementHandler (via web service)

Ora gli sviluppatori che hanno lavorato al progetto, come la separazione delle preoccupazioni, dato che è molto chiaro dove tutto appartiene e mantiene il codice al minimo in ogni livello. Ma il lato negativo nell'app MVC è per molte delle chiamate che il mediatore fa semplicemente una singola chiamata WCF e non ha nemmeno bisogno di convertire il risultato (il più delle volte il contratto dati va bene per l'uso come modello) risultante in una discreta quantità di un codice di piastra di caldaia metodo di linea. Il mediatore in realtà non aggiunge molto in questo scenario se non per mantenere le cose coerenti tra i controller. Alcuni sviluppatori che non hanno lavorato al progetto, insistono sul fatto che non vi è alcuna necessità per il livello Mediator e che potrebbe essere gestito interamente dai controllori stessi. Il che significa mantenere il proxy WCF appropriato in ogni controller. Questo nella mia mente viola il principio della responsabilità unica. A loro sostengono che SOLID è più come un insieme di linee guida, e non per essere seguito ciecamente. Che mentre io sono d'accordo con questa affermazione, è anche da non ignorare ciecamente.

Ho ammesso che il termine mediatore non è proprio appropriato (forse regista o staffetta), ma penso ancora che il progetto di base sia valido e lo userei di nuovo. Lo stesso si può dire per coloro che hanno lavorato al progetto. Mi piacerebbe sapere cosa pensano gli altri. C'è una soluzione migliore o ho "complicato". (Ancora non sono d'accordo che è complicato, è un concetto molto semplice e di facile manutenzione)

    
posta John Petrak 27.07.2012 - 04:51
fonte

5 risposte

3
The mediator doesn't really add much in that scenario 
except to keep things consistent across controllers. 

Bene, in realtà lo fa.

Mantenere le cose coerenti è, a mio parere, di per sé un enorme vantaggio che vale la pena.

I benefici aggiunti che vedo sono i mediatori:

  • ti consente di aggiungere altri siti
  • fornisce un punto comodo per aggiungere il bilanciamento del carico
  • ti consente di cambiare il metodo di comunicazione / framework
  • ... (un bel po 'di più)

E tutto senza cambiare una sola riga di codice al di fuori dei mediatori!

Fondamentalmente significa che la tua app è meglio modulare, e non ho ancora incontrato situazioni in cui ciò non fosse vantaggioso, anche se le cose che isola il tuo codice dell'app non cambiano mai. Semplicemente rende tutte le altre cose meno complicate semplicemente perché impostare il provider non è più un problema.

Quindi attenersi alle pistole SRP. La convenienza non è quasi mai un buon consulente quando si tratta di costruire sistemi maintable.

Una presentazione interessante sui semplici rispetto al complesso e su come confondiamo la semplicità per semplicità: link È stato un "ah sì, finalmente qualcuno che mette ciò che ho pensato / sentito riguardo a questo argomento in parole" esperienza.

    
risposta data 27.07.2012 - 12:53
fonte
2

Sembra ben pensato. Una cosa che gli sviluppatori web spesso non ottengono è, che i server (o il servizio WCF nel tuo caso) e i client (applicazione web, applicazione mobile o qualsiasi altra cosa) sono due cose separate e NON devono essere confusi. Trovi molte delle cosiddette implementazioni MVC che pensano che sia una buona idea posizionare controller e modelli sul server e avere la vista sul client. Si sentono tutti non proprio soddisfacenti.

Quando si tratta di sviluppo web, in qualche modo i bravi sviluppatori si fermano a pensare. In qualche modo non passano inosservati su un'architettura pulita e affidabile. Quindi, l'hai fatto bene. Punto. Lascia il contesto, chiamalo modulo "A" e modulo "B", qualunque cosa, e all'improvviso non sembra più discutibile.

Un modo pulito sarebbe avere uno stack MVC completo sul lato client. Ovviamente il tuo Controller non vuole sapere come esattamente i tuoi dati sono memorizzati. Questo è il lavoro modello, dopo tutto. Se il modello funziona con un database o un servizio web non importa, giusto? La tua idea con il mediatore in atto è buona, per ogni motivo che hai menzionato.

    
risposta data 27.07.2012 - 07:54
fonte
2

Spero di aver capito la situazione, ma di sicuro cerco di sintetizzarlo.

Hai un "master" separato (strumenti condivisi, dati e funzioni comuni) e (più?) servizi "satellite" (specifici del sito). La tua applicazione si connette a un satellite (a seconda del login, o dei registri del cliente nel sito?) E utilizza anche i servizi del master. È una decisione naturale che gli utenti non debbano essere consapevoli del fatto che usano entrambi all'interno della stessa applicazione - la domanda è come gestire questo scenario a livello di codice. Naturalmente, non conosco abbastanza la situazione attuale per rispondere a questa domanda, quindi mi limito a considerare che potresti trovare utile.

La tua singola applicazione "ospita" diversi componenti: unità con i loro dati, la logica aziendale e l'interfaccia utente. Insieme creano l'intera app: il menu o un dashboard li attiva e forse più componenti possono apparire su una singola schermata, forse da diversi servizi WCF. Alcuni di essi potrebbero "stare in giro" nell'app perché altri componenti li usino.

La domanda qui è: come vedi il ruolo dell'applicazione? Potrebbe essere

  • heavyweight, tipo "I MANAGE": esso nasconde la natura eterogenea del sistema , mostrando un singolo punto di accesso a qualsiasi servizio e inviando le richieste ai server appropriati (quindi chiamerei questo Dispatcher , ma non so se questa è una parola riservata nel mondo dei modelli)
  • leggero, tipo "I SERVE": sapendo che ci sono diversi server e i loro servizi potenzialmente indipendenti (in crescita, in cambiamento), non tenta di imitare un singolo livello di "copertura virtuale" sopra tutti , ma contengono più connessioni al server, da cui i componenti selezionano le proprie.

Senza conoscere troppo il tuo compito (e assolutamente zero conoscenze su WCF), il secondo approccio sembra più comodo. Penso che tu abbia ragione nel fatto che i componenti non dovrebbero possedere la loro connessione , perché molti di loro condividono lo stesso (capo o sito) - ma potrebbero riferirsi ad esso . Il tuo Mediatore (che ora sembra essere tutto-in-tutti) dovrebbe risolvere solo questi riferimenti per i componenti e anche fare le pulizie (stato, comunicazione, gestione degli errori, ecc.). Con questo approccio, avresti

  • mantenere il ruolo centrale del Mediatore (una posizione per la registrazione, la limitazione, il caching, ecc., nessuna soluzione diretta "veloce e sporca" nei componenti), ma
  • dimentica di gestire il livello di servizio globale per tutto il tempo in cui appaiono nuovi siti o qualsiasi servizio viene modificato (anche se hai bisogno di gestire i connettori a livello di app, dovresti inserirli in essi - ma questa volta la tua implementazione si adatta ai loro l'interfaccia).

I miei 2 centesimi.

Se questo suona bene, la transizione non è troppo complessa. Hai già il livello di gestione delle connessioni multiple, devi solo aprirlo e lasciare che i componenti accedano direttamente. Il lato oscuro è che devi spostare la parte centrale di gestione verso il basso, dal livello di copertura globale a livelli di copertura locali sopra ogni connessione.

Non dico questo perché penso che dovresti cambiare qualcosa , lo so fin troppo poco per avere una tale opinione [EDIT: non so nemmeno se questo approccio sia praticabile in WCF, Ho trascorso solo 3 settimane con C # nella mia vita, e l'ho trovato abbastanza rapido e maneggevole], ma penso che dovresti considerare entrambe le opzioni obiettivamente dai costi di implementazione e manutenzione richiesti, sia a breve che a lungo termine.

    
risposta data 27.07.2012 - 06:34
fonte
1

Sono favorevole al tuo argomento:

The controllers responsibility is to handle client requests and return a view/result. It should not need to know or maintain a WCF proxy and convert its result. (It could go directly to a database instead of a WCF call but the controller shouldn't be responsible or even aware of that because it is responsible for the view)

Quando utilizzi il pattern MVC, devi mantenere i controller skinny .

Inoltre, se metti i proxy client direttamente nel controller, perdi la possibilità di utilizzare iniezione di dipendenza ed eseguire test unitari automatizzati.

    
risposta data 29.07.2012 - 01:46
fonte
0

Quello che stai suggerendo è un servizio che sembra desiderabile estrapolare dai controller. Dovrebbe anche migliorare la capacità di testare i controller rimuovendo le chiamate concrete al servizio (la parte D di SOLID).

Forse invece di "Mediator" chiamalo "Service Bus" in quanto è più probabile che disegni un riconoscimento ed è un catherer.

    
risposta data 27.07.2012 - 05:54
fonte

Leggi altre domande sui tag