ActiveRecord vs. Ecto Bagian Dua

Ini adalah bagian kedua dari seri “ActiveRecord vs. Ecto”, di mana Batman dan Batgirl berebut database query dan kami membandingkan apel dan jeruk.

Setelah melihat skema basis data dan migrasi di ActiveRecord vs. Ecto bagian satu, postingan ini mencakup bagaimana ActiveRecord dan Ecto memungkinkan pengembang untuk menanyakan database, dan bagaimana membandingkan ActiveRecord dan Ecto ketika berhadapan dengan persyaratan yang sama. Sepanjang jalan, kita juga akan menemukan identitas Batgirl pada 1989-2011.

Data seed

Ayo mulai! Berdasarkan pada struktur basis data yang ditentukan pada posting pertama dari seri ini, anggap pengguna dan tabel faktur memiliki data berikut yang tersimpan di dalamnya:

pengguna

* Bidang create_at ActiveRecord dinamai dimasukkan_at di Ecto secara default.

faktur

* Bidang create_at ActiveRecord dinamai dimasukkan_at di Ecto secara default.

Pertanyaan yang dilakukan melalui pos ini mengasumsikan bahwa data di atas disimpan dalam database, jadi ingatlah informasi ini saat membacanya.

Temukan item menggunakan kunci utamanya

Mari kita mulai dengan mendapatkan catatan dari database menggunakan kunci utamanya.

ActiveRecord

irb (utama): 001: 0> User.find (1) Beban Pengguna (0.4ms) PILIH "pengguna". * DARI "pengguna" DI MANA "pengguna". "id" = $ 1 LIMIT $ 2 [["id", 1 ], ["LIMIT", 1]] => # 

Dll

iex (3)> Repo.get (Pengguna, 1)
[debug] QUERY OK source = "users" db = decode 5.2ms = 2.5ms antrian = 0.1ms
SELECT u0. "Id", u0. "Full_name", u0. "Email", u0. "Insert_at", u0. "Updated_at" DARI "pengguna" AS u0 WHERE (u0. "Id" = $ 1) [1]
% Financex.Accounts.User {
  __meta__: # Ecto.Schema.Metadata <: dimuat, "users">,
  email: "bette@kane.test",
  full_name: "Bette Kane",
  id: 1,
  dimasukkan_at: ~ N [2018-01-01 10: 01: 00.000000],
  faktur: # Ecto.Association.NotLoaded ,
  updated_at: ~ N [2018-01-01 10: 01: 00.000000]
}

Perbandingan

Kedua kasus sangat mirip. ActiveRecord bergantung pada metode kelas menemukan kelas model Pengguna. Ini berarti bahwa setiap kelas anak ActiveRecord memiliki metode find sendiri di dalamnya.

Ecto menggunakan pendekatan yang berbeda, dengan mengandalkan konsep Repositori sebagai mediator antara lapisan pemetaan dan domain. Saat menggunakan Ecto, modul Pengguna tidak memiliki pengetahuan tentang cara menemukan dirinya sendiri. Tanggung jawab tersebut ada dalam modul Repo, yang dapat memetakannya ke datastore di bawahnya, yang dalam kasus kami adalah Postgres.

Saat membandingkan kueri SQL itu sendiri, kami dapat menemukan beberapa perbedaan:

  • ActiveRecord memuat semua bidang (pengguna. *), Sementara Ecto hanya memuat bidang yang tercantum dalam definisi skema.
  • ActiveRecord menyertakan LIMIT 1 ke kueri, sedangkan Ecto tidak.

Mengambil semua item

Mari melangkah lebih jauh dan memuat semua pengguna dari basis data.

ActiveRecord

irb (utama): 001: 0> User.all User Load (0.5ms) PILIH "users". * DARI "users" LIMIT $ 1 [["LIMIT", 11]] => # , # , # , # ]>

Dll

