Miglior approccio per il monitoraggio dello stato dipendente

3

Supponiamo di lavorare su un'applicazione di tracciamento del progetto. L'applicazione è un database supportato, server ospitato, applicazione web. In questa applicazione ci sono Progetti che hanno molte Attività che hanno molti Attività . Un compito ha due campi data un originalDueDate e un projectedDueDate .

Inoltre, ci sono campi dinamici nelle Attività e Progetti che indicano se Attività o Progetto è in ritardo sulla pianificazione in base alle date di scadenza previste delle attività secondarie e a varie altre variabili come il tempo di buffer residuo, ecc.

Ci sono un certo numero di cose che possono far cambiare projectedDueDate . Ad esempio, un dipendente che lavora al progetto può (tramite una richiesta del server) inserire un ritardo di spedizione. In alternativa, un sito può (tramite una richiesta del server) entrare in una chiusura inaspettata.

Quando si verifica una di queste cose, non devo solo aggiornare il projectedDueDate della attività ma anche attivare il corrispondente progetto e Attività da aggiornare.

Qual è il modo migliore per farlo?

Ho pensato al pattern observer ma non conservo una singola copia di tutti questi oggetti in memoria. Quando arriva una richiesta, interrogo il Task in dal database, a quel punto non è associata alcuna Attività in memoria che sarebbe un listener. Potrei rimuovere la possibilità di eseguire query per Attività e forzare l'applicazione a eseguire query prima da Progetto , quindi da Attività (nel contesto di Progetto ), quindi per attività (nel contesto di Attività ) aggiungendo le relazioni dell'osservatore ad ogni passaggio ma non sono sicuro che sia il modo migliore.

Potrei configurare un sistema per l'ascolto di un database così quando viene inviato un evento modificato Task Ho un gestore che richiede il Attività a quel punto.

Potrei semplicemente impostare una relazione a due vie tra Attività e Attività in modo che L'attività conosce l'attività del genitore e quando l'attività aggiorna il suo stato l' Attività acquisisce lo stato padre e aggiornamenti.

In questo momento sono bloccato considerando tutte le opzioni e mi sto chiedendo se un singolo approccio (non deve essere un approccio elencato) sta saltando agli altri come l'approccio migliore.

    
posta Pace 17.04.2014 - 17:26
fonte

3 risposte

1

Primo: mai male per la memorizzazione dei dati in due punti. Questo avviene sempre nelle banche dati "Reporting" / "Warehousing": è una de-normalizzazione ed è perfettamente accettabile. Finché hai spazio su disco per farlo, bene! Un join o una query in meno è molto meno carico.

