Saat saya mempelajari lebih banyak tentang OOP, dan mulai menerapkan berbagai pola desain, saya terus kembali ke kasus di mana orang membenci Active Record .
Seringkali, orang mengatakan bahwa itu tidak berskala dengan baik (mengutip Twitter sebagai contoh utama mereka) - tetapi tidak ada yang benar-benar menjelaskan mengapa itu tidak berskala dengan baik; dan / atau bagaimana mencapai kelebihan AR tanpa kontra (melalui pola yang serupa tetapi berbeda?)
Mudah-mudahan ini tidak berubah menjadi perang suci tentang pola desain - yang ingin saya ketahui hanyalah **** khususnya **** apa yang salah dengan Rekaman Aktif.
Jika tidak berkembang dengan baik, mengapa tidak?
Masalah lain apa yang dimilikinya?
ruby-on-rails
design-patterns
oop
activerecord
Adam Tuttle
sumber
sumber
Jawaban:
Ada ActiveRecord the Design Pattern dan ActiveRecord the Rails ORM Library , dan ada juga banyak tiruan untuk .NET, dan bahasa lainnya.
Ini semua adalah hal yang berbeda. Mereka kebanyakan mengikuti pola desain itu, tetapi memperluas dan memodifikasinya dengan berbagai cara, jadi sebelum ada yang mengatakan "ActiveRecord Sucks", perlu dikualifikasikan dengan mengatakan "ActiveRecord mana, ada tumpukan?"
Saya hanya akrab dengan Rails 'ActiveRecord, saya akan mencoba mengatasi semua keluhan yang telah diangkat dalam konteks menggunakannya.
Kode:
Ini menghasilkan SQL dengan
LEFT JOIN companies on companies.id = person.company_id
, dan secara otomatis menghasilkan objek Perusahaan terkait sehingga Anda dapat melakukannyapeople.first.company
dan tidak perlu masuk ke database karena datanya sudah ada.Kode:
Ini tidak disarankan karena jelek, tetapi untuk kasus di mana Anda hanya sekadar dan hanya perlu menulis SQL mentah, itu mudah dilakukan.
Kode:
Ini hanya akan memilih kolom nama dan ID dari database, semua 'atribut' lainnya dalam objek yang dipetakan hanya akan nihil, kecuali Anda memuat ulang objek itu secara manual, dan seterusnya.
sumber
Saya selalu menemukan bahwa ActiveRecord bagus untuk aplikasi berbasis CRUD cepat di mana Modelnya relatif datar (seperti dalam, tidak banyak hierarki kelas). Namun, untuk aplikasi dengan hierarki OO yang kompleks, DataMapper mungkin merupakan solusi yang lebih baik. Sementara ActiveRecord mengasumsikan rasio 1: 1 antara tabel dan objek data Anda, hubungan semacam itu menjadi berat dengan domain yang lebih kompleks. Dalam bukunya tentang pola , Martin Fowler menunjukkan bahwa ActiveRecord cenderung rusak dalam kondisi di mana Model Anda cukup kompleks, dan menyarankan DataMapper sebagai alternatif.
Saya telah menemukan ini benar dalam praktiknya. Dalam kasus, di mana Anda memiliki banyak warisan di domain Anda, lebih sulit untuk memetakan warisan ke RDBMS Anda daripada memetakan asosiasi atau komposisi.
Cara saya melakukannya adalah memiliki objek "domain" yang diakses oleh pengontrol Anda melalui kelas DataMapper (atau "lapisan layanan") ini. Ini tidak secara langsung mencerminkan database, tetapi bertindak sebagai representasi OO Anda untuk beberapa objek dunia nyata. Katakanlah Anda memiliki kelas Pengguna di domain Anda, dan perlu memiliki referensi ke, atau kumpulan objek lain, yang sudah dimuat saat Anda mengambil objek Pengguna tersebut. Data mungkin berasal dari banyak tabel yang berbeda, dan pola ActiveRecord dapat membuatnya sangat sulit.
Alih-alih memuat objek User secara langsung dan mengakses data menggunakan API gaya ActiveRecord, kode pengontrol Anda mengambil objek User dengan memanggil API metode UserMapper.getUser (), misalnya. Mapper inilah yang bertanggung jawab untuk memuat objek terkait dari tabel masing-masing dan mengembalikan objek "domain" Pengguna yang telah selesai ke pemanggil.
Pada dasarnya, Anda hanya menambahkan lapisan abstraksi lain untuk membuat kode lebih mudah dikelola. Apakah kelas DataMapper Anda berisi SQL kustom mentah, atau panggilan ke API lapisan abstraksi data, atau bahkan mengakses pola ActiveRecord itu sendiri, tidak terlalu penting bagi kode pengontrol yang menerima objek Pengguna yang bagus dan terisi.
Bagaimanapun, itulah cara saya melakukannya.
sumber
Saya pikir ada kemungkinan alasan yang sangat berbeda antara mengapa orang "membenci" pada ActiveRecord dan apa yang "salah" dengannya.
Mengenai masalah kebencian, ada banyak racun terhadap apapun yang berhubungan dengan Rails. Sejauh apa yang salah dengan itu, mungkin itu seperti semua teknologi dan ada situasi di mana itu adalah pilihan yang baik dan situasi di mana ada pilihan yang lebih baik. Situasi di mana Anda tidak bisa memanfaatkan sebagian besar fitur Rails ActiveRecord, menurut pengalaman saya, adalah saat database terstruktur dengan buruk. Jika Anda mengakses data tanpa kunci utama, dengan hal-hal yang melanggar bentuk normal pertama, di mana ada banyak prosedur tersimpan yang diperlukan untuk mengakses data, lebih baik Anda menggunakan sesuatu yang lebih dari sekadar pembungkus SQL. Jika database Anda memiliki struktur yang relatif baik, ActiveRecord memungkinkan Anda memanfaatkannya.
Untuk menambah tema membalas komentator yang mengatakan hal-hal sulit di ActiveRecord dengan rejoinder cuplikan kode
Dengan menggunakan opsi sertakan, ActiveRecord memungkinkan Anda mengganti perilaku pemuatan lambat default.
sumber
Jawaban saya yang panjang dan terlambat, bahkan tidak lengkap, tapi penjelasan yang bagus MENGAPA saya benci pola, opini, dan bahkan emosi ini:
1) versi singkat: Rekaman Aktif membuat " lapisan tipis " dari " ikatan kuat " antara database dan kode aplikasi. Yang memecahkan tidak logis, tidak ada masalah apa pun, tidak ada masalah sama sekali. IMHO tidak memberikan NILAI APA PUN, kecuali beberapa gula sintaksis untuk programmer (yang kemudian dapat menggunakan "sintaks objek" untuk mengakses beberapa data, yang ada dalam database relasional). Upaya untuk menciptakan kenyamanan bagi pemrogram harus (IMHO ...) sebaiknya diinvestasikan dalam alat akses basis data tingkat rendah, misalnya beberapa variasi
hash_map get_record( string id_value, string table_name, string id_column_name="id" )
metode sederhana, mudah, sederhana dan serupa (tentu saja, konsep dan keanggunan sangat bervariasi dengan bahasa yang digunakan).2) versi panjang: Dalam setiap proyek berbasis database di mana saya memiliki "kendali konseptual" atas berbagai hal, saya menghindari AR, dan itu bagus. Saya biasanya membangun arsitektur berlapis (Anda cepat atau lambat membagi perangkat lunak Anda dalam beberapa lapisan, setidaknya dalam proyek berukuran sedang hingga besar):
A1) database itu sendiri, tabel, relasi, bahkan beberapa logika jika DBMS memungkinkannya (MySQL juga sudah dewasa sekarang)
A2) sangat sering, ada lebih dari sekedar penyimpanan data: sistem file (gumpalan dalam database tidak selalu merupakan keputusan yang baik ...), sistem lama (bayangkan diri Anda "bagaimana" mereka akan diakses, banyak variasi yang mungkin .. tapi itu saja bukan itu intinya ...)
B) lapisan akses database (pada tingkat ini, metode alat, pembantu untuk dengan mudah mengakses data dalam database sangat diterima, tetapi AR tidak memberikan nilai apa pun di sini, kecuali beberapa gula sintaksis)
C) lapisan objek aplikasi: "objek aplikasi" terkadang berupa baris tabel sederhana dalam database, tetapi sebagian besar tetap merupakan objek gabungan , dan memiliki beberapa logika yang lebih tinggi, jadi menginvestasikan waktu dalam objek AR pada level ini jelas tidak berguna , membuang-buang waktu pembuat kode yang berharga, karena "nilai sebenarnya", "logika yang lebih tinggi" dari objek-objek itu perlu diimplementasikan di atas objek AR, bagaimanapun - dengan dan tanpa AR! Dan, misalnya, mengapa Anda ingin memiliki abstraksi "Objek entri log"? Kode logika aplikasi menulisnya, tetapi haruskah itu memiliki kemampuan untuk memperbarui atau menghapusnya? terdengar konyol, dan
App::Log("I am a log message")
beberapa besaran lebih mudah digunakan daripadale=new LogEntry(); le.time=now(); le.text="I am a log message"; le.Insert();
. Dan misalnya: menggunakan "Objek entri log" dalam tampilan log di aplikasi Anda akan berfungsi untuk 100, 1000, atau bahkan 10.000 baris log, tetapi cepat atau lambat Anda harus mengoptimalkan - dan saya yakin dalam banyak kasus, Anda hanya akan gunakan pernyataan SQL SELECT kecil yang indah itu dalam logika aplikasi Anda (yang benar-benar merusak ide AR ..), alih-alih menggabungkan pernyataan kecil itu dalam bingkai ide AR tetap yang kaku dengan banyak kode yang membungkus dan menyembunyikannya. Waktu yang Anda buang dengan menulis dan / atau membuat kode AR bisa diinvestasikan dalam antarmuka yang jauh lebih pintar untuk membaca daftar entri log (banyak, banyak cara, langit adalah batasnya). Pembuat kode harus berani menemukan abstraksi baru untuk mewujudkan logika aplikasinya yang sesuai dengan aplikasi yang dimaksudkan, dan tidak dengan bodohnya menerapkan kembali pola konyol, kedengarannya bagus pada pandangan pertama!D) logika aplikasi - mengimplementasikan logika objek yang berinteraksi dan membuat, menghapus, dan membuat daftar (!) Objek logika aplikasi (TIDAK, tugas-tugas tersebut jarang harus berlabuh di objek logika aplikasi itu sendiri: apakah selembar kertas di meja Anda memberi tahu Anda nama dan lokasi semua sheet lain di kantor Anda? lupakan metode "statis" untuk membuat daftar objek, itu konyol, kompromi buruk yang dibuat untuk membuat cara berpikir manusia cocok dengan [beberapa-tidak-semua-AR-framework-like -] berpikir AR)
E) antarmuka pengguna - yah, apa yang akan saya tulis di baris berikut sangat, sangat, sangat subjektif, tetapi menurut pengalaman saya, proyek yang dibangun di atas AR sering mengabaikan bagian UI dari aplikasi - waktu terbuang percuma untuk pembuatan abstraksi yang tidak jelas . Pada akhirnya, aplikasi semacam itu menyia-nyiakan banyak waktu pembuat kode dan terasa seperti aplikasi dari pembuat kode untuk pembuat kode, yang cenderung teknologi di dalam dan di luar. Para pembuat kode merasa baik (kerja keras akhirnya selesai, semuanya selesai dan benar, sesuai dengan konsep di atas kertas ...), dan pelanggan "hanya perlu belajar bahwa perlu seperti itu", karena itu "profesional" .. ok, maaf, saya ngelantur ;-)
Memang, memang, ini semua subjektif, tetapi ini pengalaman saya (Ruby on Rails tidak termasuk, mungkin berbeda, dan saya tidak memiliki pengalaman praktis dengan pendekatan itu).
Dalam proyek berbayar, saya sering mendengar permintaan untuk memulai dengan membuat beberapa objek "rekaman aktif" sebagai blok bangunan untuk logika aplikasi tingkat yang lebih tinggi. Dalam pengalaman saya, ini sering kali menyolokadalah semacam alasan bahwa pelanggan (perusahaan pengembang perangkat lunak dalam banyak kasus) tidak memiliki konsep yang baik, pandangan yang besar, gambaran tentang produk yang seharusnya. Pelanggan tersebut berpikir dalam bingkai yang kaku ("dalam proyek sepuluh tahun yang lalu ini bekerja dengan baik .."), mereka dapat menyempurnakan entitas, mereka dapat mendefinisikan relasi entitas, mereka dapat memecah hubungan data dan mendefinisikan logika aplikasi dasar, tetapi kemudian mereka berhenti dan menyerahkannya kepada Anda, dan berpikir hanya itu yang Anda butuhkan ... mereka sering kali tidak memiliki konsep yang lengkap tentang logika aplikasi, antarmuka pengguna, kegunaan, dan seterusnya ... mereka tidak memiliki pandangan yang besar dan mereka kurang menyukai detailnya, dan mereka ingin Anda mengikuti cara AR itu, karena .. yah, mengapa, itu berhasil dalam proyek itu bertahun-tahun yang lalu, itu membuat orang sibuk dan diam? Saya tidak tahu. Tapi "detail" pisahkan laki-laki dari laki-laki, atau .. bagaimana slogan iklan aslinya? ;-)
Setelah bertahun-tahun (sepuluh tahun pengalaman pengembangan aktif), setiap kali pelanggan menyebutkan "pola rekaman aktif", bel alarm saya berdering. Saya belajar untuk mencoba membawa mereka kembali ke fase konsepsi yang penting , membiarkan mereka berpikir dua kali, mencoba mereka untuk menunjukkan kelemahan konseptional mereka atau hanya menghindarinya sama sekali jika mereka tidak mengerti (pada akhirnya, Anda tahu, pelanggan yang belum tahu apa yang diinginkannya, bahkan mungkin berpikir dia tahu tetapi tidak, atau mencoba untuk mengeluarkan konsep kerja kepadaKU secara gratis, menghabiskan banyak waktu, hari, minggu dan bulan yang berharga untuk waktu saya, hidup terlalu singkat ...).
Jadi, akhirnya: INI SEMUA adalah mengapa saya benci "pola rekaman aktif" konyol itu, dan saya lakukan dan akan menghindarinya bila memungkinkan.
EDIT : Saya bahkan akan menyebut ini Tanpa Pola. Itu tidak menyelesaikan masalah apa pun (pola tidak dimaksudkan untuk membuat gula sintaksis). Ini menciptakan banyak masalah: akar dari semua masalahnya (disebutkan dalam banyak jawaban di sini ..) adalah, bahwa ia hanya menyembunyikan SQL lama yang dikembangkan dengan baik dan kuat di belakang antarmuka yang menurut definisi pola sangat terbatas.
Pola ini menggantikan fleksibilitas dengan gula sintaksis!
Coba pikirkan, masalah apa yang dipecahkan AR untuk Anda?
sumber
before_save
callback yang masuk akal untuk menjaga konsistensi dalam catatan 4)after_commit
hook untuk pemicu layanan eksternal. 5) DSL yang baik untuk mengatur perubahan DDL ke dalam set perubahan (migrasi). (Masih ada rasa sakit di sana tetapi tidak memiliki pola lebih buruk ketika> 1 pengembang.)Beberapa pesan membuat saya bingung. Beberapa jawaban akan menjadi "ORM" vs "SQL" atau sesuatu seperti itu.
Faktanya adalah bahwa AR hanyalah pola pemrograman penyederhanaan di mana Anda memanfaatkan objek domain Anda untuk menulis kode akses database di sana.
Objek ini biasanya memiliki atribut bisnis (properti kacang) dan beberapa perilaku (metode yang biasanya bekerja pada properti ini).
AR hanya mengatakan "tambahkan beberapa metode ke objek domain ini" ke tugas terkait database.
Dan saya harus mengatakan, dari pendapat dan pengalaman saya, bahwa saya tidak suka polanya.
Pada pandangan pertama kedengarannya cukup bagus. Beberapa alat Java modern seperti Spring Roo menggunakan pola ini.
Bagi saya, masalah sebenarnya hanya pada masalah OOP. Pola AR memaksa Anda dalam beberapa cara untuk menambahkan ketergantungan dari objek Anda ke objek infrastruktur. Objek infrastruktur ini memungkinkan objek domain melakukan kueri database melalui metode yang disarankan oleh AR.
Saya selalu mengatakan bahwa dua lapisan adalah kunci keberhasilan sebuah proyek. Lapisan layanan (tempat logika bisnis berada atau dapat diekspor melalui beberapa jenis teknologi remote, seperti Layanan Web, misalnya) dan lapisan domain. Menurut pendapat saya, jika kita menambahkan beberapa dependensi (tidak terlalu diperlukan) ke objek lapisan domain untuk menyelesaikan pola AR, objek domain kita akan lebih sulit untuk dibagikan dengan lapisan lain atau (jarang) aplikasi eksternal.
Implementasi Spring Roo dari AR menarik, karena tidak bergantung pada objek itu sendiri, tetapi pada beberapa file AspectJ. Tetapi jika nanti Anda tidak ingin bekerja dengan Roo dan harus melakukan refaktorisasi proyek, metode AR akan diterapkan secara langsung di objek domain Anda.
Sudut pandang lain. Bayangkan kita tidak menggunakan Database Relasional untuk menyimpan objek kita. Bayangkan aplikasi menyimpan objek domain kita dalam Database NoSQL atau hanya dalam file XML, misalnya. Apakah kita akan mengimplementasikan metode yang melakukan tugas ini di objek domain kita? Saya rasa tidak (misalnya, dalam kasus XM, kami akan menambahkan dependensi terkait XML ke objek domain kami ... Sungguh menyedihkan menurut saya). Lalu mengapa kita harus mengimplementasikan metode DB relasional di objek domain, seperti yang dikatakan pola Ar?
Singkatnya, pola AR bisa terdengar lebih sederhana dan bagus untuk aplikasi kecil dan sederhana. Namun, ketika kami memiliki aplikasi yang kompleks dan besar, saya pikir arsitektur berlapis klasik adalah pendekatan yang lebih baik.
sumber
Pertanyaan asli ditandai dengan rel dan mengacu pada Twitter yang dibangun di Ruby on Rails. Kerangka kerja ActiveRecord dalam Rails adalah implementasi pola desain Rekaman Aktif Fowler.
sumber
Hal utama yang saya lihat berkenaan dengan keluhan tentang Rekaman Aktif adalah ketika Anda membuat model di sekitar tabel, dan Anda memilih beberapa contoh model, pada dasarnya Anda melakukan "pilih * dari ...". Ini bagus untuk mengedit rekaman atau menampilkan rekaman, tetapi jika Anda ingin, misalnya, menampilkan daftar kota untuk semua kontak dalam database Anda, Anda dapat melakukan "pilih Kota dari ..." dan hanya mendapatkan kota . Melakukan ini dengan Rekaman Aktif akan mengharuskan Anda memilih semua kolom, tetapi hanya menggunakan Kota.
Tentu saja, berbagai implementasi akan menangani hal ini secara berbeda. Namun demikian, itu satu masalah.
Sekarang, Anda dapat menyiasatinya dengan membuat model baru untuk hal spesifik yang coba Anda lakukan, tetapi beberapa orang akan berpendapat bahwa ini lebih merupakan upaya daripada manfaat.
Saya, saya menggali Rekaman Aktif. :-)
HTH
sumber
Saya suka cara SubSonic melakukan satu kolom saja.
Antara
, atau:
Tapi Linq masih menjadi raja dalam hal lazy loading.
sumber
@BlaM: Kadang-kadang saya baru saja menerapkan catatan aktif sebagai hasil dari bergabung. Tidak selalu harus relasi Tabel <--> Rekaman Aktif. Mengapa bukan "Hasil dari pernyataan Gabung" <--> Rekaman Aktif?
sumber
Saya akan berbicara tentang Rekaman Aktif sebagai pola desain, saya belum melihat ROR.
Beberapa pengembang membenci Rekaman Aktif, karena mereka membaca buku pintar tentang menulis kode yang bersih dan rapi, dan buku-buku ini menyatakan bahwa catatan aktif melanggar prinsip tanggung jawab tunggal, melanggar aturan DDD bahwa objek domain harus terus-menerus bodoh, dan banyak aturan lain dari buku semacam ini .
Objek domain hal kedua dalam Rekaman Aktif cenderung 1-to-1 dengan database, yang mungkin dianggap sebagai batasan dalam beberapa jenis sistem (kebanyakan n-tier).
Itu hanya hal-hal abstrak, saya belum melihat ruby di rel implementasi sebenarnya dari pola ini.
sumber
Masalah yang saya lihat dengan Rekaman Aktif adalah, selalu hanya tentang satu tabel. Tidak apa-apa, selama Anda benar-benar bekerja hanya dengan satu tabel itu, tetapi ketika Anda bekerja dengan data dalam banyak kasus, Anda akan memiliki semacam gabungan di suatu tempat.
Ya, bergabung biasanya lebih buruk daripada tidak bergabung sama sekali dalam hal kinerja, tetapi bergabung biasanya lebih baik daripada "palsu" bergabung dengan terlebih dahulu membaca seluruh tabel A dan kemudian menggunakan informasi yang diperoleh untuk membaca dan memfilter tabel B.
sumber
Masalah dengan ActiveRecord adalah bahwa kueri yang dibuatnya secara otomatis untuk Anda dapat menyebabkan masalah kinerja.
Anda akhirnya melakukan beberapa trik yang tidak intuitif untuk mengoptimalkan kueri yang membuat Anda bertanya-tanya apakah akan lebih efektif waktu untuk menulis kueri secara manual.
sumber
Meskipun semua komentar lain tentang pengoptimalan SQL pasti valid, keluhan utama saya dengan pola rekaman aktif adalah biasanya menyebabkan ketidakcocokan impedansi . Saya suka menjaga domain saya tetap bersih dan terenkapsulasi dengan benar, yang pola rekaman aktif biasanya menghancurkan semua harapan untuk melakukannya.
sumber
Coba lakukan hubungan polimorfik banyak ke banyak. Tidak begitu mudah. Terutama jika Anda tidak sedang menggunakan IMS.
sumber