Critica del design / Revisione di un metodo God per un ViewModel

0

Per qualche motivo il design sottostante non mi sta bene, ma non riesco a trovare un ragionamento articolato sul perché. Vorrei il tuo aiuto nel formulare un caso contro (o per) esso.

Supponiamo che il design di FooViewModel sia tale:

// Some Observables
Observable_1: bool
Observable_2: string;
// --- //

// The method where all the "logic" is dumped
godMethod() {
    if (Singleton1.Status1 != DesiredStatus1) {
        set_state_1();
        return;
    }

    if (Singleton2.Status2 != DesiredStatus2) {
        set_state_2();
        return;
    }

    if (Observable_2.Value != "Desired String") {
        set_state_3();
        return;
    }

    set_state4();
}
// --- //


// In case of ANY external or internal event that may need the observables to change, just call the "godMethod"
externalEvent_Singleton1_Status1_Changed += () => {
    godMethod();
}

externalEvent_Singleton2_Status2_Changed += () => {
    godMethod();
}

Observable_2.Changed += () => {
    godMethod();
}
// --- //

// Actual values of the observables are defined here
set_state_1() {
    Observable_1 = false;
    Observable_2 = "Status 1 is undesirable :(";
}
set_state_2() {
    Observable_1 = false;
    Observable_2 = "Status 2 is undesirable :(";
}
set_state_3() {
    Observable_1 = false;
}
set_state_4() {
    Observable_1 = true;
}
// --- //

Immagino che questo progetto, invece di definire la logica per ogni osservabile, definisca invece la logica per ogni "stato".

  • Quali sono alcuni vantaggi / svantaggi di questo design?
  • Quali possono essere alcune insidie di questo design?
  • Può diventare un incubo di manutenzione?

My $ 0.02:

  • È molto difficile scoprire le dipendenze per gli osservabili semplicemente leggendo il codice:

    • Supponiamo di voler capire quando Observable_1 è impostato su false.
    • Il codice dovrebbe indicare:
      • Se Status1 è non appropriato, OPPURE
      • Se Status1 è appropriato E Se Status2 è non appropriato, OPPURE
      • Se Status1 è appropriato E Se Status2 è appropriato AND Observable_2 è not appropriato
    • Invece di limitarsi a definire (dichiarare?) che se uno qualsiasi di Status1, Status2 o Observable_2 è not appropriato.
    • Vedi quanto può diventare complicato?
  • Il numero di "stati" può esplodere esponenzialmente.

  • Chiamare il metodo di dio dopo ogni azione fa semplicemente capolino; ma non sono in grado di indicare alcun principio specifico che questo modello vìola.

  • Penso che questo possa essere il modo "procedurale" di fare le cose, ed è il mio cervello che si lamenta di OOP; ma ancora, perché questo è oggettivamente inferiore / superiore?

Infine, per aggiungere, gli argomenti che ho sentito per questo design sono:

  • Puoi guardare tutta la logica in un punto, che rende il codice più leggibile.
  • Ogni volta che si verifica un evento, chiama semplicemente godMethod. Questo, presumibilmente, rende il codice più facile da scrivere e mantenere.
posta Fa773N M0nK 26.05.2017 - 09:29
fonte

3 risposte

2

Quello che stai guardando è Correggi tutto design pattern. Lo scopo di godMethod è di ispezionare tutto sulla pagina e assicurarsi che state sia impostato su un valore corretto, dato lo stato del resto dei controlli / osservabili.

I vantaggi di questo approccio sono:

  • godMethod è idemopotent. Puoi chiamarlo un qualsiasi numero di volte e otterrai lo stesso risultato, quindi puoi chiamarlo quando non sei sicuro.
  • Devi solo scrivere un gestore e tutta la logica è in un unico posto.
  • L'approccio funziona bene quando i dati possono essere aggiornati da più di una fonte.

I contro sono:

  • Una chiamata a godMethod fa più lavoro che avrebbe bisogno di fare se il codice rispondesse a ciascun evento osservabile individualmente, quindi le prestazioni potrebbero non essere altrettanto buone. D'altra parte, al di sotto di una certa soglia, probabilmente non ha importanza.
  • La logica in godMethod può essere un po 'complicata da risolvere poiché devi guardare la pagina nel suo insieme e tenere conto di tutti gli stati possibili.

Non c'è niente di sbagliato nel tuo approccio al "metodo del dio", e in effetti penso sia meglio nella maggior parte dei casi.

Say you want to figure out when the Observable_1 is set false

Non capisco il problema. Se un pezzo di codice non interessa lo stato e vuole solo sapere se Observable_1 è falso, ha solo bisogno di leggere Observable_1 direttamente, ad es. var f = Observable_1; Cosa mi manca?

The number of "states" can explode exponentially.

Non penso che sia giusto. Se State è una funzione dello stato degli osservabili, il numero di valori possibili per State è esattamente lo stesso indipendentemente da di come ti avvicini a questo problema, a patto di non aggiungere o rimuovere osservabili.

L'unica cosa che potrebbe cambiare è la complessità ciclomatica della funzione che calcola State . Se deve guardare tutto, ovviamente sarà più complesso di qualcosa che guarda i bit in isolamento.

D'altra parte, se hai eliminato la funzione "dio", la complessità di aggregare di avere diverse funzioni il cui output combinato è necessario per determinare State è probabilmente ancora più alta, e molto più difficile da testare, poiché l'ordine e la ripetizione possono influire sui risultati e non esiste un modo semplice per forzare l'accoppiamento sequenziale a meno che tutti la logica è in un posto, come nel tuo approccio "metodo divino".

Smettila di pensarci troppo sopra; il tuo approccio va bene.

    
risposta data 30.05.2017 - 23:47
fonte
0

Sono d'accordo con te sul fatto che il design odori. Ma non riesco a trovare un design specifico che sarebbe meglio.

Quello che posso suggerire è isolare la logica di commutazione dal codice dell'effetto collaterale e scrivere una suite di test unitaria completa per la logica di commutazione. Ci sono alcuni vantaggi:

  1. Riduce la paura che provi dandoti confidenza nella correttezza del codice.
  2. I casi di test correttamente scritti offrono un modo più semplice per dedurre il comportamento del codice. Quindi capire "quando l'Observable_1 è impostato come falso" diventerà più facile.
  3. Con una corretta suite di test, sarà banale modificare l'implementazione interna se scoprirai il modo migliore per implementare il design.
  4. Separare correttamente la logica di commutazione e il codice degli effetti collaterali potrebbe fornire un design più pulito e migliorare la comprensione del comportamento interno.

Una cosa su cui starei molto attento è come creare API tra l'unità isolata che rappresenta il comportamento di commutazione e il resto del codice. Puoi isolare solo godMethod o includere anche gli eventi osservabili nel codice verificabile. Non posso dirti quale opzione è migliore con le informazioni che ci hai fornito.

    
risposta data 29.05.2017 - 08:18
fonte
0

Ci sono un certo numero di cose sbagliate che immagino tu stia pensando:

  • godMethod ha più uscite
  • godMethod cambia Observable2, che attiverà godMethod, potenziale loop infinito

La presenza di un possibile loop infinito mostra che la logica per lo stato richiesto non è stata pensata. Nessuno specificherà "quando ciò accade, l'app dovrebbe bloccarsi"

Allo stesso modo le uscite multiple suggeriscono che la logica non è ben definita.

Ovviamente il tuo codice qui è solo un esempio, quindi non conosciamo i requisiti reali. Idealmente saremmo in grado di distillarli in una singola funzione stateless con un singolo punto di uscita

state getNextState(status1, status2, observable2)
{
   ...???
   return requiredState
}

state
{
    status1;
    status2;
    observable1;
    observable2;
}

Dove il processo di distillazione mostra dove non viene utilizzata una variabile di input che può essere rimossa, che è possibile collegare in modo tale da evitare loop infiniti e attivarsi solo quando appropriato.

Ci si aspetterebbe anche di vedere vari metodi di test che controllano tutte le combinazioni di input producono l'output atteso.

Il prodotto finale potrebbe sembrare molto simile, ma sarebbe un milione di volte più sicuro che fosse sia corretto che ben pensato.

    
risposta data 30.05.2017 - 16:55
fonte

Leggi altre domande sui tag