+1

3 nguyên tắc giúp viết code ruby tốt hơn

Làm thế nào để viết code ruby được tốt hơn? Đó là câu trả lời không phải đơn giản. Và dưới đây sẽ là 3 nguyên tắc cho bạn tham khảo để có thể cải thiện khả năng viết cũng như khả năng đọc cho người khác.

Nguyên Tắc 1: Tránh sự hiểu lầm

Sự hiểu lầm chính là nguyên nhân lớn nhất dẫn tới những sai lầm. Ví dụ yêu cầu là soft delete một user, bạn lại xóa hẳn user đó đi => sinh ra một sự hiểm lầm có thể nói là nghiêm trọng.

Vậy sự hiểu lầm trong code của bạn diễn ra như thế nào? Nó có thể đến từ đâu? Câu trả lời là nó có thể đến bất cứ nơi đâu trong những dòng code của bạn, từ những thứ rất nhỏ nhặt như là biến được đặt tên không rõ nghĩa, hoặc hard code không có tên biến, hoặc khi bạn đọc những comment từ ngày đầu code, mà trong khi đó spec thay đổi, code thay đổi, comment lại không được cập nhật, hay là khi bạn phải dành quá nhiều thời gian để đọc hiểu 1 đoạn code nào đó.

Sự hiểu lầm này ảnh hưởng tới khả năng đọc code. Nó gây ra sự lãng phí thời gian của bạn, cũng như của những người sau tiếp nhận code của bạn để maintaince. Bạn có thể sửa những lỗi lầm này theo một số cách:

  • Đặt tên cho các biến, methods sao cho nói lên được ý nghĩa mục đích của nó. (ví dụ method trả về true, false thì nên để ? ở cuối method.)
  • Xóa hoặc cập nhật lại những comment đã bị hết hạn. Thực ra khi bạn viết code đủ dễ hiểu thì comment thực sự là cũng không cần.
  • Nhóm, xắp xếp code của bạn một cách hợp lý. Ví dụ, khi bạn muốn check 1 user có đủ điều kiện đăng nhập vào hệ thống hay không, thay vì check user.is_started? && user.not_stopped? thì chúng ta gộp nó thành 1 methods để check user.can_authenticate? như vậy chúng ta có thể dùng chung nó cho mọi nơi cần đến, cũng như là đọc tên methods có thể hiểu được nó dùng để làm gì.

Ví dụ:

if name =~ /\A[\u30A0-\u30FF\uFF5F-\uFF9F\s  *]+\z/
# ...
end

Bạn có thể là master về các biểu thức regex, có thể hiểu đc đoạn regex trên để làm gì, nhưng sau đó có lẽ bạn sẽ không hiểu ý định của đoạn code này là gì? Và tại sao chúng ta lại cần đoạn regex đó? Chính vì vậy bạn muốn làm cho code của mình trở nên rõ ràng, dễ hiểu đến nỗi không cần suy nghĩ ý nghĩa của chúng là gì, một khi đã rõ ràng thì comment là điều không cần thiết, và chính code của bạn là 1 bản document. Điều này có nghĩa chúng ta cần đặt một cái tên cho đoạn mã regex kia cho biết ý nghĩa của chúng. Và chúng ta có mã code sau khi refactor như sau:

VALID_NAME_KANA = /\A[\u30A0-\u30FF\uFF5F-\uFF9F\s  *]+\z/
if name =~ VALID_NAME_KANA
...
end

Và bây giờ khi nhìn vào đoạn code trên bạn có thể dễ dàng hiểu đc mục đích của nó là gì và không cần phải rõ đoạn regex trên kia nó như thế nào nữa.

Nguyên Tắc 2: Tạo nhiều class nhỏ

Tạo nhiều class chính là chìa khóa cho việc breaking những class, hay methods lớn thành những class, hay methods nhỏ hơn.

Một class lớn được gọi là God Class chúng chứa quá nhiều logic, ở khắp mọi nơi và có tất cả chức năng quan trọng nhất. Điều đó thật là tồi tệ. Bạn không nên để 1 class duy nhất có quyền quản lý lớn đối với hệ thống của bạn => một khi có vấn đề nho nhỏ gì đối với class đó thì sẽ gây ra hậu quả nghiêm trọng cho toàn bộ hệ thống. Thay vào đó chúng ta chia nhỏ nó ra, mỗi class nhỏ đảm nhiệm một chức năng, nhiệm vụ riêng biệt khi đó bạn dễ dàng kiểm soát code của mình, một khi chức năng nào đó bị lỗi, ta hoàn toàn có thể tạm break chúng ra khỏi hệ thống mà không cần phải suy nghĩ nhiều về ảnh hưởng của chúng.

