web-dev-qa-db-ja.com

再利用可能なVSクリーンコード-バランスはどこにありますか?

ブログ投稿のデータモデルがあり、そのモデルの2つのユースケースがあるとします。すべてのブログ投稿を取得することと、特定の作成者によって作成されたブログ投稿のみを取得することです。

それを実現するには、基本的に2つの方法があります。

最初のモデル

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

最初の使用法(プレゼンター/コントローラー)

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

2番目

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回目の使用(プレゼンター/コントローラー)

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

短所を要約するには:

1)よりクリーンなコード

2)より再利用可能なコード

どちらが良いと思いますか、そしてその理由は何ですか?これら2つの間に何らかの妥協点はありますか?

5
Radek Simko

秘訣は、選択する必要がないことです。多くのORMが提供する素晴らしいものの1つ(たとえば、Django、Squeryl、SQLAlchemyなどのもの)は、合成可能なクエリです。つまり、テーブルをクエリするだけでなく、別のクエリの結果をクエリすることもできます。 ORMまたはDBクエリオプティマイザのいずれかが内部で結合されたSELECTに削減できるため、これは見た目ほどコストがかかりません。

したがって、(Djangoの例)のようなものになります

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

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

そこには-2つの別々のメソッドandの繰り返しはありません。 :-)

クリーンと再利用可能のどちらかを選択する必要がある場合、多くの場合、3番目のオプションがあります。もう少し洗練されていますが、クリーンで再利用可能です。

(ちなみに、静的メソッドは構造を模倣するためだけにあります。実際にはArticleマネージャークラスにインスタンスメソッドがあります。これは、Article.objectsという名前のデフォルトマネージャーとして、自明な例であることも追加する必要があります。 -すでにすべての結果を取得するためのallメソッドを提供していますが、これは重要ではありません-重要なのは、より大きな結果セットをクエリすることで、より具体的な結果セットを取得したことです。)

4
Andrea

私はオプション#1が好きです。なぜなら、それはあなたのコードに明確な物語を与え、他のプログラマーは_$authorUid_がnullのときに何が起こるかを見るためにあなたのArticlesクラスを掘り下げる必要がないからです。

しかし、そのif()を多くの場所で使用する場合は、そのロジックを1つの関数にまとめるために何かを行うのが理にかなっています。おそらく、getPosts()のような一般的に名前が付けられたメソッドには、オプションの引数を解決するロジックがあるという慣習になります。たぶんこのようなことをするでしょう:

_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));
    }
}
_
1
programmer

空の$query配列に、取得する投稿に要件がないことを示してはどうですか?そうすれば、ほぼ全体を通して同じ関数呼び出しを両方に使用できます(配列キーへの依存関係をハードコーディングしたくない場合は、最も外側のラッパー呼び出しのみを異なる必要があります)。

それは確かに、少なくとも再利用性と清潔さの両方の観点から私が好むアプローチです。

0
a CVn

どちらかまたは両方のケースのように見える場合は、適切なソリューションがまだ見つからないことを意味します。

私はPHPを話さないので、私のコード例はおそらく間違っているでしょうが、それを抽象的に保つために、あなたの例bothを再利用可能かつクリーンにする最も明白な方法は、あなたのgetPosts()関数は、null引数を使用してgetPostsByAuthor()関数を呼び出します。さらに良いのは、検索を実行するコードをリファクタリングして、他の両方の関数から直接使用することです(1つは検索を取得してそのまま実行し、もう1つは追加の条件を先に実行してから実行します)。そうすれば、作業を1回だけ実行するコードを定義するだけで(つまり、後で変更する必要がある場合は、1か所で変更するだけで済みます)、どちらのメソッドも呼び出すことができるという点でクリーンです(私があなたを誤解していない限り、あなたの「クリーンな」基準になります)。

0