Ora ... architettonicamente questo tipo di problema si verifica quando hai:

  1. An Aggregate (che è la combinazione di oggetti che non sono direttamente correlati ma necessari per la logica aziendale da applicare.

  2. Un evento (che è il tipo che accade nei modelli Publish and Subscribe) che deve essere trasmesso a uno o più abbonati.

Probabilmente hai # 2 - e piuttosto che hackerarlo nel database, prendi in considerazione alcune alternative. Sei sulla strada giusta con il pattern Observer.

Risoluzione:

  1. La cosa migliore che puoi fare è creare un nuovo oggetto. Caricare i dati dagli oggetti disparati attraverso qualsiasi meccanismo (i) tramite uno o più stabilimenti, quindi applicare la logica aziendale per calcolare la nuova data risultante e persistere nel database tramite il normale percorso che potrebbe comportare il ritorno dei convertitori alle entità standard o semplicemente Aggiornamenti SQL per modificare le date.

  2. Sembra che tu abbia bisogno di un evento - quando i dati devono essere condivisi tra due parti del sistema che normalmente non parlano tra loro durante il percorso di esecuzione corrente, gli eventi possono darti un modo pulito per comunicare. Questo è particolarmente vero nel tuo scenario quando più comandi (richieste) possono causare questo evento.

Nel n. 2, puoi seguire il percorso di "coerenza finale" ed elaborare l'evento in modo asincrono oppure puoi scegliere di gestirlo all'interno della stessa transazione. Senza saperne di più sulla tua architettura, è difficile dire come rendere questo meccanismo di eventi disponibile.

Ricorda che non hai bisogno di un abbonato per ogni attività possibile. Solo uno (per tipo di evento) che riceve le informazioni richieste, carica l'attività o il progetto (se necessario) e apporta le modifiche necessarie per mantenere il sistema sincronizzato.

Controlla DDD - anche se non lo usi, ti aiuta a pensare a problemi in diversi modi. (anche CQRS e Event Sourcing sono grandi argomenti)

    
risposta data 20.10.2014 - 02:36
fonte
0

Diamo un'occhiata al tuo pattern di osservatore: come hai affermato, gli oggetti parent potrebbero non essere presenti nella memoria al momento del cambiamento. Il modello di osservatore viene applicato solo alle situazioni in cui l'intera gerarchia dell'osservatore è presente nella memoria in modo che le modifiche possano essere riflesse direttamente. Considerare questa opzione significherebbe considerare quanto segue:

  • Che cosa significa per il server contenere l'intera gerarchia in memoria? Il server può gestirlo in tutte le circostanze?
  • Che cosa significa per lo spazio di archiviazione? Ogni modifica deve essere applicata immediatamente al database? È in attesa di eventi qualcosa che deve essere considerato a questo punto?

Tuttavia, c'è una risposta nella forma del modello di osservatore possibile, in cui è possibile ritardare tutti questi avvertimenti (fino a quando una ristrutturazione del progetto lo richiederà). Questo sarebbe un disegno che non ho mai visto usato nella pratica: creare una classe di osservatori in cui le istanze punterebbero ai genitori, invece di fare in modo che i genitori siano gli osservatori. Così, per esempio, possono contenere l'ID del record del database del genitore per il quale stanno osservando.

In questo modo, quando viene caricato un Task per esempio, puoi anche caricare tutti gli osservatori dal database che osservano quell'attività (da una tabella separata con record ciascuno che punta a 1 task e 1 osservatore, quindi ottenere tutti gli osservatori per compito ID). Ora non è necessario ottenere l'intera gerarchia, ma solo gli oggetti osservatore che osservano tale attività.

In questi oggetti osservatore avresti quindi l'ID del genitore come variabile, in modo che quando gli osservatori debbano aggiornarsi, potresti optare per una delle seguenti opzioni:

  • Carica i genitori che osservano in memoria, quindi li modifica e fa riflettere le modifiche nel database. Opzione utilizzata più probabilmente per: quando gli oggetti principali in questione sono necessari piuttosto presto ancora, per non doverli ricaricare nuovamente in memoria così presto.
  • Aggiorna direttamente gli oggetti parent nel database. Opzione utilizzata più probabilmente per: non è necessario ottenere dati dal database per eseguire l'operazione di aggiornamento.

Ma dal momento che la gerarchia degli osservatori può essere più profonda di un solo livello, è probabile che l'aggiornamento di un'attività si traduca in un aggiornamento dell'attività, che si traduce in un aggiornamento del progetto. Quindi per far fronte a questo, dovresti caricare gli osservatori che osservano il genitore del compito in questione. Per questo motivo, gli oggetti dell'osservatore dovrebbero quindi verificare se il genitore target ha osservatori, dopo che l'aggiornamento diretto è completo, per poter notificare i genitori del genitore. Non sono sicuro che sia consigliabile una struttura ricorsiva generalizzata per questo, dovresti scoprire da solo se la struttura del progetto / attività / compito potrebbe diventare più complessa in futuro, al fine di decidere in merito.

Anywho, spero che questo aiuti. Buona fortuna.

    
risposta data 21.07.2014 - 13:57
fonte
0

Come già detto, non penso che si applichi il pattern Observer, perché i tuoi progetti, attività e attività non sono oggetti. Non è possibile registrare un singolo record di progetto per ricevere notifiche dagli aggiornamenti dei record delle attività. I pattern Observer possono essere usati solo con oggetti in memoria.

È possibile inserire un trigger nella tabella Tasks per eseguire una stored procedure che aggiorna la relativa attività o progetto. Questo può funzionare ma devi implementare parte della tua logica aziendale in SQL. Probabilmente duplicherà il codice nel tuo server. Inoltre, quando si aggiornano più attività, si attiva la procedura tutte le volte che si hanno attività. Non è necessariamente performante.

Devi pensare che la dipendenza non sia necessariamente da un'attività all'attività, potresti voler spostare in blocco un'attività con tutte le sue attività.

Quello che suggerirei è di avvolgere tutti gli aggiornamenti di pianificazione nel modulo che chiamerò "Scheduler". The Sheduler fornirebbe una serie di servizi per aggiungere o aggiornare i tuoi compiti, attività o progetti. Tutti gli aggiornamenti passano attraverso tale Scheduler. Ogni volta che viene effettuata una richiesta, lo Scheduler aprirà una transazione sul proprio database, eseguirà gli aggiornamenti richiesti e aggiusterà qualsiasi altro dato dipendente in modo appropriato prima di impegnarsi.

Potrebbe sembrare un po 'poco elegante, gli aggiornamenti non sono automatici e devono essere scritti, ma sono abbastanza sicuro che il codice sarebbe più facile da comprendere e da eseguire il debug.

    
risposta data 21.08.2014 - 00:42
fonte

Leggi altre domande sui tag