Apa kelemahan pola ActiveRecord?

30

Saya ingin tahu apa kelemahan menggunakan pola ActiveRecord untuk akses data / objek bisnis. Satu-satunya yang dapat saya pikirkan adalah bahwa hal itu melanggar Prinsip Tanggung Jawab Tunggal, tetapi pola AR cukup umum sehingga alasan ini saja sepertinya tidak "cukup baik" untuk membenarkan tidak menggunakannya (tentu saja saya pandangan mungkin miring karena sering kali tidak ada kode yang saya gunakan dengan mengikuti salah satu prinsip SOLID).

Secara pribadi saya bukan penggemar ActiveRecord (dengan pengecualian menulis aplikasi Ruby on Rails, di mana AR terasa "alami") karena rasanya seperti kelas melakukan terlalu banyak, dan akses data tidak boleh sampai ke kelas itu sendiri untuk menangani. Saya lebih suka menggunakan Repositori yang mengembalikan objek bisnis. Sebagian besar kode yang saya gunakan cenderung menggunakan variasi ActiveRecord, dalam bentuk (Saya tidak tahu mengapa metode ini adalah boolean):

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

atau kadang-kadang cara yang lebih "tradisional" untuk memiliki public static Foo FindFooByID(int fooID)metode untuk para pencari dan sesuatu public void Save()untuk menghemat / memperbarui.

Saya mendapatkan bahwa ActiveRecord biasanya jauh lebih sederhana untuk diimplementasikan dan digunakan, tetapi tampaknya sedikit terlalu sederhana untuk aplikasi yang kompleks dan Anda bisa memiliki arsitektur yang lebih kuat dengan merangkum logika akses data Anda dalam Repositori (belum lagi memiliki lebih mudah untuk swap keluar strategi akses data mis. mungkin Anda menggunakan Stored Procs + DataSets dan ingin beralih ke LINQ atau sesuatu)

Jadi apa kelemahan lain dari pola ini yang harus dipertimbangkan ketika memutuskan apakah ActiveRecord adalah kandidat terbaik untuk pekerjaan itu?

Wayne Molina
sumber

Jawaban:

28

Kelemahan utama adalah "entitas" Anda menyadari kegigihan mereka sendiri yang mengarah ke banyak keputusan desain buruk lainnya.

Masalah lainnya adalah bahwa sebagian besar toolkit catatan aktif pada dasarnya memetakan 1 ke 1 ke bidang tabel dengan nol lapisan tipuan. Ini bekerja pada skala kecil tetapi berantakan ketika Anda memiliki masalah rumit untuk dipecahkan.


Nah, memiliki objek Anda tahu tentang kegigihan mereka berarti Anda perlu melakukan hal-hal seperti:

  • dengan mudah memiliki koneksi basis data yang tersedia di mana-mana. Ini biasanya mengarah pada hardcoding yang tidak menyenangkan atau semacam koneksi statis yang dapat dipukul dari mana-mana.
  • objek Anda cenderung lebih mirip SQL daripada objek.
  • sulit untuk melakukan apa pun di aplikasi terputus karena basis data sudah tertanam.

Akhirnya ada banyak keputusan buruk lainnya di atas ini.

Wyatt Barnett
sumber
2
dapatkah Anda menguraikan "keputusan desain buruk lainnya"?
kevin cline
2
Terima kasih. Saya belum menemukan masalah ini sebagai masalah dalam pengembangan Ruby on Rails. Masih mungkin untuk menguji perilaku dan kegigihan secara terpisah. IMO yang memisahkan kegigihan dari perilaku memiliki sedikit nilai praktis.
kevin cline
@ kevin: hal-hal ini kurang dari kelemahan dengan fitur ruby ​​seperti mixin dan ketikan bebek. Dengan bahasa statis - seperti C # yang digunakan OP dalam pertanyaannya - agak sulit untuk memisahkan keduanya.
Wyatt Barnett
@Wayne: bagi saya, kelas hanyalah kotak untuk memasukkan metode - Saya dapat memisahkan logika bisnis dari kegigihan dengan menempatkannya di kelas yang berbeda, atau saya hanya bisa memisahkannya secara konseptual dengan memastikan bahwa metode bisnis tidak melakukan saya / HAI. Dalam bahasa dengan dukungan delegasi yang buruk (mis. Java), ini menyimpan sejumlah besar kode. OTOH, saya baru saja masuk ke Hibernate sehingga saya bisa salah total.
kevin cline
4
Saya akan menambahkan dua hal; 1. Kopling dengan mekanisme kegigihan membuat kode sulit, jika bukan tidak mungkin, untuk unit test dengan benar. 2. Rekaman Aktif menempelkan kode Anda ke hubungan dalam mekanisme ketekunan terpusat, sehingga sangat sulit untuk membagi monolit Anda jika Anda pernah memutuskan untuk melakukannya.
istepaniuk
15

Kerugian terbesar dari rekaman aktif adalah bahwa domain Anda biasanya menjadi sangat terkait dengan mekanisme ketekunan tertentu. Jika mekanisme itu memerlukan perubahan global, mungkin dari kegigihan berbasis file ke DB, atau di antara kerangka kerja akses data, SETIAP kelas yang mengimplementasikan pola ini dapat berubah. Bergantung pada bahasa, kerangka kerja, dan desain, bahkan sesuatu yang sangat sederhana seperti mengubah di mana DB berada atau siapa yang "memiliki" itu mungkin perlu melalui setiap objek untuk memperbarui metode akses data (ini tidak umum dalam kebanyakan bahasa yang menyediakan akses mudah untuk mengkonfigurasi file dengan string koneksi).

