Một số nguyên tắc cần lưu ý khi lập trình Ruby on Rails
Bài đăng này đã không được cập nhật trong 7 năm
Trong bài viết này, mình xin giới thiệu các bạn một số nguyên tắc để áp dụng trong khi xây dựng ứng dụng web với Ruby on Rails. Khi mình xây dựng ứng dụng của mình tốt, nó sẽ mang những lợi như sau:
- Dễ dàng bảo trì (Maintainability)
- Dễ đọc (Readability)
- Elegance
- Phát triển nhanh hơn (Faster development)
- DRY code
Two Space Indentation
Đây là nguyên tắc viết rộng rãi nhất và thoả thuận trong cộng đồng Ruby. Hãy sử dụng 2 space indentation thay cho 4 space identation. 4 space indentation
def some_method
some_var = true
if some_var
do_something
else
do_something_else
end
end
2 spaces indentation
def some_method
some_var = true
if some_var
do_something
else
do_something_else
end
end
Define Predicate Methods with a ?
Các method nào mà trả về true
hoặc false
, theo convention tốt nhất trong Ruby nên viết dấu ?
ở cuối với muc đích mang ý nghĩa dễ hiểu hơn. Đối với ngôn ngữ khác thì thường đặt tên như sau:
object.is_valid
object.is_paid
Nhưng trong Ruby hãy viết:
object.is_valid?
object.is_paid?
Iteration: Use each Instead of for
Đa số lập trình viên Ruby thương sử dụng each
thay cho for
trong vòng lặp vì nó sẽ làm cho code dể đọc, và dễ hiểu hơn.
for
for i in 1..100
...
end
each
(1..100).each do |i|
...
end
Conditionals: Use unless Instead of !if:
Hãy sử dụng unless
thay cho !if
với các câu phù định.
Không nên
if !true
do_this
end
or
if name != "sarmad"
do_that
end
Nên viết
unless true
do_this
end
or
unless name == "sarmad"
do_that
end
Nhưng nếu sử dụng với else
thì đừng sử dụng unless ... else
, hãy viết như sau:
Không nên
unless user.save
#throw error
else
#return success
end
Nên viết
if user.save
#return success
else
#throw error
end
DRY (Don’t Repeat Yourself)
Khi lập trình, hãy đảm bảo rằng bạn không lặp lại chính mình, tránh sự trùng lặp nhiều nhất có thể. 1. Use Abstract classes: Trước khi DRY:
class Mercedes
def accelerate
"60MPH in 5 seconds"
end
def apply_brakes
"stopped in 4 seconds"
end
def open_boot
"opened"
end
def turn_headlights_on
"turned on"
end
def turn_headlights_off
"turned off"
end
end
class Audi
def accelerate
"60MPH in 6.5 seconds"
end
def apply_brakes
"stopped in 3.5 seconds"
end
def open_boot
"opened"
end
def turn_headlights_on
"turned on"
end
def turn_headlights_off
"turned off"
end
end
Chúng ta thấy rằng có 3 methods trùng lặp open_boot
, turn_headlights_on
, and turn_headlights_off
.
Hãy viết lại như sau:
class Car
def open_boot
"opened"
end
def turn_headlights_on
"turned on"
end
def turn_headlights_off
"turned off"
end
end
class Mercedes < Car
def accelerate
"60MPH in 5 seconds"
end
def apply_brakes
"stopped in 4 seconds"
end
end
class Audi < Car
def accelerate
"60MPH in 6.5 seconds"
end
def apply_brakes
"stopped in 3.5 seconds"
end
end
2. Use Modules Chúng ta cũng có thể sử dụng Module để tránh sự trùng lặp, và để chia sẻ các trạng thái (Behavior) của module đó với các classes khác. Xem ví du sau:
class Newspaper
def headline
#code
end
def price
#code
end
end
class Book
def title
#code
end
def price
#code
end
def total_pages
#code
end
end
Nếu chúng ta muốn thêm một method print
trong classes trên và không trùng lặp, hãy sử dụng module như sau:
module Printable
def print
#code
end
end
Trong class trên phải thêm include
module đó là được:
class Newspaper
include Printable
.....
end
class Book
include Printable
.....
end
Smart Use of Enums
Gia sử chúng ta có model Book
mà có field muốn lưu trữ status là draft
, completed
hoặc published
. Chúng ta có thể viết:
if book.status == "draft"
do_something
elsif book.status == "completed"
do_something
elsif book.status == "published"
do_something
end
or
if book.status == 0 #draft
do_something
elsif book.status == 1 #completed
do_something
elsif book.status == 2 #published
do_something
end
Cách viết trên thì chưa tốt lắm. Để dễ dàng và để code readable hơn, hãy sử dụng emum
như sau:
Trong model Book
:
enum status: { draft: 0, completed: 1, published: 2 }
Chúng ta có thể viết ví dụ trên lại như sau:
if book.draft?
do_something
elsif book.completed?
do_something
elsif book.published?
do_something
end
Fat Models, Skinny Controllers and Concerns
Hãy nhớ một số nguyên tắc sau đây:
- Controllers nên chỉ thực hiện các queries đơn giản để gọi đến model. Đối với các queries hoặc logic phức tạp, hãy đưa chúng vào models. Controller nên chỉ dùng để handle các request và response.
- Các code mà không liên quan với response và request, hoặc liên quan trực tiếp với model nào đó, hãy đưa vào model.
- Việc sử lý logic hoặc queries phức tạp, và muốn dùng chung cho các model mà không muốn trùng lặp code, hãy đưa
app/models/concerns
directory. - Để xử lý các thảo tác cũng như các logic phức tạp (không liên quan trực tiếp đến model nào đó) như: thảo tác: send sms or email, subscribe or push notifications, ...., hãy đưa chúng vào
app/services/
directory.
Internationalization/Localization
Cách tốt nhất nên sử dụng I18n để xử lý các ngôn ngữ khác nhau trong ứng dụng web của bạn ngay từ khi bắt đầu project nào đó. Không nên:
<h1>Books Listing</h1>
<table>
<thead>
<th>Name</th>
<th>Author</th>
</thead>
<tbody>
<td> Some book </td>
<td> Some author </td>
</tbody>
</table
Nên viết:
<h1><%= t('.title') %></h1>
<table>
<thead>
<th><%= t('.name') %></th>
<th><%= t('.author') %></th>
</thead>
<tbody>
<td> Some book </td>
<td> Some author </td>
</tbody>
</table>
file .yml:
en:
title: "Books Listing"
name: "Name"
author: "Author
Use Time.zone.now Instead of Time.now
Date.today
và Time.now
: sử dụng date và time của máy ứng đụng đang chạy. Còn Time.zone.now
và Time.zone.toda
y sử dụng timezone, date và time dựa vào cách config của bạn trong ứng dụng.
# config/application.rb:
config.time_zone = ‘Eastern Time (US & Canada)'`.
Don’t Put Too Much Logic in Views
View là sử dụng để hiển thị, không phải là để xử lý các logic. Vây, nên tách các logic ra khỏi view và đưa các logic đó vào trong helper
hoặc sử dụng decorator
.
Không nên:
<% if book.published? && book.published_at > 1.weeks.ago %>
<span>Recently added</span>
<% end %>
Nên viết:
# Đưa logic kiểm tra vào helper
module ApplicationHelper
def recently_added?(book)
book.published? && book.published_at > 1.weeks.ago
end
end
# Và gọi trong view như sau
<% if recently_added?(book) %>
<span>Recently added</span>
<% end %>
Conclusion
Đây là một số các nguyên tắc cơ bản cần nhớ và lưu ý khi lâp trình Ruby on Rails, và còn nhiều các nguyên tắc nữa, mình sẽ trinh bày trong bài tiếp theo. Mong rằng bài viết này sẽ giúp các bạn viết code một cách hiệu quả và tốt hơn.
References: http://rails-bestpractices.com/ https://www.sitepoint.com/10-ruby-on-rails-best-practices-3/
All rights reserved