Kode Buggy Rails: 10 Kesalahan Paling Umum yang Dilakukan Pengembang Rails
Diterbitkan: 2022-03-11Ruby on Rails (“Rails”) adalah kerangka kerja open source yang populer, berdasarkan bahasa pemrograman Ruby yang berusaha untuk menyederhanakan dan merampingkan proses pengembangan aplikasi web.
Rel dibangun berdasarkan prinsip konvensi di atas konfigurasi. Sederhananya, ini berarti bahwa, secara default, Rails mengasumsikan bahwa pengembang ahlinya akan mengikuti konvensi praktik terbaik "standar" (untuk hal-hal seperti penamaan, struktur kode, dan sebagainya) dan, jika Anda melakukannya, semuanya akan bekerja untuk Anda "otomatis -magically” tanpa Anda perlu menentukan detail ini. Sementara paradigma ini memiliki kelebihan, juga bukan tanpa jebakan. Terutama, "keajaiban" yang terjadi di balik layar dalam kerangka terkadang dapat menyebabkan pemalsuan kepala, kebingungan, dan "apa yang sedang terjadi?" jenis masalah. Ini juga dapat memiliki konsekuensi yang tidak diinginkan berkaitan dengan keamanan dan kinerja.
Oleh karena itu, meskipun Rails mudah digunakan, namun juga tidak sulit untuk disalahgunakan. Tutorial ini membahas 10 masalah umum Rails, termasuk cara menghindarinya dan masalah yang ditimbulkannya.
Kesalahan Umum #1: Menempatkan terlalu banyak logika di pengontrol
Rails didasarkan pada arsitektur MVC. Dalam komunitas Rails, kami telah berbicara tentang model gemuk, pengontrol kurus untuk sementara waktu sekarang, namun beberapa aplikasi Rails baru-baru ini yang saya warisi melanggar prinsip ini. Terlalu mudah untuk memindahkan logika tampilan (yang lebih baik ditempatkan di pembantu), atau logika domain/model, ke pengontrol.
Masalahnya adalah bahwa objek pengontrol akan mulai melanggar prinsip tanggung jawab tunggal yang membuat perubahan di masa mendatang pada basis kode menjadi sulit dan rawan kesalahan. Secara umum, satu- satunya jenis logika yang harus Anda miliki di pengontrol Anda adalah:
- Sesi dan penanganan cookie. Ini mungkin juga termasuk otentikasi/otorisasi atau pemrosesan cookie tambahan yang perlu Anda lakukan.
- Pemilihan model. Logika untuk menemukan objek model yang tepat mengingat parameter yang diteruskan dari permintaan. Idealnya ini harus menjadi panggilan ke metode find tunggal yang mengatur variabel instan untuk digunakan nanti untuk membuat respons.
- Permintaan manajemen parameter. Mengumpulkan parameter permintaan dan memanggil metode model yang sesuai untuk mempertahankannya.
- Rendering/pengalihan. Merender hasil (html, xml, json, dll.) atau mengarahkan ulang, sebagaimana mestinya.
Meskipun ini masih mendorong batas prinsip tanggung jawab tunggal, ini adalah semacam minimum yang harus dimiliki oleh kerangka kerja Rails di controller.
Kesalahan Umum #2: Menempatkan terlalu banyak logika dalam tampilan
Mesin templating Rails yang out-of-the-box, ERB, adalah cara yang bagus untuk membangun halaman dengan konten variabel. Namun, jika Anda tidak hati-hati, Anda dapat segera berakhir dengan file besar yang merupakan campuran kode HTML dan Ruby yang sulit untuk dikelola dan dipelihara. Ini juga merupakan area yang dapat menyebabkan banyak pengulangan, yang mengarah pada pelanggaran prinsip KERING (jangan ulangi sendiri).
Ini dapat memanifestasikan dirinya dalam beberapa cara. Salah satunya adalah penggunaan logika kondisional yang berlebihan dalam pandangan. Sebagai contoh sederhana, pertimbangkan kasus di mana kami memiliki metode current_user
tersedia yang mengembalikan pengguna yang saat ini masuk. Seringkali, akan ada struktur logika kondisional seperti ini dalam file tampilan:
<h3> Welcome, <% if current_user %> <%= current_user.name %> <% else %> Guest <% end %> </h3>
Cara yang lebih baik untuk menangani sesuatu seperti ini adalah memastikan objek yang dikembalikan oleh current_user
selalu disetel, apakah seseorang masuk atau tidak, dan itu menjawab metode yang digunakan dalam tampilan dengan cara yang wajar (kadang-kadang disebut sebagai null obyek). Misalnya, Anda dapat mendefinisikan pembantu current_user
di app/controllers/application_controller
seperti ini:
require 'ostruct' helper_method :current_user def current_user @current_user ||= User.find session[:user_id] if session[:user_id] if @current_user @current_user else OpenStruct.new(name: 'Guest') end end
Ini kemudian akan memungkinkan Anda untuk mengganti contoh kode tampilan sebelumnya dengan satu baris kode sederhana ini:
<h3>Welcome, <%= current_user.name -%></h3>
Beberapa praktik terbaik Rails tambahan yang direkomendasikan:
- Gunakan tata letak tampilan dan sebagian dengan tepat untuk merangkum hal-hal yang berulang di halaman Anda.
- Gunakan presenter/dekorator seperti permata Draper untuk merangkum logika pembangunan tampilan dalam objek Ruby. Anda kemudian dapat menambahkan metode ke dalam objek ini untuk melakukan operasi logis yang mungkin telah Anda masukkan ke dalam kode tampilan Anda.
Kesalahan Umum #3: Menempatkan terlalu banyak logika dalam model
Diberikan panduan untuk meminimalkan logika dalam tampilan dan pengontrol, satu-satunya tempat yang tersisa dalam arsitektur MVC untuk meletakkan semua logika itu adalah di model, bukan?
Yah, tidak cukup.
Banyak pengembang Rails benar-benar membuat kesalahan ini dan akhirnya menempelkan semuanya di kelas model ActiveRecord
mereka yang mengarah ke file mongo yang tidak hanya melanggar prinsip tanggung jawab tunggal tetapi juga merupakan mimpi buruk pemeliharaan.
Fungsionalitas seperti menghasilkan pemberitahuan email, antarmuka ke layanan eksternal, mengonversi ke format data lain dan sejenisnya tidak banyak berhubungan dengan tanggung jawab inti model ActiveRecord
yang seharusnya melakukan sedikit lebih banyak daripada menemukan dan menyimpan data dalam database.
Jadi, jika logika tidak harus masuk ke tampilan, dan tidak harus masuk ke pengontrol, dan tidak harus masuk ke model, lalu, ke mana harus pergi?
Masukkan objek Ruby lama biasa (PORO). Dengan kerangka kerja yang komprehensif seperti Rails, pengembang baru sering kali enggan untuk membuat kelas mereka sendiri di luar kerangka kerja. Namun, memindahkan logika dari model ke PORO sering kali merupakan perintah dokter untuk menghindari model yang terlalu rumit. Dengan PORO, Anda dapat merangkum hal-hal seperti notifikasi email atau interaksi API ke dalam kelasnya sendiri daripada memasukkannya ke dalam model ActiveRecord
.
Jadi dengan mengingat hal itu, secara umum, satu-satunya logika yang harus tetap ada dalam model Anda adalah:
- Konfigurasi
ActiveRecord
(yaitu, relasi dan validasi) - Metode mutasi sederhana untuk merangkum pembaruan beberapa atribut dan menyimpannya di database
- Access wrapper untuk menyembunyikan informasi model internal (misalnya, metode
full_name
yang menggabungkanfirst_name
danlast_name
dalam database) - Kueri canggih (yaitu, yang lebih kompleks daripada
find
sederhana); secara umum, Anda tidak boleh menggunakan metodewhere
, atau metode pembuatan kueri lainnya seperti itu, di luar kelas model itu sendiri
Kesalahan Umum #4: Menggunakan kelas pembantu umum sebagai tempat pembuangan
Kesalahan ini benar-benar semacam akibat wajar dari kesalahan #3 di atas. Seperti yang telah dibahas, kerangka kerja Rails menekankan pada komponen bernama (yaitu, model, tampilan, dan pengontrol) dari kerangka kerja MVC. Ada definisi yang cukup baik tentang jenis hal yang termasuk dalam kelas masing-masing komponen ini, tetapi terkadang kita mungkin memerlukan metode yang tampaknya tidak cocok dengan salah satu dari ketiganya.
Generator Rails dengan mudah membangun direktori helper dan kelas helper baru untuk digunakan dengan setiap sumber daya baru yang kami buat. Namun, menjadi terlalu menggoda untuk mulai memasukkan fungsionalitas apa pun yang tidak secara formal cocok dengan model, tampilan, atau pengontrol ke dalam kelas pembantu ini.
Sementara Rails tentu saja MVC-sentris, tidak ada yang mencegah Anda membuat jenis kelas Anda sendiri dan menambahkan direktori yang sesuai untuk menyimpan kode untuk kelas tersebut. Saat Anda memiliki fungsionalitas tambahan, pikirkan tentang metode mana yang dikelompokkan bersama dan temukan nama yang bagus untuk kelas yang menyimpan metode tersebut. Menggunakan kerangka kerja yang komprehensif seperti Rails bukanlah alasan untuk membiarkan praktik terbaik desain berorientasi objek yang baik berlalu begitu saja.
Kesalahan Umum #5: Menggunakan terlalu banyak permata
Ruby dan Rails didukung oleh ekosistem permata yang kaya yang secara kolektif menyediakan hampir semua kemampuan yang dapat dipikirkan oleh pengembang. Ini bagus untuk membangun aplikasi yang kompleks dengan cepat, tetapi saya juga melihat banyak aplikasi yang membengkak di mana jumlah permata dalam Gemfile
aplikasi sangat besar jika dibandingkan dengan fungsionalitas yang disediakan.
Ini menyebabkan beberapa masalah Rails. Penggunaan permata yang berlebihan membuat ukuran proses Rails lebih besar dari yang seharusnya. Hal ini dapat memperlambat kinerja dalam produksi. Selain frustrasi pengguna, ini juga dapat mengakibatkan kebutuhan akan konfigurasi memori server yang lebih besar dan peningkatan biaya pengoperasian. Ini juga membutuhkan waktu lebih lama untuk memulai aplikasi Rails yang lebih besar, yang membuat pengembangan lebih lambat dan membuat pengujian otomatis memakan waktu lebih lama (dan sebagai aturan, pengujian lambat tidak sering dijalankan).
Ingatlah bahwa setiap permata yang Anda bawa ke dalam aplikasi Anda mungkin pada gilirannya memiliki ketergantungan pada permata lain, dan permata itu pada gilirannya mungkin memiliki ketergantungan pada permata lain, dan seterusnya. Menambahkan permata lain dengan demikian dapat memiliki efek peracikan. Misalnya, menambahkan permata rails_admin
akan menghasilkan total 11 permata lagi, lebih dari 10% peningkatan dari instalasi Rails dasar.
Pada tulisan ini, instalasi Rails 4.1.0 yang baru menyertakan 43 permata di file Gemfile.lock
. Ini jelas lebih dari yang disertakan dalam Gemfile
dan mewakili semua permata yang dibawa oleh segelintir permata Rails standar sebagai dependensi.
Pertimbangkan dengan cermat apakah biaya tambahan tersebut bermanfaat saat Anda menambahkan setiap permata. Sebagai contoh, pengembang sering kali dengan santai menambahkan permata rails_admin
karena pada dasarnya menyediakan front-end web yang bagus untuk struktur model, tetapi sebenarnya tidak lebih dari sekadar alat penjelajahan basis data yang mewah. Bahkan jika aplikasi Anda memerlukan pengguna admin dengan hak istimewa tambahan, Anda mungkin tidak ingin memberi mereka akses database mentah dan Anda akan lebih baik dilayani dengan mengembangkan fungsi administrasi Anda sendiri yang lebih efisien daripada dengan menambahkan permata ini.
Kesalahan Umum #6: Mengabaikan file log Anda
Sementara sebagian besar pengembang Rails mengetahui file log default yang tersedia selama pengembangan dan produksi, mereka sering tidak cukup memperhatikan informasi dalam file tersebut. Sementara banyak aplikasi mengandalkan alat pemantauan log seperti Honeybadger atau New Relic dalam produksi, penting juga untuk mengawasi file log Anda selama proses pengembangan dan pengujian aplikasi Anda.