iex (4)> Repo.all (Pengguna)
[debug] QUERY OK source = "users" db = 2.8ms decode = 0.2ms queue = 0.2ms
SELECT u0. "Id", u0. "Full_name", u0. "Email", u0. "Insert_at", u0. "Updated_at" DARI "pengguna" AS u0 []
[
  % Financex.Accounts.User {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "users">,
    email: "bette@kane.test",
    full_name: "Bette Kane",
    id: 1,
    dimasukkan_at: ~ N [2018-01-01 10: 01: 00.000000],
    faktur: # Ecto.Association.NotLoaded ,
    updated_at: ~ N [2018-01-01 10: 01: 00.000000]
  },
  % Financex.Accounts.User {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "users">,
    email: "barbara@gordon.test",
    full_name: "Barbara Gordon",
    id: 2,
    dimasukkan_at: ~ N [2018-01-02 10: 02: 00.000000],
    faktur: # Ecto.Association.NotLoaded ,
    updated_at: ~ N [2018-01-02 10: 02: 00.000000]
  },
  % Financex.Accounts.User {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "users">,
    email: "cassandra@cain.test",
    full_name: "Cassandra Cain",
    id: 3,
    dimasukkan_at: ~ N [2018-01-03 10: 03: 00.000000],
    faktur: # Ecto.Association.NotLoaded ,
    updated_at: ~ N [2018-01-03 10: 03: 00.000000]
  },
  % Financex.Accounts.User {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "users">,
    email: "stephanie@brown.test",
    full_name: "Stephanie Brown",
    id: 4,
    dimasukkan_at: ~ N [2018-01-04 10: 04: 00.000000],
    faktur: # Ecto.Association.NotLoaded ,
    updated_at: ~ N [2018-01-04 10: 04: 00.000000]
  }
]

Perbandingan

Ini mengikuti pola yang sama persis seperti bagian sebelumnya. ActiveRecord menggunakan metode semua kelas dan Ecto bergantung pada pola repositori untuk memuat catatan.

Ada lagi beberapa perbedaan dalam query SQL:

Pertanyaan dengan kondisi

Sangat tidak mungkin bahwa kita perlu mengambil semua catatan dari sebuah tabel. Kebutuhan umum adalah penggunaan kondisi, untuk menyaring data yang dikembalikan.

Mari kita gunakan contoh itu untuk mendaftar semua faktur yang masih harus dibayar (WHERE paid_at IS NULL).

ActiveRecord

irb (utama): 024: 0> Invoice.where (paid_at: nil) Beban Faktur (18.2ms) PILIH "faktur". * DARI "faktur" WHERE "faktur". "paid_at" IS NULL LIMIT $ 1 [[LIMIT "" , 11]] => # , # ]>

Dll

iex (19)> where (Faktur, [i], is_nil (i.paid_at)) |> Repo.all ()
[debug] QUERY OK sumber = "faktur" db = 20.2ms
SELECT i0. "Id", i0. "Payment_method", i0. "Paid_at", i0. "User_id", i0. "Insert_at", i0. "Updated_at" DARI "faktur" AS i0 WHERE (i0. "Paid_at" IS NULL) []
[
  % Financex.Accounts.Invoice {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
    id: 3,
    dimasukkan_at: ~ N [2018-01-04 08: 00: 00.000000],
    paid_at: nil,
    metode pembayaran: nihil,
    updated_at: ~ N [2018-01-04 08: 00: 00.000000],
    pengguna: # Ecto.Association.NotLoaded ,
    user_id: 3
  },
  % Financex.Accounts.Invoice {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
    id: 4,
    dimasukkan_at: ~ N [2018-01-04 08: 00: 00.000000],
    paid_at: nil,
    metode pembayaran: nihil,
    updated_at: ~ N [2018-01-04 08: 00: 00.000000],
    pengguna: # Ecto.Association.NotLoaded ,
    user_id: 4
  }
]

Perbandingan

Dalam kedua contoh, di mana kata kunci digunakan, yang merupakan koneksi ke klausa SQL WHERE. Meskipun query SQL yang dihasilkan sangat mirip, cara bagaimana kedua alat sampai di sana memiliki beberapa perbedaan penting.

ActiveRecord mengubah argumen paid_at: nil menjadi pernyataan SQL NULL IS NULL secara otomatis. Untuk mendapatkan output yang sama menggunakan Ecto, pengembang harus lebih eksplisit tentang maksudnya, dengan memanggil is_nil ().