Biasanya juga mengharuskan Anda mengulangi sendiri. Sebagian besar mekanisme ketekunan memiliki banyak kode umum, untuk terhubung ke DB dan memulai transaksi. KERING (Jangan Ulangi Diri Sendiri) akan memberi tahu Anda sebagai pembuat kode untuk memusatkan logika tersebut.

Itu juga membuat operasi atom rumit. Jika sekelompok objek harus disimpan dengan cara semua atau tidak sama sekali (seperti Faktur dan InvoiceLines dan / atau Pelanggan dan / atau entri GL), salah satu objek harus tahu tentang semua objek lain ini dan mengendalikan kegigihannya ( yang membentang ruang lingkup objek pengontrol; catatan besar yang saling berhubungan dapat dengan mudah menjadi "objek dewa" yang mengetahui segala sesuatu tentang ketergantungannya), atau kontrol atas seluruh transaksi harus ditangani dari luar domain (dan dalam kasus itu mengapa Anda menggunakan AR?)

Ini juga "salah" dari perspektif Berorientasi Objek. Di dunia nyata, faktur tidak tahu cara mengajukan sendiri, jadi mengapa objek kode Faktur tahu bagaimana cara menyimpan dirinya ke DB? Tentu saja, kepatuhan yang terlalu religius terhadap "objek seharusnya hanya memodelkan apa yang dapat dilakukan rekan-rekan mereka di dunia nyata" akan mengarah pada model domain anemia (faktur juga tidak tahu bagaimana menghitung totalnya sendiri, tetapi membagi perhitungan total itu menjadi objek lain umumnya dianggap ide buruk).

KeithS
sumber
Di Ruby, di mana kegigihan dapat didefinisikan atau diabstraksi di balik kata kunci atau perintah yang sangat sederhana, itu mungkin bukan masalah. Dalam. NET, yang membutuhkan lebih banyak LoC untuk mengatur berbagai mekanisme kegigihan, biasanya berlebihan untuk memiliki koneksi SQL untuk setiap objek, terutama jika beberapa objek harus disimpan dalam satu transaksi atom. Menghubungkan ke DB terlihat sama apakah Anda menyimpan Faktur atau Pelanggan. Anda bisa mengabstraksi hal-hal umum menjadi kelas dasar yang umum untuk semua objek ActiveRecord dalam basis kode Anda, atau mengekstraknya ke kelasnya sendiri (Repositori)
KeithS
dapatkah Anda memberikan contoh penggunaan Ruby ActiveRecord yang menggambarkan poin Anda? Saya tidak mengalami masalah ini, tetapi aplikasi saya cukup kecil. Saya bisa menulis migrasi di Ruby, dan menyebarkannya ke implementasi DB yang berbeda. Saya menemukan bahwa ActiveRecord Ruby sangat berguna dalam menghilangkan pengulangan, jadi saya tidak melihat mengapa Anda akan menyatakan bahwa menggunakan ActiveRecord akan memiliki efek sebaliknya. Saya tidak punya masalah dengan menyimpan: Saya hanya memodifikasi model objek, dan membiarkan AR memperbarui DB untuk mencerminkan model objek.
kevin cline
2

Kelemahan dasarnya adalah, Ini membuat model domain Anda menjadi kompleks karena tidak hanya menyimpan logika bisnis tetapi juga informasi kegigihan.

Jadi solusinya adalah dengan menggunakan implementasi Data Mapper dari ORM. Itu memisahkan lapisan persistensi dan kita sekarang lebih fokus pada logika bisnis entitas. Doktrin adalah Data Mapper ORM.

Tetapi pendekatan ini juga memiliki beberapa kompleksitas, Untuk permintaan sekarang Anda terlalu bergantung pada Data Mapper, membuat lingkungan yang berorientasi permintaan. Untuk menyederhanakannya lapisan lain diperkenalkan antara Model Domain dan Data Mapper disebut Repositori .

Repositori mengabstraksi lapisan persistensi. Itu membuat merasa pemrograman berorientasi objek dalam arti, itu adalah kumpulan dari semua jenis objek yang sama (karena semua entitas disimpan dalam tabel database) dan Anda dapat melakukan operasi pada mereka sebagai operasi pengumpulan, menambah , menghapus . mengandung dll

Misalnya untuk Entitas Pengguna , akan ada UserRepository yang mewakili koleksi dari jenis objek pengguna yang sama (yang disimpan dalam tabel pengguna) yang dapat Anda lakukan operasi. Untuk query ke tabel pengguna itu menggunakan Mapper Data Pengguna tetapi itu disarikan ke model domain Pengguna .

Pola repositori adalah tipe Lapisan Akses Data , yang lain adalah Perbedaan Akses Objek Data . Repositori memiliki fitur Agregat Root

palash140
sumber
Repositori dan pola DAO berbeda, DAO adalah akses data umum, Repositori adalah untuk persistensi koleksi semua objek bertipe sama. Yaitu semua Repositori harus memiliki antarmuka yang sama (seperti array atau daftar). Raja metode lainnya bukan milik Repositori. DAO adalah level yang lebih rendah, Repositori dapat menggunakan DAO. Seringkali, programmer (terutama PHP) menggunakan Repository sebagai DAO, tetapi itu tidak benar.
xmedeko