Código limpo e reutilizável VS - cadê o saldo?

5

Digamos que eu tenha um modelo de dados para postagens de blog e tenha dois casos de uso desse modelo - obtendo todos os posts do blog e obtendo apenas postagens de blog que foram escritas por um autor específico.

Existem basicamente duas maneiras de entender isso.

1º modelo

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));
    }
}

1º uso (apresentador / controlador)

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

2º lugar

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));
    }

}

2º uso (apresentador / controlador)

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

Para resumir (des) vantagens:

1) código mais limpo

2) código mais reutilizável

Qual você acha que é melhor e por quê? Existe algum tipo de compromisso entre os dois?

    
por Radek Simko 11.10.2012 / 10:06
fonte

4 respostas

4

O truque é que você não precisa escolher. Uma coisa legal que muitos ORMs fornecem (por exemplo, o do Django, Squeryl, SQLAlchemy e mais) são consultas compostas. Ou seja, você pode não apenas consultar uma tabela, mas consultar os resultados de outra consulta. Isso não é tão caro quanto parece, já que o otimizador de consultas ORM ou DB pode reduzi-lo a um SELECT combinado.

Então você acabaria com algo como (exemplo do Django)

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

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

Lá você tem - dois métodos separados e sem repetição. : -)

Quando você tem que escolher entre limpa e reutilizável, muitas vezes há uma terceira opção: um pouco mais sofisticada, mas limpa e reutilizável.

(By the way, os métodos estáticos existem apenas para imitar sua estrutura. Na verdade, um teria métodos de instância na classe Gerenciador de artigos. Também devo acrescentar que este é um exemplo trivial, como o gerenciador padrão - denominado Article.objects - já fornece o método all para recuperar todos os resultados, mas esse não é o ponto - o ponto é que você obteve um resultado mais específico, consultando um conjunto de resultados maior.

    
por 11.10.2012 / 10:42
fonte
1

Eu mesmo gosto da opção # 1 porque ela fornece uma narrativa mais clara para o seu código, e outros programadores não precisam se aprofundar na sua classe Articles para ver o que acontece quando $authorUid é nulo.

Mas se você vai usar esse if() em muitos lugares, então faz sentido fazer algo para envolver essa lógica em uma única função. Talvez seja uma convenção que qualquer método genericamente nomeado como getPosts() tenha lógica para resolver argumentos opcionais. Talvez faça algo assim:

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));
    }
}
    
por 11.10.2012 / 19:05
fonte
0

Por que não deixar uma matriz $query vazia indicar que não há requisitos sobre as postagens a serem recuperadas? Dessa forma, as mesmas chamadas de função podem ser usadas para praticamente todas as partes (somente a chamada de wrapper mais externa precisa ser diferente, se você não quiser codificar dependências nas chaves de matriz).

Essa é certamente a abordagem que eu preferiria tanto de uma perspectiva de reutilização quanto de limpeza, pelo menos.

    
por 11.10.2012 / 10:38
fonte
0

Se parecer um caso específico, significa que você ainda não encontrou a solução correta.

Eu não falo PHP, então meu exemplo de código provavelmente estaria errado, mas para mantê-lo abstrato, a maneira mais óbvia de tornar seu exemplo both reutilizável e limpo é ter seu getPosts() function chama sua função getPostsByAuthor() com um argumento null . Melhor ainda, basta refatorar o código que faz a pesquisa e usá-lo diretamente de ambas as outras funções (uma obtém a pesquisa e a executa como está, a outra marca primeiro uma condição extra e depois a executa). Dessa forma, você só define o código que faz o trabalho uma vez (ou seja, se ele precisa ser alterado mais tarde, ele só precisa ser alterado em um lugar) e é limpo em termos de poder chamar qualquer método (que parecia seja o seu critério "limpo", a menos que eu o esteja entendendo mal).

    
por 11.10.2012 / 11:03
fonte