ActiveRecordパターンの欠点は何ですか?


30

データアクセス/ビジネスオブジェクトにActiveRecordパターンを使用することの欠点は何ですか?私が頭の外から考えることができる唯一のことは、それが単一責任原則に違反しているということですが、ARパターンは十分に一般的であり、この理由だけではそれを使用しないことを正当化する「十分」ではないようです(もちろん私のビューは、以下で符号Iの作業の多くの場合、いずれもため斜めであってもよい任意)SOLID原理を。

個人的にはActiveRecordのファンではありません(Ruby on Railsアプリケーションを書くことは例外で、ARは「自然」だと感じます)。処理します。ビジネスオブジェクトを返すリポジトリを使用することを好みます。私が扱うコードのほとんどは、ActiveRecordのバリエーションを使用する傾向があります(メソッドがブール値である理由がわかりません)。

public class Foo
{
    // properties...

    public Foo(int fooID)
    {
        this.fooID = fooID;
    }

    public bool Load()
    {
        // DB stuff here...
        // map DataReader to properties...

        bool returnCode = false;
        if (dr.HasRows)
            returnCode = true;

        return returnCode;
    }
}

またはpublic static Foo FindFooByID(int fooID)、ファインダやpublic void Save()保存/更新の方法に沿った何かのためのメソッドを持つ、より「伝統的な」方法です。

ActiveRecordは一般的に実装と使用がはるかに簡単ですが、複雑なアプリケーションには少し単純すぎるようで、データアクセスロジックをリポジトリにカプセル化することでより堅牢なアーキテクチャを実現できますデータアクセス戦略。たとえば、ストアドプロセッサ+データセットを使用していて、LINQなどに切り替えたい場合

ActiveRecordがジョブの最適な候補であるかどうかを判断する際に考慮すべきこのパターンの他の欠点は何ですか?

回答:


28

主な欠点は、「エンティティ」が自身の永続性を認識しているため、他の多くの悪い設計上の決定につながることです。

他の問題は、ほとんどのアクティブなレコードツールキットが基本的に1対1の間接参照のレイヤーを持たないテーブルフィールドにマップすることです。これは小規模では機能しますが、解決するのが難しい問題がある場合はバラバラになります。


さて、オブジェクトにその永続性を知らせることは、次のようなことをする必要があることを意味します。

  • どこでも簡単にデータベース接続を利用できます。これは通常、厄介なハードコーディングや、あらゆる場所からヒットする静的な接続につながります。
  • オブジェクトはオブジェクトよりもSQLのように見える傾向があります。
  • データベースが非常に染み込んでいるため、切断されたアプリで何かをするのは難しい。

これに加えて、他の多くの悪い決定がたくさんあります。


2
「その他の悪い設計上の決定」について詳しく説明できますか?
ケビンクライン

2
ありがとう。これらの問題がRuby on Rails開発の問題であるとは思っていません。動作と永続性を個別にテストすることは引き続き可能です。永続性と動作を分離するIMOには実用的な価値はほとんどありません。
ケビンクライン

@kevin:これらは、ミックスインやダックタイピングなどのルビー機能を備えているため、欠点が少なくなります。OPが彼の質問で使用したものであるC#のような静的言語では、2つを分離するのはもう少し難しいです。
ワイアットバーネット

@Wayne:私にとって、クラスはメソッドを入れるための単なる箱です-私はそれらを別々のクラスに置くことによって永続性からビジネスロジックを分離することができます、またはビジネスメソッドがI / O. 委任サポートが不十分な言語(Javaなど)では、これにより大量のコードが節約されます。OTOH、私はただHibernateに入っているので、完全に間違っている可能性があります。
ケビンクライン

4
次の2つを追加します。1.永続化メカニズムとの結合により、コードは、不可能ではないにしても、適切に単体テストを行うことが難しくなります。2. Active Recordはコードを一元化された永続化メカニズムでリレーションシップに接着します。これにより、モノリスを分割することが本当に困難になる場合があります。
istepaniuk

15

アクティブレコードの最大の欠点は、通常、ドメインが特定の永続化メカニズムに密接に結合されることです。そのメカニズムが、ファイルベースからデータベースベースの永続性への、またはデータアクセスフレームワーク間のグローバルな変更を必要とする場合、このパターンを実装するすべてのクラスが変更される可能性があります。言語、フレームワーク、設計によっては、DBの場所や「所有者」を変更するような単純なものであっても、すべてのオブジェクトを経由してデータアクセスメソッドを更新する必要があります(これは、簡単なアクセスを提供するほとんどの言語では一般的ではありません接続文字列を使用してファイルを構成します)。

