Đối tượng dịch vụ Rails

Tram Ho

Giả sử ta cần đăng 1 đoạn message lên Twitter, chúng ta thường làm như sau:

Nhìn vào đoạn code trên ta đã định nghĩa send_tweet gọi api twitter.Nếu 1 controller khác cũng gọi twitter 1 cách tương tự thì sao? Có nên cho nó vào concern?? Nhưng nó k hẳn thuộc về controller, tại sao ta k tìm cách cho Twitter API thành 1 đối tượng sau đó call khi cần

Service object là gì?

Service object được thiết kế để thực hiện một logic cụ thể nào đó mà đối tượng xử lí k hoàn toàn thuộc về 1 model nào cả.
Lợi ích của Service object là nó giúp chúng ta tập chung toàn bộ logic chức năng vào 1 object riêng biệt thay vì chia nhỏ nó ở controller hay model. Lúc nào cần đến thì gọi object đó ra.
Chính vì khối logic được tập trung hết vào trong 1 object nên sẽ tối giản controller và model đi rất nhiều, code clean và quá trình maintain sau này cũng đỡ vất vả hơn.
Xem ví dụ trên method send_tweet thực hiện 1 logic duy nhất là tạo 1 tweet. Nếu logic này được gói gọn vào 1 class, chúng ta có thể khởi tạo và gọi theo kiểu:

hoặc

Thật tiện lợi đúng k. Ta chỉ việc định nghĩa nó 1 lần, có thể dùng nó ở bất cứ đâu, dễ dàng maintance sửa đổi

Tạo Service object

Chúng ta sẽ tạo TweetCreator trong app/services:

add logic vào trong service:

Sau đó bạn có thể gọi bằng cách:

TweetCreator class name tương đối ngắn nhưng khi khởi tạo và gọi thì trông khá dài đúng không. ta có thể rút gọn câu lệnh gọi bằng cách sau đây, Nếu TweetCreator có thể giống với proc trong Ruby ta có thể gọi nó bằng TweetCreator.call(message)
Giờ chúng ta sẽ biến service object như 1 proc để thuận tiện cho việc gọi service nhé!
Tạo 1 ApplicationService:

Mỗi khi call dc gọi nó sẽ tạo ra 1 instance của class đó vs các biến truyền vào

Tại controller ta gọi

1 cách làm cho code trở nên tối ưu hơn đúng không 😃)

Grouping Similar Service Objects

Ở ví dụ trên ta chỉ xét 1 service object, nhưng trên thực tế có thể phức tạp hơn thế. Ví dụ ta có hàng trăm service xử lí nhiều logic khác nhau. Ta k thể nhét chúng vào 1 file sẽ rất khó quản lí đúng không. Chúng ta sẽ sử dụng namespacing, ta sẽ nhóm các service object có chung đặc điểm vào 1 module:
Ví dụ:

Trong service:

Ta gọi bằng cách

Service Objects thao tác với database

Ở ví dụ trên ta xét api call, nhưng service object cũng có thể sử dụng để gọi tới database. Nó thực sự hữu ích khi ta cập nhập nhiều DB với nhiều logic phức tạp ví dụ như:

Service object nên trả về gì?

Vừa rồi chúng ta thảo luận cách xây dựng gọi method call như thế nào, vậy method call nên trả về gì? Có 3 cách trả về

  • Trả về true/ false

  • Trả về 1 giá trị

  • Trả về 1 enum

Một số rule để viết service object tốt

Mỗi Service Object chỉ nên có 1 public method

Mỗi một service object chỉ thực hiện 1 bussiness cụ thể nào đó, do vậy chỉ nên có 1 public method

Đặt tên Service object theo vai trò của nó

Ta nên đặt tên service object để người code có thể hiểu được vai trò của nó luôn

Không thực hiện nhiều action

Mỗi service object chỉ thực hiên 1 bussiness

Handle Exceptions bên trong service object

Hi vọng bài viết giúp bạn hiểu về service object và vận dụng được trong dự án. Thanks for reading. 😄

Tham khảo tại: https://www.toptal.com/ruby-on-rails/rails-service-objects-tutorial

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo