+3

Một số nguyên tắc cần lưu ý khi lập trình Ruby on Rails

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:

  1. Dễ dàng bảo trì (Maintainability)
  2. Dễ đọc (Readability)
  3. Elegance
  4. Phát triển nhanh hơn (Faster development)
  5. 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.todayTime.now: sử dụng date và time của máy ứng đụng đang chạy. Còn Time.zone.nowTime.zone.today 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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí