Gli argomenti di supporto sono passati a funzioni che aiutano a saltare determinati controlli su una trappola?

0

Spesso, attraverso l'aspetto dell'importazione del mio framework, ho accesso a determinati dati che le funzioni che sto per utilizzare avranno sicuramente bisogno di se stessi.

Ho "resolver" che queste funzioni possono usare per ottenere i dati aggiuntivi di cui hanno bisogno ma sono operazioni molto pesanti e stavo pensando:

Dato che ho già accesso a quei dati esatti di cui la funzione avrebbe bisogno, perché non limitarti a passarli e non affidarti a questi risolutori heavy-lift per averlo per me?

Incontra "argomenti di supporto" - Posso semplicemente passarli a un array e all'interno della mia funzione, controlla se sono passati - altrimenti, chiedi ai resolver di darli (dato che ho bisogno dei dati in entrambi i casi).

Ecco il mio codice attuale:

/**
 * Retrieves the component activated before a target component.
 *
 * @internal Targets the 'active_history' in the mother array, as such, it doesn't look at the installed history at all.
 *
 * @param string $target_component_name The target component name, used as a starting point.
 * @param boolean $skip_check Flag to allow skipping of certain checks.
 * @param array $support_package A support package passed from outside callers that can speed up the execution of this function due to bypasses of checks.
 *
 * @return string|mixed Returns the string of the component found before our target on success and a mix of boolean / WP_Errors on failure.
 */
public static function getActiveComponentBeforeThisOne( $target_component_name, $skip_check = False, $support_package = null )
{
    $installed_components = get_option( 'currently_installed_demo_components' );

    //Support check 1.
    if( $skip_check == False ) {
        if( !self::determineIfDemoComponentIsInstalled( $target_component_name ) ) {
            return new \WP_Error(
                'component-not-installed',
                esc_html__( 'Component is not currently installed.', 'setup-theme' )
            );
        }
    }

    //Support check 2.
    $local_package = [
        'component_category' => ''
    ];

    if( isset( $support_package['component_category'] ) ) {
        $local_package['component_category'] = $support_package['component_category'];
    } else {
        $local_package['component_category'] = self::getComponentCategoryByName( $target_component_name );
    }

    //Do some things with $local_package['component_category'] here.
}

Come puoi vedere, il primo supporto $skip_check mi consente di impostare un flag per saltare un controllo pesante che può essere ed è, nel 95% dei casi, eseguito prima che venga chiamata questa funzione.

Questa è una trappola: in un sistema basato su eventi come WordPress (anche se i ganci sono perfettamente eseguiti), si potrebbero riscontrare errori nelle condizioni di gara, specialmente all'interno delle chiamate AJAX (che è dove questi sono utilizzati). Il mio assegno non farebbe nulla allora. Anche se nel 99,9% dei casi in cui funziona, c'è quella terribile situazione in cui non funziona e finisce per rompere tutto.

Il secondo supporto è $support_package . Sto chiamando getActiveComponentBeforeThisOne da un contesto in cui ho già accesso a molti dati, in particolare component_category , quindi, per quasi tutti i casi, posso solo fornire alla mia funzione, ancora, di saltare questi pesanti controlli che rallentano me giù.

Questa è una trappola due: potrei semplicemente decidere di chiamare getComponentCategoryByName dove chiamo anche getActiveComponentBeforeThisOne se, a quel punto, vedo che component_category non è disponibile per me. Ciò introdurrebbe chiarezza su cosa sta succedendo. Quindi il vero problema qui è la visibilità e il secondo, forse un problema importante è la separazione delle preoccupazioni. Così com'è, la mia funzione getActiveComponentBeforeThisOne finisce per fare troppo. Una funzione che genera molti dati in genere è soddisfacente: non è intelligente separare le operazioni di un array in un'unica operazione in più funzioni perché diventa rapidamente un cluster-f da seguire: i buoni commenti vanno bene. Ma qui, chiaramente, qui abbiamo una funzione mostro che fa molto in termini di controlli , infatti, le mie funzioni finirebbero per essere il 90% + solo questi controlli e il 10% effettivo "fai cosa X ".