Ví dụ :

class Game
  def display_board
  end
  def save_state
  end
  def make_move
  end
  def valid_move?
  end
end

Đoạn code trên chưa nhiều methods với những mục đích khác nhau. Việc hiển thị game nó là rất khác so với việc lưu lại trạng thái của game, hay là việc di chuyển hoặc check xem nó có được phép di chuyển hay không. Một class chưa rất nhiều thứ không liên quan. Bạn có thể nhìn các methods, xem mục đích, concepts của chúng là gì? từ đó có thể dựa vào đó phân tách chúng thành những class nhỏ khác nhau, phục vụ từng mục đích riêng. Với class trên chúng ta có thể chia ra làm 3 class nhỏ với 3 mục đích chính: Hiện thị game, lưu trạng thái của game và xử lý việc di chuyển. Và sau khi refactor chúng ta sẽ có các class như sau:

class GameBoard
  def display_board
  end
end
class GameState
  def save
  end
end
class GameLogic
  def make_move
  end
  def legal_move?
  end
end

Khi bạn làm điều này, có nghĩa là code của bạn đang dần tiến tới nguyên tắc Single Responsibility Principle (SRP).

Một ví dụ nhỏ nữa mà chúng ta nên tạo class mới như là: Khi đăng kí 1 user (name, name_kana) có 2 cách để đăng kí, 1 là user tự đăng kí, 2 là có amdin đăng kí giùm. Yêu cầu ở đây là khi admin đăng kí thì required name nhưng không required name_kana, nhưng khi user đăng kí thì name bắt buộc required (lấy ví dụ nho nhỏ). Thay vì việc chúng ta có 1 class user chưa tất cả các validate, và chúng ta cần check xem ai là người đang tạo nó để check điều kiện validate name đó thì tại sao chúng ta không tách riêng class quản lý việc validate cho user đăng kí và cho admin đăng kí riêng? => chúng ta sẽ có 3 class như sau:

class User
end
### For user entry
class UserForm
  include ActiveModel::Model
	
	attr_accessor :name, :name_kana
	
	validate :name, name_kana, presence: true
end
### For admin create
class AdminUserForm
  include ActiveModel::Model
	
	attr_accessor :name, :name_kana
	
	validate :name, presence: true
end

=> 3 class rõ ràng phục vụ những mục đích khác nhau, rất dễ dàng control đúng không.

Nguyên Tắc 3: Xóa các phần tử không cần thiết

Rào cản lớn nhất đối với việc đọc và maintainability code là có những yếu tố không cần thiết xuất hiện. Nó có thể là

  • lệnh return ở cuối 1 mã code (cái này là không cần thiết với ruby)
  • quá nhiều biến temporary
  • những comment thừa thãi
  • duplication code
  • những đoạn mã code không làm gì

Nếu bạn muốn code của mình sạch sẽ, dễ đọc thì hãy loại bỏ chúng. Ví dụ

def add a, b
  result = a + b
  return result
end

Thì bạn hoàn toàn có thể viết một cách đơn giản

def add a, b
  a + b
end

Gọn gàng dễ đọc hơn rất nhiều. Có nhiều trường hợp spec thay đổi, một số methods không còn được dùng nữa, nhưng họ vẫn cố tình để lại những đoạn code trước kia họ viết (vì cảm thấy phí công mình đã viết ra hoặc có thể sẽ dùng đến) điều này gây ra sự bối rối, khó hiểu cho những người sau tiếp nhận, họ không biết đc đoạn này làm gì? mục đích là gì. Vì vậy đừng tiếc những gì đã viết. nếu bạn dùng git, hay bitbucket,... thì những code đó đã được lưu trữ lại, bạn muốn check lại cũng rất đơn giản. Thế nên đừng tiếc gì mà hãy xóa hết chúng đi.

Cuối cùng, bạn hoàn toàn có thể kết hợp cả 3 nguyên tắc lại để cho ra được một đoạn mã mà bạn cảm thấy tốt nhất.

Reference: https://www.rubyguides.com/3-principles-download/


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í