また、一般的に自分自身を繰り返す必要があります。ほとんどの永続化メカニズムには、DBに接続してトランザクションを開始するための多くの共通コードがあります。DRY(Do n't Repeat Yourself)は、そのようなロジックを集中化するコーダーとしてあなたに伝えます。

また、アトミック操作を扱いにくくします。オブジェクトのグループをオールオアナッシングで保存する必要がある場合(InvoiceとそのInvoiceLinesおよび/またはCustomerおよび/またはGLエントリなど)、いずれかのオブジェクトがこれらの他のすべてのオブジェクトを認識し、その永続性を制御する必要があります(制御オブジェクトの範囲を拡大します。相互接続された大きなレコードは、依存関係についてすべてを知っている「神オブジェクト」になりやすい)、またはトランザクション全体の制御はドメインの外部から処理する必要があります(その場合は、 AR?)

また、オブジェクト指向の観点からは「間違っています」。現実の世界では、請求書はそれ自体のファイル方法を知らないので、なぜInvoiceコードオブジェクトはそれ自体をDBに保存する方法を知っているのでしょうか?もちろん、「オブジェクトは現実世界の対応物ができることのみをモデル化する必要があります」を過度に宗教に固執すると貧血領域モデルになります(請求書も独自の合計を計算する方法を知りませんが、その合計の計算を別のオブジェクトは一般に悪い考えと見なされます)。


非常に単純なキーワードまたはコマンドの背後で永続性が定義または抽象化される可能性のあるRubyでは、おそらくそれほど問題ではありません。さまざまな永続化メカニズムをセットアップするためにより多くのLoCを必要とする.NETでは、特に1つのアトミックトランザクションで複数のオブジェクトを保存する必要がある場合、各オブジェクトにSQL接続を確立することは通常冗長です。請求書を保存する場合も顧客を保存する場合も、DBへの接続は同じように見えます。共通のものをコードベース内のすべてのActiveRecordオブジェクトに共通の基本クラスに抽象化するか、独自のクラス(リポジトリ)に抽出します
KeithS

あなたのポイントを説明するRuby ActiveRecordの使用例を提供できますか?これらの問題は発生しませんでしたが、アプリケーションはかなり小さかったです。Rubyで移行を記述し、異なるDB実装に展開することができます。RubyのActiveRecordは繰り返しを排除するのに非常に役立つことがわかったので、ActiveRecordを使用すると逆の効果があると断言する理由がわかりません。保存に問題はありませんでした。オブジェクトモデルを変更し、ARでオブジェクトモデルを反映するようにDBを更新しました。
ケビンクライン

2

基本的な欠点は、ビジネスロジックだけでなく永続性情報も保持するため、ドメインモデルが複雑になることです。

そのため、ソリューションはORMのData Mapper実装を利用することです。これにより、永続化レイヤーが分離され、エンティティのビジネスロジックにより重点を置くようになりました。DoctrineData Mapper ORMです。

しかし、このアプローチには多少の複雑さもあります。クエリの場合、Data Mapperに依存しすぎているため、クエリ指向の環境になります。それを簡素化するために、ドメインモデルData Mapperの間に別のレイヤーが導入され、リポジトリと呼ばれます

リポジトリは永続層を抽象化します。ある意味でオブジェクト指向プログラミングの感覚があり、すべての同じタイプのオブジェクトのコレクション(すべてのエンティティがデータベーステーブルに格納されている)であり、コレクション操作、addremoveとしてそれらの操作を実行できます。など が含まれています

たとえば、User Entityの場合、操作を実行できる同じタイプのユーザーオブジェクト(usersテーブルに格納されている)のコレクションを表すUserRepositoryがあります。ユーザーテーブルにクエリを実行するために、ユーザーデータマッパーを使用しますが、ドメインモデルUserに抽象化されます

リポジトリパターンデータアクセス層のタイプで、別のパターンデータアクセスオブジェクトのみの違いですリポジトリに集約ルート機能があります


リポジトリDAOのパターンは異なります。DAOは一般的なデータアクセスであり、リポジトリはすべて同じタイプのオブジェクトのコレクションを永続化するためのものです。すなわち、すべてのリポジトリは同じ配列(配列やリストなど)を持つ必要があります。メソッドの他の王はリポジトリに属していません。DAOは下位レベルであり、リポジトリはDAOを使用する場合があります。多くの場合、プログラマー(特にPHP)はリポジトリをDAOとして使用しますが、それは正しくありません。
xmedeko
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.