Nếu không quen thuật ngữ, refactoring là hành động cải thiện chất lượng code mà không thay đổi chức năng. Điều này làm code dễ làm việc hơn rất nhiều.
Bài này học kỹ thuật refactoring Ruby phổ biến.
Bắt đầu!
Extract Method (Trích Xuất Phương Thức)
Một refactoring phổ biến nhất gọi là 'extract method'. Di chuyển code từ phương thức cũ sang phương thức mới. Cho phép phương thức nhỏ hơn với tên mô tả.
Xem ví dụ:
@sold_items = %w( onions garlic potatoes )
def print_report
puts "*** Sales Report for #{Time.new.strftime("%d/%m/%Y")} ***"
@sold_items.each { |i| puts i }
puts "*** End of Sales Report ***"
end
Bắt đầu trích xuất phần xấu nhất, tạo ngày hiện tại.
def print_report
puts "*** Sales Report for #{current_date} ***"
@sold_items.each { |i| puts i }
puts "*** End of Sales Report ***"
end
def current_date
Time.new.strftime("%d/%m/%Y")
end
Đã đọc dễ hơn, nhưng còn tiến xa hơn. Trích xuất thêm vài phương thức kết thúc với code:
def print_report
print_header
print_items
print_footer
end
def print_header
puts "*** Sales Report for #{current_date} ***"
end
def current_date
Time.new.strftime("%d/%m/%Y")
end
def print_items
@sold_items.each { |i| puts i }
end
def print_footer
puts "*** End of Sales Report ***"
end
Code dài hơn, nhưng có dễ đọc hơn không? Đừng sợ phương thức nhỏ, chúng tốt cho code.
Refactoring Điều Kiện (Conditionals)
Cũng refactor điều kiện phức tạp thành phương thức để dễ đọc hơn.
Ví dụ:
def check_temperature
if temperature > 30 && (Time.now.hour >= 9 && Time.now.hour <= 17)
air_conditioner.enable!
end
end
Phần hai câu if không siêu dễ đọc, trích xuất thành phương thức:
def check_temperature
if temperature > 30 && working_hours
air_conditioner.enable!
end
end
def working_hours
Time.now.hour >= 9 && Time.now.hour <= 17
end
Đã đặt tên mô tả cho điều kiện, dễ dàng cho người đọc code sau này (kể cả bạn!).
Replace Method with Method Object (Thay Phương Thức Bằng Đối Tượng Phương Thức)
Đôi khi phương thức lớn mất kiểm soát. Khó refactor vì phương thức lớn có nhiều biến cục bộ. Giải pháp dùng refactoring 'Method Object'.
"Phương thức lớn là nơi lớp đi trốn." - Uncle Bob
Xem ví dụ:
require 'socket'
class MailSender
def initialize
@sent_messages = []
end
def send_message(msg, recipient = "rubyguides.com")
raise ArgumentError, "message too small" if msg.size < 5
formatted_msg = "[New Message] #{msg}"
TCPSocket.open(recipient, 80) do |socket|
socket.write(formatted_msg)
end
@sent_messages << [msg, recipient]
puts "Message sent."
end
end
sender = MailSender.new
sender.send_message("testing")
Để refactor, tạo lớp mới và thăng cấp biến cục bộ thành biến instance. Cho phép refactor tiếp mà không lo truyền dữ liệu.
Hey! Muốn nâng cao kỹ năng Ruby to lớn? Xem Beautiful Ruby Course của mình 🙂
Lớp MailSender sau refactor:
class MailSender
def initialize
@sent_messages = []
end
def deliver_message(message)
send(message)
@sent_messages << message
puts "Message sent."
end
def send(msg)
TCPSocket.open(msg.recipient, 80) { |socket| socket.write(msg.formatted_msg) }
end
end
Và lớp mới 도입入:
class Message
attr_reader :msg, :recipient
def initialize(msg, recipient = "rubyguides.com")
raise ArgumentError, "message too small" if msg.size < 5
@msg = msg
@recipient = recipient
end
def formatted_msg
"[New Message] #{msg}"
end
end
sender = MailSender.new
msg = Message.new("testing")
sender.deliver_message(msg)
Kết Luận
Dùng kỹ thuật refactoring này giúp tuân thủ Nguyên tắc Trách Nhiệm Đơn (Single Responsibility Principle) và giữ lớp/phương thức kiểm soát.
Nếu thích bài viết chia sẻ với bạn bè để họ cũng tận hưởng 🙂