Codice pulito riutilizzabile VS: dov'è il bilanciamento?

5

Diciamo che ho un modello di dati per i post di un blog e ho due casi d'uso di quel modello - ottenendo tutti i post di blog e ricevendo solo post di blog che sono stati scritti da un autore specifico.

Ci sono fondamentalmente due modi in cui posso rendermene conto.

1o modello

class Articles {

    public function getPosts() {
        return $this->connection->find()
            ->sort(array('creation_time' => -1));
    }

    public function getPostsByAuthor( $authorUid ) {
        return $this->connection->find(array('author_uid' => $authorUid))
            ->sort(array('creation_time' => -1));
    }
}

Primo utilizzo (presentatore / controller)

if ( $GET['author_uid'] ) {
    $posts = $articles->getPostsByAuthor($GET['author_uid']);
} else {
    $posts = $articles->getPosts();
}

2o

class Articles {

    public function getPosts( $authorUid = NULL ) {
        $query = array();

        if( $authorUid !== NULL ) {
            $query = array('author_uid' => $authorUid);
        }

        return $this->connection->find($query)
            ->sort(array('creation_time' => -1));
    }

}

Secondo utilizzo (presentatore / controller)

$posts = $articles->getPosts( $_GET['author_uid'] );

Per riassumere (dis) vantaggi:

1) codice più pulito

2) codice più riutilizzabile

Quale pensi sia meglio e perché? C'è qualche tipo di compromesso tra questi due?

    
posta Radek Simko 11.10.2012 - 10:06
fonte

4 risposte

4

Il trucco è che non devi scegliere. Una cosa carina che molti ORM forniscono (per esempio quella di Django, Squeryl, SQLAlchemy e altro) sono le query componibili. Cioè, puoi non solo interrogare una tabella ma interrogare i risultati di un'altra query. Questo non è così costoso come sembra, in quanto l'ORM o il DB Query Optimizer possono ridurlo a una SELECT combinata sotto il cofano.

Quindi ti ritroverai con qualcosa tipo (esempio di Django)

class Article:
  @staticmethod
  def posts():
    return Article.objects.all()

  @staticmethod
  def author_posts(author):
    return Article.posts().filter(author=author)

Ecco qua - due metodi separati e nessuna ripetizione. : -)

Quando devi scegliere tra pulito e riutilizzabile, c'è spesso una terza opzione: un po 'più sofisticata, ma sia pulita che riutilizzabile.

(A proposito, i metodi statici ci sono solo per imitare la tua struttura. In realtà uno avrebbe i metodi di istanza nella classe Article Manager. Dovrei anche aggiungere che questo è un esempio banale, come il gestore predefinito - chiamato Article.objects - fornisce già il metodo all per recuperare tutti i risultati, ma non è questo il punto - il punto è che hai ottenuto un set di risultati più specifico interrogando un set di risultati più ampio.)

    
risposta data 11.10.2012 - 10:42
fonte
1

Mi piace l'opzione n. 1 perché fornisce una descrizione più chiara del tuo codice e altri programmatori non devono scavare nella tua classe Articles per vedere cosa succede quando $authorUid è nullo.

Ma se utilizzi quel if() in molti punti, allora ha senso fare qualcosa per avvolgere quella logica in una singola funzione. Forse rendi una convenzione che qualsiasi metodo con nomi generici come getPosts() avrà la logica per risolvere argomenti opzionali. Forse fai qualcosa del genere:

class Articles {

    public function getPosts($authorUid = NULL, $yada = NULL, $yada_yada = NULL) {
        // Keep all descision making logic in this method.
        if( $authorUid !== NULL ) {
            // call getPostsByAuthor
        } else if(...) {
            // call getAllPosts
        } // else if (...) and so on...
    }

    public function getAllPosts() {
        return $this->connection->find()
            ->sort(array('creation_time' => -1));
    }

    public function getPostsByAuthor( $authorUid ) {
        return $this->connection->find(array('author_uid' => $authorUid))
            ->sort(array('creation_time' => -1));
    }
}
    
risposta data 11.10.2012 - 19:05
fonte
0

Perché non lasciare che una matrice $query vuota indichi che non ci sono requisiti per i post da recuperare? In questo modo, le stesse chiamate di funzione possono essere utilizzate praticamente per tutto (solo la chiamata del wrapper più esterna deve essere diversa, se non si desidera utilizzare le dipendenze dell'hardcode sui tasti dell'array).

Questo è certamente l'approccio che preferirei sia dalla prospettiva di riusabilità e pulizia, almeno.

    
risposta data 11.10.2012 - 10:38
fonte
0

Se sembra un caso / o, significa solo che non hai ancora trovato la soluzione giusta.

Non parlo PHP, quindi il mio esempio di codice sarebbe probabilmente sbagliato, ma per tenerlo astratto, il modo più ovvio per rendere il tuo esempio entrambi riutilizzabile e pulito è avere il tuo getPosts() function chiama la tua funzione getPostsByAuthor() con un argomento null . Meglio ancora, basta rifattorizzare il codice che fa la ricerca e usarlo direttamente da entrambe le altre funzioni (si ottiene la ricerca e la si esegue così com'è, l'altra punta su una condizione extra prima e poi la esegue). In questo modo, definisci il codice che fa il lavoro una sola volta (cioè se ha bisogno di essere modificato in seguito, deve solo essere cambiato in un unico posto) ed è pulito in termini di poter chiamare entrambi i metodi (che sembrava sii il tuo criterio "pulito", a meno che non ti fraintenda).

    
risposta data 11.10.2012 - 11:03
fonte

Leggi altre domande sui tag