Come realizzare "Dillo, non chiedere" in un'architettura di cipolla per l'analisi dei dati

2

Attualmente sto pensando a come implementare un software che ho scritto alcuni anni fa con un'architettura pulita / esagonale / a cipolla. Questo non sarà un "Grand Redesign from Heaven", dal momento che non sono più coinvolto nel progetto, ma piuttosto mi piacerebbe imparare cosa avrei potuto fare meglio.

Una cosa che ho problemi a realizzare per casi d'uso specifici è il "Dillo, non chiedere" principio ( TDA ). Senza entrare troppo nei dettagli del dominio del problema, vorrei dare una breve descrizione dei principali casi d'uso

Locali base:

  • I dati sono organizzati in partite (abbiamo analizzato uno sport di squadra)
  • Ogni partita ha un numero di giocatori ciascuno per la casa e il gruppo di visitatori
  • C'è una serie di azioni per ogni partita (in pratica i giocatori toccano la palla)
    • Ogni azione è associata a un giocatore
    • Per motivi di semplicità, ho omesso set all'interno della partita e sostituzioni di giocatori e simili

Utilizza i casi per la corrispondenza

  • Aggiungi home player
  • Aggiungi lettore visitatore
  • Aggiungi azione per casa / visitatore e numero di riferimento

(di nuovo, c'è molto di più, ma penso che sarà sufficiente per descrivere il mio problema)

L'analisi dei dati all'interno delle partite (anche su più corrispondenze, ma - semplicità) è centrale per l'applicazione. All'interno dell'architettura posizionerei le analisi sul secondo anello, poiché non sono entità dell'applicazione, ma forniscono comunque casi d'uso centrali. Le analisi si basano molto sul filtraggio e sul successivo conteggio delle azioni all'interno della corrispondenza.

  • Filtro per il giocatore
  • Filtraggio con altre azioni (ad esempio, prendi azione A se si verifica dopo l'azione R , ma non dopo l'azione D ; prendi solo azione A dopo un'azione buona o molto buona R ;. ..)
  • Filtro per qualità
  • Calcoli basati sulle qualità delle azioni rimanenti
  • e così via

In ogni caso, solo chiedendo all'oggetto della partita che i suoi contatti operassero su di loro sarebbe una violazione del TDA. E dal momento che la partita contiene la logica del business, ritengo che dovrei rispettare TDA. D'altra parte, non vedo un modo per aggiungere analisi a una corrispondenza e mantenere comunque le definizioni delle analisi sul secondo squillo.

Come posso eseguire analisi delle azioni all'interno della partita, ma aderire ancora al TDA? O non dovrei comunque operare su una partita per le analisi, ma ottenere direttamente le azioni da un repository?

var contacts = contactsRepository.GetContactsForMatch(match);

Sebbene ciò risolva il problema per le analisi, non lo farebbe per salvare i contatti per una corrispondenza, e il salvataggio diretto dalla rispettiva classe violerebbe certamente l'SRP e non è nel senso dei paradigmi dell'architettura.

    
posta Paul Kertscher 15.12.2017 - 11:50
fonte

1 risposta

1

Ci sono molti punti che mi vengono in mente, anche se alcuni potrebbero non essere applicabili, dal momento che non realizzo appieno le tue specifiche.

Prima di tutto, per quanto ne so, i casi d'uso sono intrinsecamente coordinatori. Non svolgono alcun lavoro eccetto il coordinamento del flusso degli oggetti del dominio :

These use cases orchestrate the flow of data to and from the entities, and direct those entities to use their enterprise wide business rules to achieve the goals of the use case.

Mi rendo conto che questo può essere interpretato come ottenere alcuni dati con getter di alcune entità e implementare qualche logica proprio nel codice del caso d'uso, ma penso che non sia quello che intendeva Robert Martin. Odora solo con un modello di dominio anemico.

Quindi è qui che passo al secondo punto. La nozione di TDA credo sia indotta dal fatto che non vuoi che il tuo modello di dominio sia anemico. Sono sicuro che sei consapevole del fatto che OOP riguarda la combinazione di dati e comportamenti, in modo che gli oggetti non espongano i dati, fornendo invece ai loro clienti un comportamento.

In terzo luogo, come potrei ottenerlo. Vorrei utilizzare CQS . Avrei due modelli separati: uno che sta mutando il suo stato e un altro che contiene la logica di calcolo.

In quarto luogo, come questo potrebbe essere implementato. Se non hai tonnellate di dati su cui operare, propendo di usare i decoratori. Come effetto collaterale, devono solo avere un accesso alle entità decorate. Ma tutta la tua logica sarebbe contenuta nel tuo dominio puro, non in un caso d'uso. Ecco come potrebbe essere:

new Filtered(
    playersFromDBTable(),
    function (Player $player) {
        return come_condition_result($player);
    }
);

E se hai molti dati, utilizzerei i repository per questo scopo - ancora, repository read-side .

In quinto luogo, se devi avere una regola aziendale, utilizzerei il modello di lettura (calcolo) che controlla che alcune condizioni siano vere, e se lo sono, invoco un modello di scrittura: aggiungi un giocatore o prendere qualche altra azione.

    
risposta data 15.12.2017 - 12:54
fonte

Leggi altre domande sui tag