Viết code đẹp trong Ruby (Phần 1)

1. Giới thiệu

Như trên tiêu đề của bài viết thì hôm nay tôi sẽ giới thiệu tới các bạn một số qui tắc viết code đẹp trong Ruby. Đã có khá nhiều các bài viết trên các trang mạng nói về đề tài phong cách lập trình và tư duy viết code đẹp, hơn nữa vấn đề này cũng thuộc về phong cách lập trình của mỗi lập trình viên nhưng vẫn có những qui tắc chung trong giới coder để sao cho code dễ đọc, dễ viết và nhìn đẹp hơn. Sau đây tôi chỉ giới thiệu 15 qui tắc code trong ngôn ngữ Ruby cực kì kinh điển mà đôi khi lập trình viên không để ý nhưng nó lại cực kì quan trọng bởi vì nó đã được cả cộng đồng lập trình Ruby tuân theo. Để đạt được những qui tắc này thì cộng đồng lập đã trải qua một quá trình đấu tranh lâu dài để bài trừ những đoạn code xấu. Ở đây tôi sẽ tổng hợp lại và chia theo một số tiêu chí để các bạn dễ theo dõi. Và hãy nhớ đây chỉ là style trong code Ruby nhé!

2. Cách dùng khoảng trắng

  • KHÔNG DÙNG khoảng trắng sau (, [ và trước ], ). DÙNG khoảng trắng quanh { và trước } trừ trường hợp nhúng biến vào string
#bad
some( arg )
[ 1, 2, 3 ].each{|x| puts x}
{one: 1, two: 2}
"From: #{ user.first_name }, #{ user.last_name }"

#good
some(arg)
[1, 2, 3].each { |x| puts x }
{ one: 1, two: 2 }
"From: #{user.first_name}, #{user.last_name}"

Lưu ý đối với các ngoặc nhọn {} là nó được dùng cho cả block, hash và nhúng biến vào string.

  • KHÔNG DÙNG khoảng trắng sau dấu chấm than !
#bad
! something

#good
!something
  • KHÔNG DÙNG khoảng trắng khi khai báo khoảng (khoảng)
#bad
(1 .. 5)

