Sử dụng design-parttern Service Object giúp clean và tránh DRY code
Nếu bạn đang làm việc với rails thì chắc cũng không lạ gì Serivce object. Đây là một design patter được tạo ra để thực thi một công việc nhất định nào đó mà có logic khá phức tạp không dành riêng cho một model hay một controller nào nhất định. Nó sinh ra để tránh việc Model và controller bị phình ...
Nếu bạn đang làm việc với rails thì chắc cũng không lạ gì Serivce object. Đây là một design patter được tạo ra để thực thi một công việc nhất định nào đó mà có logic khá phức tạp không dành riêng cho một model hay một controller nào nhất định. Nó sinh ra để tránh việc Model và controller bị phình lên bởi quá nhiều xử lý logic và nó cũng có thể được gọi nhiều lần.
Service Objects
Như bạn đã biết là trong MVC logic business được đặt ở Model layer. Nhưng đến một thời điểm bạn nhận ra Model đã phình lên quá to khó hiểu, khó maintanable và bạn cũng không thể đẩy logic đó vào Controllers layout được vì nó đóng vai trò điều hướng thôi, phải giữ cho controller clean nhất có thể. Vậy thì lúc này để giúp cho Model và Controller được đơn giản thì bạn nên nhóm các business đối tượng liên qua ra và đặt chúng trong folder app/services. Bạn hãy tạo một folder service ngay trong thư mục app. Và khi sử dụng trong controller chỉ cần gọi ra và thực thi là được
Cấu trúc
Trong services bạn có thể tạo ra nhiều loại service khác nhau để phục vụ nhưng business nhất định nào đó VD call api, update object, register... Nhưng mỗi service nên chỉ đảm nhiệm một nhiệm vụ thôi. tránh việc ôm đồm quá nhiều thứ trong service. VD service manage_candidate.rb từ manage qua rộng và có quá nhiều việc trong từ manage này. Thật ra service object chỉ là một class sinh ra để hoàn thành một action nào đó thôi, trong class này thì nên chỉ có một hàm để được gọi thực thi bên ngoài thôi là xong. Việc thiết kế như vậy cũng giúp chúng ta dễ dàng cover toàn bộ được service đó. Bạn có thể đặt tùy thích đặt tên cho method đó VD call, regiest, perform... mình thì sẽ chọn perform hehe. Luyên thuyên đủ rồi giờ đi thẳng vào cấu trúc của một serivce object nào
class class_name def initialize *args ... end def perform #action.... end private def private_method1 #... end end
Như bạn đã nhìn thấy ở trên thì không khác gì một class bình thường thôi. Vẫn có hàm khởi tạo và các method cần thiết. Khi chúng ta implement thì cố gắng giữ đơn giản nhất có thể. từ biến khởi tạo cho đến việc thực thi trong hàm perform.
thậm chí đến việc truyền biến khởi tạo cũng nên giữ cho nó dễ đọc nhất có thể.VD bạn có thể truyền rất nhiều biến khi khỏi tạo gia su.
UpdateCandidate.new(params[:candidate], params[:career_partner_id], true).perform
thay vì thế hãy viết
UpdateCandidate.new(attributes: params[:candidate], career_partner_id: params[:career_partner_id], is_vip: true)
việc viết như vậy sẽ khiến maintain dễ đọc hơn.
Trạng thái trả về
Thông thường thì chúng ta chỉ quan tâm đến thực thi thành công hay thất bại sau khi chạy xong service. Tuy nhiên ít lần chúng ta cần lấy thống tin gì đó sau khi chạy. Vì thế dể đơn giản thì thường thì hàm perform sẽ trả về true khi thực thi thành công hay false thì việc thự thi thất bại hay gặp vấn đề. và việc này cũng sẽ giúp chúng ta viết rsect test cho service dễ dàng hơn hehe.
Tổng quan
Bài viết này mình đã giới thiệu về service object một desing pattern khá hay giúp tổ chức code dễ đọc và tránh được viêc DRY code trong rails app. hy vọng sẽ giúp ích được cho bạn Thank you!