Sto solo sporcando il mio codice, schiacciando il livello dati nel mio livello logico? Qual è l'alternativa?

Sembra che, quando leggo il mio codice, devo passare un sacco di controlli in cui ho bisogno di dire "Ah, quindi controlla questo, questo e questo ..." solo per ottenere al reale "ah, fa questo!".

Ho anche a che fare con cose molto delicate in cui se importo / elimino la cosa sbagliata, il mio sistema fallisce e non c'è altro modo di farlo, quindi è anche necessario controllare ogni passaggio prima di eseguire operazioni cruciali.

    
posta coolpasta 14.12.2018 - 15:52
fonte

2 risposte

2

Questa è sicuramente una trappola. Una trappola per orsi d'acciaio. E la gamba del codice è catturata in essa. E un T-Rex ha già calpestato il codice e lo sta battendo avanti e indietro in stile Jurassic Park.

Mescolare un parametro booleano che attiva e disattiva la funzionalità, e combinarlo con un altro argomento che è un nebuloso array di "supporto" ti dà un tale caos aggrovigliato che non saprei neanche come raccomandare una correzione. Sembra che tu abbia tre problemi:

  1. Un controllo è costoso
  2. Devi fornire una categoria una volta ogni tanto
  3. Altre cose varie

Correzione del controllo "costoso"

Fondamentalmente ci sono troppe fonti di informazione, e correggerle non è facile dato lo stato attuale del codice. È necessario mantenere lo stato in modo da poter memorizzare in cache questi controlli costosi. La prima volta che si controlla se un componente è installato, memorizza il valore booleano in qualche posto in modo che non sia necessario eseguire la parte più costosa del controllo. Controllare una volta Restituisce il valore memorizzato nella cache nei controlli successivi in modo da non dover controllare in modo condizionale. Controlla sempre. La differenza è che è solo il primo controllo ad essere costoso.

Se qualcosa verifica prima di chiamare questa procedura, quell'altra cosa ha bisogno di un modo per contrassegnare un componente come installato prima di eseguire questa procedura, essenzialmente pre-cache del risultato del controllo per quel componente.

Fornire una categoria o un valore predefinito

Questa è un'altra facile soluzione. Elimina l'array $support_package a favore di un argomento con nome esplicito, impostando come valore predefinito null:

public static function getActiveComponentBeforeThisOne( $target_component_name, $category = null)
{
    if (!isset($category)) {
        $category = self::getComponentCategoryByName( $target_component_name );
    }

    // ...

Altre cose varie

Penso che la risposta qui sia "non farlo". O creare metodi aggiuntivi o creare un'altra classe per incapsulare questi dati e comportamenti. L'array $support_package è sicuramente un odore di codice. Diventa un coltellino svizzero di dati che guida un coltellino svizzero di funzionalità. Sembra che manchi alcune classi specializzate in altre cose. Qui puoi sfruttare il polimorfismo in combinazione con classi o interfacce astratte per passare in un comportamento diverso, che può essere determinato dal chiamante.

Questo non dovrebbe essere un grosso problema, dal momento che il chiamante sta già passando cose diverse in base a diversi casi d'uso comunque.

    
risposta data 14.12.2018 - 17:12
fonte
0

Quello che dovresti fare è passare in un repository le cose di cui la tua funzione ha bisogno e implementare la cache in quel repository

es

self::getComponentCategoryByName( $target_component_name )

Se lo hai già chiamato una volta, da qualche parte sul flusso della funzione, allora non dovrebbe più essere un controllo lento. Poiché all'interno di questa funzione puoi implementare il tuo

if( isset( $alreadyLoaded[$target_component_name] ) )

array e semplicemente restituire il valore senza eseguire il sollevamento pesante due volte.

Naturalmente, se esiste un problema di una possibile condizione di competizione, è necessario implementare il blocco all'interno della funzione per garantire che le chiamate successive alla funzione attestino il primo carico lento delle chiamate piuttosto che il caricamento per ciascuna chiamata.

Ma perché incapsula la cache e il caricamento nello stesso posto è semplice.

    
risposta data 14.12.2018 - 16:40
fonte

Leggi altre domande sui tag