Seperti yang disebutkan sebelumnya dalam tutorial ini, kerangka kerja Rails melakukan banyak "keajaiban" untuk Anda, terutama dalam model. Mendefinisikan asosiasi dalam model Anda membuatnya sangat mudah untuk menarik hubungan dan memiliki semua yang tersedia untuk pandangan Anda. Semua SQL yang diperlukan untuk mengisi objek model Anda dibuat untuk Anda. Itu keren. Tetapi bagaimana Anda tahu bahwa SQL yang dihasilkan efisien?
Salah satu contoh yang sering Anda temui disebut masalah kueri N+1. Meskipun masalahnya dipahami dengan baik, satu-satunya cara nyata untuk mengamatinya adalah dengan meninjau kueri SQL di file log Anda.
Katakanlah misalnya Anda memiliki kueri berikut dalam aplikasi blog biasa di mana Anda akan menampilkan semua komentar untuk satu set posting terpilih:
def comments_for_top_three_posts posts = Post.limit(3) posts.flat_map do |post| post.comments.to_a end end
Saat kita melihat file log dari permintaan yang memanggil metode ini, kita akan melihat sesuatu seperti berikut ini, di mana satu kueri dibuat untuk mendapatkan tiga objek posting kemudian tiga kueri lagi dibuat untuk mendapatkan masing-masing komentar objek tersebut:
Started GET "/posts/some_comments" for 127.0.0.1 at 2014-05-20 20:05:13 -0700 Processing by PostsController#some_comments as HTML Post Load (0.4ms) SELECT "posts".* FROM "posts" LIMIT 3 Comment Load (5.6ms) ELECT "comments".* FROM "comments" WHERE "comments"."post_id" = ? [["post_id", 1]] Comment Load (0.4ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = ? [["post_id", 2]] Comment Load (1.5ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = ? [["post_id", 3]] Rendered posts/some_comments.html.erb within layouts/application (12.5ms) Completed 200 OK in 581ms (Views: 225.8ms | ActiveRecord: 10.0ms)
Kemampuan pemuatan bersemangat ActiveRecord
di Rails memungkinkan untuk secara signifikan mengurangi jumlah kueri dengan membiarkan Anda menentukan terlebih dahulu semua asosiasi yang akan dimuat. Ini dilakukan dengan memanggil metode includes
(atau preload
) pada objek Arel ( ActiveRecord::Relation
) yang sedang dibangun. Dengan includes
, ActiveRecord
memastikan bahwa semua asosiasi yang ditentukan dimuat menggunakan jumlah kueri seminimal mungkin; misalnya:
def comments_for_top_three_posts posts = Post.includes(:comments).limit(3) posts.flat_map do |post| post.comments.to_a end end
Ketika kode yang direvisi di atas dijalankan, kita melihat di file log bahwa semua komentar dikumpulkan dalam satu kueri, bukan tiga:
Started GET "/posts/some_comments" for 127.0.0.1 at 2014-05-20 20:05:18 -0700 Processing by PostsController#some_comments as HTML Post Load (0.5ms) SELECT "posts".* FROM "posts" LIMIT 3 Comment Load (4.4ms) SELECT "comments".* FROM "comments" WHERE"comments "."post_id" IN (1, 2, 3) Rendered posts/some_comments.html.erb within layouts/application (12.2ms) Completed 200 OK in 560ms (Views: 219.3ms | ActiveRecord: 5.0ms)
Jauh lebih efisien.
Solusi untuk masalah N+1 ini sebenarnya hanya dimaksudkan sebagai contoh dari jenis inefisiensi yang bisa ada "di bawah tenda" dalam aplikasi Anda jika Anda tidak memberikan perhatian yang memadai. Kesimpulannya di sini adalah Anda harus memeriksa pengembangan dan menguji file log selama pengembangan untuk memeriksa (dan mengatasi!) inefisiensi dalam kode yang membangun respons Anda.
Meninjau file log adalah cara yang bagus untuk mengetahui inefisiensi dalam kode Anda dan untuk memperbaikinya sebelum aplikasi Anda masuk ke produksi. Jika tidak, Anda mungkin tidak menyadari masalah kinerja Rails yang dihasilkan hingga sistem Anda ditayangkan, karena kumpulan data yang Anda gunakan dalam pengembangan dan pengujian kemungkinan akan jauh lebih kecil daripada dalam produksi. Jika Anda sedang mengerjakan aplikasi baru, bahkan set data produksi Anda mungkin dimulai dari yang kecil dan aplikasi Anda akan terlihat berjalan dengan baik. Namun, seiring bertambahnya dataset produksi Anda, masalah Rails seperti ini akan menyebabkan aplikasi Anda berjalan semakin lambat.
Jika Anda menemukan bahwa file log Anda tersumbat dengan banyak informasi yang tidak Anda perlukan, berikut adalah beberapa hal yang dapat Anda lakukan untuk membersihkannya (teknik di sana berfungsi untuk pengembangan serta log produksi).
Kesalahan Umum #7: Kurangnya tes otomatis
Ruby dan Rails menyediakan kemampuan pengujian otomatis yang kuat secara default. Banyak pengembang Rails menulis pengujian yang sangat canggih menggunakan gaya TDD dan BDD dan menggunakan kerangka pengujian yang lebih kuat dengan permata seperti rspec dan mentimun.
Terlepas dari betapa mudahnya menambahkan pengujian otomatis ke aplikasi Rails Anda, saya sangat terkejut dengan betapa banyak proyek yang saya warisi atau bergabung di mana secara harfiah tidak ada tes yang ditulis (atau paling baik, sangat sedikit) oleh sebelumnya tim pengembangan. Meskipun ada banyak perdebatan tentang seberapa komprehensif pengujian Anda, cukup jelas bahwa setidaknya beberapa pengujian otomatis harus ada untuk setiap aplikasi.
Sebagai aturan umum, setidaknya harus ada satu tes integrasi tingkat tinggi yang ditulis untuk setiap tindakan di pengontrol Anda. Di beberapa titik di masa depan, pengembang Rails lainnya kemungkinan besar ingin memperluas atau memodifikasi kode, atau meningkatkan versi Ruby atau Rails, dan kerangka pengujian ini akan memberi mereka cara yang jelas untuk memverifikasi bahwa fungsionalitas dasar aplikasi bekerja. Manfaat tambahan dari pendekatan ini adalah memberikan gambaran yang jelas kepada pengembang masa depan tentang koleksi lengkap fungsionalitas yang disediakan oleh aplikasi.
Kesalahan Umum #8: Memblokir panggilan ke layanan eksternal
Penyedia layanan Rails pihak ketiga biasanya membuatnya sangat mudah untuk mengintegrasikan layanan mereka ke dalam aplikasi Anda melalui permata yang membungkus API mereka. Tetapi apa yang terjadi jika layanan eksternal Anda padam atau mulai berjalan sangat lambat?
Untuk menghindari pemblokiran panggilan ini, daripada memanggil layanan ini secara langsung di aplikasi Rails Anda selama pemrosesan normal permintaan, Anda harus memindahkannya ke semacam layanan antrian pekerjaan latar belakang jika memungkinkan. Beberapa permata populer yang digunakan dalam aplikasi Rails untuk tujuan ini meliputi:
- Pekerjaan tertunda
- permintaan
- Sidekiq
Dalam kasus di mana tidak praktis atau tidak mungkin untuk mendelegasikan pemrosesan ke antrian pekerjaan latar belakang, maka Anda perlu memastikan bahwa aplikasi Anda memiliki penanganan kesalahan yang memadai dan ketentuan fail-over untuk situasi yang tak terhindarkan ketika layanan eksternal turun atau mengalami masalah . Anda juga harus menguji aplikasi Anda tanpa layanan eksternal (mungkin dengan menghapus server tempat aplikasi Anda aktif dari jaringan) untuk memverifikasi bahwa itu tidak menghasilkan konsekuensi yang tidak terduga.
Kesalahan Umum #9: Menikah dengan migrasi database yang ada
Mekanisme migrasi database Rails memungkinkan Anda membuat instruksi untuk menambah dan menghapus tabel dan baris database secara otomatis. Karena file yang berisi migrasi ini diberi nama secara berurutan, Anda dapat memutarnya kembali dari awal waktu untuk membawa database kosong ke skema yang sama dengan produksi. Oleh karena itu, ini adalah cara yang bagus untuk mengelola perubahan granular pada skema database aplikasi Anda dan menghindari masalah Rails.
Meskipun ini pasti bekerja dengan baik di awal proyek Anda, seiring berjalannya waktu, proses pembuatan basis data dapat memakan waktu cukup lama dan terkadang migrasi salah tempat, dimasukkan secara tidak berurutan, atau diperkenalkan dari aplikasi Rails lain menggunakan server basis data yang sama.
Rails membuat representasi skema Anda saat ini dalam file bernama db/schema.rb
(secara default) yang biasanya diperbarui saat migrasi database dijalankan. File schema.rb
bahkan dapat dibuat ketika tidak ada migrasi dengan menjalankan tugas rake db:schema:dump
. Kesalahan umum Rails adalah memeriksa migrasi baru ke repo sumber Anda tetapi bukan file schema.rb
yang diperbarui.
Ketika migrasi tidak terkendali dan membutuhkan waktu terlalu lama untuk dijalankan, atau tidak lagi membuat database dengan benar, pengembang tidak perlu takut untuk menghapus direktori migrasi lama, membuang skema baru, dan melanjutkan dari sana. Menyiapkan lingkungan pengembangan baru akan memerlukan rake db:schema:load
daripada rake db:migrate
yang diandalkan sebagian besar pengembang.
Beberapa dari masalah ini juga dibahas dalam Rails Guide.
Kesalahan Umum #10: Memeriksa informasi sensitif ke dalam repositori kode sumber
Kerangka kerja Rails memudahkan pembuatan aplikasi aman yang tahan terhadap berbagai jenis serangan. Beberapa di antaranya dilakukan dengan menggunakan token rahasia untuk mengamankan sesi dengan browser. Meskipun token ini sekarang disimpan di config/secrets.yml
, dan file itu membaca token dari variabel lingkungan untuk server produksi, versi Rails sebelumnya menyertakan token di config/initializers/secret_token.rb
. File ini sering keliru diperiksa ke dalam repositori kode sumber dengan aplikasi Anda yang lain dan, ketika ini terjadi, siapa pun yang memiliki akses ke repositori sekarang dapat dengan mudah membahayakan semua pengguna aplikasi Anda .
Oleh karena itu, Anda harus memastikan bahwa file konfigurasi repositori Anda (mis., .gitignore
untuk pengguna git) mengecualikan file dengan token Anda. Server produksi Anda kemudian dapat mengambil token mereka dari variabel lingkungan atau dari mekanisme seperti yang disediakan oleh permata dotenv.
Penutup Tutorial
Rails adalah kerangka kerja yang kuat yang menyembunyikan banyak detail jelek yang diperlukan untuk membangun aplikasi web yang kuat. Meskipun hal ini membuat pengembangan aplikasi web Rails jauh lebih cepat, pengembang harus memperhatikan potensi kesalahan desain dan pengkodean, untuk memastikan bahwa aplikasi mereka mudah dikembangkan dan dipelihara seiring pertumbuhannya.
Pengembang juga perlu menyadari masalah yang dapat membuat aplikasi mereka lebih lambat, kurang dapat diandalkan, dan kurang aman. Penting untuk mempelajari kerangka kerja dan memastikan bahwa Anda sepenuhnya memahami pengorbanan arsitektur, desain, dan pengkodean yang Anda buat selama proses pengembangan, untuk membantu memastikan aplikasi berkualitas tinggi dan berkinerja tinggi.