Perbedaan lain yang disorot adalah perilaku "murni" dari fungsi di mana di Ecto. Saat memanggil fungsi di mana saja, itu tidak berinteraksi dengan basis data. Kembalinya fungsi where adalah struct Ecto.Query:

iex (20)> where (Faktur, [i], is_nil (i.paid_at))
# Ecto.Query 

Basis data hanya tersentuh ketika fungsi Repo.all () dipanggil, meneruskan struct Ecto.Query sebagai argumen. Pendekatan ini memungkinkan komposisi permintaan di Ecto, yang merupakan subjek dari bagian selanjutnya.

Komposisi permintaan

Salah satu aspek permintaan database yang paling kuat adalah komposisi. Itu menggambarkan permintaan dengan cara yang mengandung lebih dari satu kondisi.

Jika Anda membuat kueri SQL mentah, itu artinya Anda mungkin akan menggunakan semacam rangkaian. Bayangkan Anda memiliki dua kondisi:

  1. not_paid = 'paid_at IS NOT NULL'
  2. paid_with_paypal = 'payment_method = "Paypal"'

Untuk menggabungkan kedua kondisi menggunakan SQL mentah, berarti Anda harus menggabungkannya menggunakan sesuatu yang mirip dengan:

PILIH * DARI faktur DI MANA # {not_paid} DAN # {paid_with_paypal}

Untungnya ActiveRecord dan Ecto memiliki solusi untuk itu.

ActiveRecord

irb (utama): 003: 0> Invoice.where.not (paid_at: nil) .where (payment_method: "Paypal") Beban Faktur (8.0ms) PILIH "faktur". * DARI "faktur" DIMANA "faktur". " paid_at "BUKAN NULL DAN" faktur "." payment_method "= $ 1 LIMIT $ 2 [[" payment_method "," Paypal "], [" LIMIT ", 11]] => # ]>

Dll

iex (6)> Faktur |> di mana ([i], bukan is_nil (i.paid_at)) |> di mana ([i], i.payment_method == "Paypal") |> Repo.all ()
[debug] QUERY OK source = "invoice" db = 30.0ms decode = 0.6ms antrian = 0.2ms
SELECT i0. "Id", i0. "Payment_method", i0. "Paid_at", i0. "User_id", i0. "Insert_at", i0. "Updated_at" DARI "faktur" SEBAGAI i0 WHERE (TIDAK (i0. "Paid_at "IS NULL)) AND (i0." Payment_method "= 'Paypal') []
[
  % Financex.Accounts.Invoice {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
    id: 2,
    dimasukkan_at: ~ N [2018-01-03 08: 00: 00.000000],
    paid_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "Paypal",
    updated_at: ~ N [2018-01-03 08: 00: 00.000000],
    pengguna: # Ecto.Association.NotLoaded ,
    user_id: 2
  }
]

Perbandingan

Kedua pertanyaan menjawab pertanyaan yang sama: "Faktur mana yang dibayar dan digunakan Paypal?"

Seperti yang sudah diduga, ActiveRecord menawarkan cara yang lebih ringkas dalam menyusun kueri (untuk contoh itu), sementara Ecto mengharuskan pengembang untuk menghabiskan sedikit lebih banyak dalam menulis kueri. Seperti biasa, Batgirl (anak yatim, yang bisu dengan identitas Cassandra Cain) atau Activerecord tidak begitu bertele-tele.

Jangan tertipu oleh verbositas dan kompleksitas yang tampak dari permintaan Ecto yang ditunjukkan di atas. Di lingkungan dunia nyata, kueri itu akan ditulis ulang agar lebih mirip:

Faktur
|> di mana ([i], bukan is_nil (i.paid_at))
|> di mana ([i], i.payment_method == "Paypal")
|> Repo.all ()

Melihat dari sudut itu, kombinasi aspek “murni” dari fungsi di mana, yang tidak melakukan operasi basis data dengan sendirinya, dengan operator pipa, membuat komposisi kueri di Ecto benar-benar bersih.

Pemesanan

Pemesanan adalah aspek penting dari suatu permintaan. Ini memungkinkan pengembang untuk memastikan bahwa hasil kueri yang diberikan mengikuti pesanan yang ditentukan.

ActiveRecord

irb (utama): 002: 0> Invoice.order (Created_at:: desc) Beban Faktur (1.5ms) PILIH "faktur". * DARI "faktur" ORDER DENGAN "faktur". "Created_at" DESC LIMIT $ 1 [[LIMIT] ", 11]] => # , # , # , # ]>

Dll

iex (6)> order_by (Faktur, desc:: dimasukkan_at) |> Repo.all ()
[debug] QUERY OK sumber = "faktur" db = 19.8ms
SELECT i0. "Id", i0. "Payment_method", i0. "Paid_at", i0. "User_id", i0. "Insert_at", i0. "Updated_at" DARI "faktur" SEBAGAI OR0 ORDER OLEH i0. "Insert_at" DESC []
[
  % Financex.Accounts.Invoice {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
    id: 3,
    dimasukkan_at: ~ N [2018-01-04 08: 00: 00.000000],
    paid_at: nil,
    metode pembayaran: nihil,
    updated_at: ~ N [2018-01-04 08: 00: 00.000000],
    pengguna: # Ecto.Association.NotLoaded ,
    user_id: 3
  },
  % Financex.Accounts.Invoice {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
    id: 4,
    dimasukkan_at: ~ N [2018-01-04 08: 00: 00.000000],
    paid_at: nil,
    metode pembayaran: nihil,
    updated_at: ~ N [2018-01-04 08: 00: 00.000000],
    pengguna: # Ecto.Association.NotLoaded ,
    user_id: 4
  },
  % Financex.Accounts.Invoice {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
    id: 2,
    dimasukkan_at: ~ N [2018-01-03 08: 00: 00.000000],
    paid_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "Paypal",
    updated_at: ~ N [2018-01-03 08: 00: 00.000000],
    pengguna: # Ecto.Association.NotLoaded ,
    user_id: 2
  },
  % Financex.Accounts.Invoice {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
    id: 1,
    dimasukkan_at: ~ N [2018-01-02 08: 00: 00.000000],
    paid_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "Kartu Kredit",
    updated_at: ~ N [2018-01-02 08: 00: 00.000000],
    pengguna: # Ecto.Association.NotLoaded ,
    user_id: 1
  }
]

Perbandingan

Menambahkan urutan ke kueri langsung di kedua alat.

Meskipun contoh Ecto menggunakan Faktur sebagai parameter pertama, fungsi order_by juga menerima Ecto.Query structs, yang memungkinkan fungsi order_by digunakan dalam komposisi, seperti:

Faktur
|> di mana ([i], bukan is_nil (i.paid_at))
|> di mana ([i], i.payment_method == "Paypal")
|> order_by (desc:: dimasukkan_at)
|> Repo.all ()

Membatasi

Apa yang akan menjadi basis data tanpa batas? Sebuah bencana. Untungnya, ActiveRecord dan Ecto membantu membatasi jumlah rekaman yang dikembalikan.

ActiveRecord

irb (utama): 004: 0> Invoice.limit (2)
Beban Faktur (0,2 ms) PILIH "faktur". * DARI "faktur" LIMIT $ 1 [["BATAS", 2]]
=> # , # ]>

Dll

iex (22)> limit (Faktur, 2) |> Repo.all ()
[debug] QUERY OK sumber = "faktur" db = 3.6ms
SELECT i0. "Id", i0. "Payment_method", i0. "Paid_at", i0. "User_id", i0. "Insert_at", i0. "Updated_at" DARI "faktur" SEBAGAI i0 LIMIT 2 []
[
  % Financex.Accounts.Invoice {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
    id: 1,
    dimasukkan_at: ~ N [2018-01-02 08: 00: 00.000000],
    paid_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "Kartu Kredit",
    updated_at: ~ N [2018-01-02 08: 00: 00.000000],
    pengguna: # Ecto.Association.NotLoaded ,
    user_id: 1
  },
  % Financex.Accounts.Invoice {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
    id: 2,
    dimasukkan_at: ~ N [2018-01-03 08: 00: 00.000000],
    paid_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "Paypal",
    updated_at: ~ N [2018-01-03 08: 00: 00.000000],
    pengguna: # Ecto.Association.NotLoaded ,
    user_id: 2
  }
]

Perbandingan

ActiveRecord dan Ecto memiliki cara untuk membatasi jumlah catatan yang dikembalikan oleh permintaan.

Batas Ecto berfungsi serupa dengan order_by, cocok untuk komposisi kueri.

Asosiasi

ActiveRecord dan Ecto memiliki pendekatan yang berbeda dalam hal bagaimana asosiasi ditangani.

ActiveRecord

Di ActiveRecord, Anda dapat menggunakan asosiasi apa pun yang ditentukan dalam suatu model, tanpa harus melakukan sesuatu yang istimewa tentang itu, misalnya:

irb (utama): 012: 0> user = User.find (2) Beban Pengguna (0.3ms) PILIH "pengguna". * DARI "pengguna" DI MANA "pengguna". "id" = $ 1 LIMIT $ 2 [["id" , 2], ["LIMIT", 1]] => #  irb (utama): 013: 0> user.invoices Beban Faktur (0,4 ms) PILIH" faktur ". * DARI" faktur "DI MANA" faktur " . "user_id" = $ 1 LIMIT $ 2 [["user_id", 2], ["LIMIT", 11]] => # ] >

Contoh di atas menunjukkan bahwa kita bisa mendapatkan daftar faktur pengguna saat memanggil user.invoices. Saat melakukannya, ActiveRecord secara otomatis menanyakan database dan memuat faktur yang terkait dengan pengguna. Meskipun pendekatan ini membuat segalanya lebih mudah, dalam arti menulis lebih sedikit kode atau harus khawatir tentang langkah-langkah tambahan, mungkin menjadi masalah jika Anda mengulangi beberapa pengguna dan mengambil faktur untuk setiap pengguna. Masalah ini dikenal sebagai "masalah N + 1".

Dalam ActiveRecord, perbaikan yang diusulkan untuk "N + 1 masalah" adalah menggunakan metode include:

irb (utama): 022: 0> user = User.includes (: faktur) .find (2) Muatan Pengguna (0.3ms) PILIH "pengguna". * DARI "pengguna" DI MANA "pengguna". "id" = $ 1 LIMIT $ 2 [["id", 2], ["LIMIT", 1]] Beban Faktur (0,6 ms) PILIH "faktur". * DARI "faktur" WHERE "faktur". "User_id" = $ 1 [["user_id", 2]] => #  irb (utama): 023: 0> user.invoices => # ]>

Dalam hal ini, ActiveRecord ingin memuat asosiasi faktur saat mengambil pengguna (seperti yang terlihat dalam dua kueri SQL yang ditunjukkan).

Dll

Seperti yang mungkin sudah Anda perhatikan, Ecto benar-benar tidak menyukai sihir atau kesaksian. Ini membutuhkan pengembang untuk secara eksplisit tentang maksud mereka.

Mari kita coba pendekatan yang sama dalam menggunakan user.invoices dengan Ecto:

iex (7)> ​​user = Repo.get (Pengguna, 2)
[debug] QUERY OK source = "users" db = decode 18.3ms = 0.6ms
SELECT u0. "Id", u0. "Full_name", u0. "Email", u0. "Insert_at", u0. "Updated_at" DARI "pengguna" AS u0 WHERE (u0. "Id" = $ 1) [2]
% Financex.Accounts.User {
  __meta__: # Ecto.Schema.Metadata <: dimuat, "users">,
  email: "barbara@gordon.test",
  full_name: "Barbara Gordon",
  id: 2,
  dimasukkan_at: ~ N [2018-01-02 10: 02: 00.000000],
  faktur: # Ecto.Association.NotLoaded ,
  updated_at: ~ N [2018-01-02 10: 02: 00.000000]
}
iex (8)> user.invoices
# Ecto.Association.NotLoaded 

Hasilnya adalah Ecto.Association.NotLoaded. Tidak begitu berguna.

Untuk memiliki akses ke faktur, pengembang perlu memberi tahu Ecto tentang itu, menggunakan fungsi preload:

iex (12)> user = preload (Pengguna,: faktur) |> Repo.get (2)
[debug] QUERY OK source = "users" db = 11.8ms
SELECT u0. "Id", u0. "Full_name", u0. "Email", u0. "Insert_at", u0. "Updated_at" DARI "pengguna" AS u0 WHERE (u0. "Id" = $ 1) [2]
[debug] QUERY OK sumber = "faktur" db = 4.2ms
SELECT i0. "Id", i0. "Payment_method", i0. "Paid_at", i0. "User_id", i0. "Insert_at", i0. "Updated_at", i0. " i0. "user_id" = $ 1) PESANAN OLEH i0. "user_id" [2]
% Financex.Accounts.User {
  __meta__: # Ecto.Schema.Metadata <: dimuat, "users">,
  email: "barbara@gordon.test",
  full_name: "Barbara Gordon",
  id: 2,
  dimasukkan_at: ~ N [2018-01-02 10: 02: 00.000000],
  faktur: [
    % Financex.Accounts.Invoice {
      __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
      id: 2,
      dimasukkan_at: ~ N [2018-01-03 08: 00: 00.000000],
      paid_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
      payment_method: "Paypal",
      updated_at: ~ N [2018-01-03 08: 00: 00.000000],
      pengguna: # Ecto.Association.NotLoaded ,
      user_id: 2
    }
  ],
  updated_at: ~ N [2018-01-02 10: 02: 00.000000]
}

iex (15)> user.invoices
[
  % Financex.Accounts.Invoice {
    __meta__: # Ecto.Schema.Metadata <: dimuat, "invoice">,
    id: 2,
    dimasukkan_at: ~ N [2018-01-03 08: 00: 00.000000],
    paid_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "Paypal",
    updated_at: ~ N [2018-01-03 08: 00: 00.000000],
    pengguna: # Ecto.Association.NotLoaded ,
    user_id: 2
  }
]

Demikian pula untuk ActiveRecord, preload dengan mengambil faktur terkait, yang akan membuatnya tersedia saat memanggil user.invoices.

Perbandingan

Sekali lagi, pertempuran antara ActiveRecord dan Ecto berakhir dengan titik yang dikenal: explicitness. Kedua alat memungkinkan pengembang untuk dengan mudah mengakses asosiasi, tetapi sementara ActiveRecord membuatnya kurang bertele-tele, hasilnya mungkin memiliki perilaku tak terduga. Ecto mengikuti jenis pendekatan WYSIWYG, yang hanya melakukan apa yang terlihat dalam kueri yang ditentukan oleh pengembang.

Rails terkenal untuk menggunakan dan mempromosikan strategi caching ke semua lapisan aplikasi yang berbeda. Salah satu contoh adalah tentang menggunakan pendekatan caching "boneka Rusia", yang sepenuhnya bergantung pada "N + 1 masalah" untuk mekanisme caching untuk melakukan keajaibannya.

Validasi

Sebagian besar validasi hadir dalam ActiveRecord juga tersedia di Ecto. Berikut daftar validasi umum dan bagaimana ActiveRecord dan Ecto mendefinisikannya:

Bungkus

Itu dia: perbandingan antara apel esensial dan jeruk.

ActiveRecord berfokus pada kemudahan melakukan query basis data. Sebagian besar fitur-fiturnya terkonsentrasi pada kelas model itu sendiri, tidak mengharuskan pengembang untuk memiliki pemahaman yang mendalam tentang database, atau dampak dari operasi tersebut. ActiveRecord melakukan banyak hal secara implisit secara default. Meskipun itu membuatnya lebih mudah untuk memulai, itu membuatnya lebih sulit untuk memahami apa yang terjadi di balik layar dan itu hanya berfungsi jika Anda mengikuti "cara ActiveRecord".

Ecto, di sisi lain, membutuhkan saksi yang menghasilkan kode yang lebih bertele-tele. Sebagai manfaat, semuanya ada dalam sorotan, tidak ada di belakang layar, dan Anda dapat menentukan cara Anda sendiri.

Keduanya memiliki sisi atas tergantung pada perspektif dan preferensi Anda. Jadi setelah membandingkan apel dan jeruk, kita sampai pada akhir BAT-tle ini. Hampir lupa memberi tahu Anda nama kode BatGirl (1989–2001) adalah…. Peramal. Tapi mari kita tidak membahasnya.

Posting ini ditulis oleh penulis tamu Elvio Vicosa. Elvio adalah penulis buku Phoenix for Rails Developers.

Awalnya diterbitkan di blog.appsignal.com pada 9 Oktober 2018.