#good
(1..5)
  • KHÔNG DÙNG khoảng trắng giữa tên hàm và dấu ngoặc mở (
#bad
def something (x)
end

#good
def something(x)
end
  • KHÔNG ĐỂ khoảng trắng thừa ở những dòng code cuối cùng

  • DÙNG khoảng trắng trước và sau toán tử(ngoại trừ toán tử mũ) , sau dấu phẩy, dấu hai chấm và dấu chấm phẩy. Khoảng trắng có thể (hầu hết) là không bắt buộc, nhưng nó sẽ giúp code dễ đọc, dễ viết hơn.

#bad
a=1
a=b+c
a = [1,2,3]
e = M * c ** 2

#good
a = 1
a = b + c
a = [1, 2, 3]
e = M * c**2

3. Các đặt tên hàm, tên biến, tên phương thức

  • Dùng tiếng Anh để đặt tên, không dùng các kí tự đặc biệt không thuộc bảng mã ascii
# bad 
заплат = 1_00   # dùng các kí tự không thuộc bảng mã ascii
zazazaza = 1_00    # không phải tiếng anh

# good
price = 1_00
  • Dùng snake_case cho tên phương thức, biến và nhãn (symbol).
# bad
:'some variable'
:SomeVariable
:someVariable

someVar = 5

def someMethod
  # something
end

def SomeMethod
  # something
end

# good
:some_variable

def some_method
  # something
end
  • Dùng snake_case cho tên file và tên thư mục, vd: views/hello_world/hello_world.rb.

  • Dùng CamelCase cho tên class và tên module. (viết hoa các từ viết tắt sau HTTP, RFC, XML)

# bad
class Someclass
  # some code
end

class Some_Class
  # some code
end

class SomeXttp
  # some code
end

class HttpSomething
  # some code
end

# good
class SomeClass
  # some code
end

class SomeHTTP
  # some code
end

class HTTPSomething
  # some code
end
  • Mỗi file chỉ nên có một class/module. Tên của file chính là tên của class/module nhưng thay PascalCase thành snake_case.

Ví dụ Tên file là item_comment.rb thì tên class/module bên trong sẽ đặt là

class ItemComment
  #something
end
  • Dùng SCREAMING_SNAKE_CASE cho hằng số.
# bad
ConstNumber = 2
const_number = 2

# good
CONST_NUMBER = 2
  • KHÔNG NÊN đặt tiền tố cho tên phương thức với các động từ bổ trợ như is, does, hay can. Những từ này không cần thiết và nghĩa quá chung chung, không đồng nhất với các phương thức boolean của ngôn ngữ: empty? hay include?.
# bad
class Cake
  def is_small?
    true
  end

  def can_play_football?
    true
  end

  def does_like_pizza?
    false
  end
end

# good
class Cake
  def small?
    true
  end

  def football_player?
    true
  end

  def likes_pizza?
    false
  end
end
  • Nếu có phương thức nguy hiểm thì nên có thêm phương thức an toàn.
# bad
class Animal
  def update!
  end
end

# good
class Animal
  def update
  end
end

# good
class Animal
  def update!
  end

  def update
  end
end

4. Cách trình bày bố cục

  • Nên sử dụng tabsize bằng 2 khoảng trắng. Nếu bạn cùng sublime text thì có thể setting tabsize và một số setting khác như sau:

Ở thanh menu chọn Preferences -> Setting - Distraction Free rồi thêm đoạn code sau vào file và lưu lại.

{
    "ensure_newline_at_eof_on_save": true,
    "font_size": 9,
    "highlight_line": true,
    "ignored_packages":
    [
        "Vintage"
    ],
    "rulers":
    [
        80
    ],
    "show_encoding": true,
    "show_line_endings": true,
    "tab_size": 2,
    "translate_tabs_to_spaces": true,
    "trim_trailing_white_space_on_save": true
}

=> Khi sử dụng tabsize là 2 thì sẽ dễ nhìn hơn và tiết kiệm dòng code hơn.

  • Không dùng dấu chấm phẩy ; để ngăn cách các câu lệnh và biểu thức, mà hãy viết mỗi câu 1 dòng.
# bad
puts 'foobar';   # Thừa dấu chấm phẩy

puts 'foo'; puts 'bar'  # hai câu lệnh trên cùng 1 dòng

# good
puts 'foobar'

puts 'foo'
puts 'bar'

puts 'foo', 'bar'  # câu lệnh này sẽ tự tách làm hai lệnh `puts`
  • Tránh kiểu viết gom nhiều phương thức vào một dòng. Mặc dù ở một vài nơi nó vẫn được sử dụng, có một vài điểm đặc thù khiến người ta cảm thấy khó chịu khi gặp nó. Dù sao vẫn không nên viết nhiều hơn một biểu thức, câu lệnh trên một dòng.
# bad
def method_name; something; something_else; end

# okish
def some_method() body end  # đúng cú pháp nhưng khó đọc hơn

# good
def some_method
  body
end
  • Cặp if, else hoặc when, case thụt đầu dòng cùng cấp. Style này được khuyến khích dùng trong cả "The Ruby Programming Language" và "Programming Ruby".
# bad
case
  when some_condition
    #do something
  when some_condition
    #do something
  when some_condition
    #do something
  else
    #do something
end

# good
case
when some_condition
  #do something
when some_condition
  #do something
when some_condition
  #do something
else
  #do something
end
  • KHÔNG DÙNG dấu phẩy , sau tham số cuối cùng khi khai báo phương thức, đặc biệt khi những tham số không nằm trên những dòng riêng biệt.
# bad
some_method(
             blue,
             red,
             black,
           )

# bad
some_method(blue, red, black, )

# good
some_method(blue, red, black)

Thêm một dòng trống giữa các phương thức, và các nhóm xử lý logic.

def some_method
  key = "#{CATCH_KEY}#{id}"

  Price.all.pluck(:id)

  data.result
end

def some_method
  result
end
  • Với cách gọi phương thức nhiều lần liên tiếp, có hai kiểu thông dụng, kiểu nào cũng được cả: . ở đầu dòng mới (Cách 1) hoặc . ở cuối dòng cũ (Cách 2). Mặc dù dùng kiểu nào thì cũng nên dùng nhất quán một kiểu.
#Cách 1

one.two.three
   .four

#Cách 2
one.two.three.
   four

Xem thêm về cuộc thảo luận chọn cách nào: tại đây

Thứ tự viết trong một file

Các phần trong một file nên viết theo thứ tự sau

class Person
  # Đầu tiên là extend và include
  extend SomeModule
  include AnotherModule

  # tiếp theo là inner classes
  CustomErrorKlass = Class.new(StandardError)

  # tiếp theo là khai báo hằng số
  SOME_CONSTANT = 20

  # tiếp đến attribute macros
  attr_reader :name

  # followed by other macros (if any)
  validates :name

  # public class methods are next in line
  def self.some_method
  end

  # initialization goes between class methods and other instance methods
  def initialize
  end

  # followed by other public instance methods
  def some_method
  end

  # protected and private methods are grouped near the end
  protected

  def some_protected_method
  end

  private

  def some_private_method
  end
end

5. Lời kết và tài liệu tham khảo

Ở phần này tôi đã giới thiệu tới các bạn một số style viết code cơ bản trong ruby bao gồm các phần về bố cục. Ở phần tiếp theo tôi sẽ tiếp tục giới thiệu tới các bạn các style sâu hơn về logicsyntax. Rất mong bài viết này sẽ hữu ích đối với bạn đọc

Tool

Rails có gem Rubocop là một Ruby code style checker các lỗi cơ bản khi viết code, bạn có thể thêm gem này vào project của mình và tùy chỉnh các settings Rubocop

Tài liệu tham khảo

Các bạn có thể đọc nhiều hơn về Coding-Style in Ruby trong các tài liệu dưới đây. Ruby-Style-Guide