12/08/2018, 14:49

Phân biệt các loại service trong ứng dụng của bạn

Ở bài viết trước mình đã từng giới thiệu Service Object là gì và cách sử dụng chúng, bài dưới đây sẽ thể hiện tổng quan hơn việc service là gì và các loại service mà chúng ta có. Không chỉ riêng về service object trong rails. Đôi khi trong model bạn đi qua một điều gì đó mà nó không thực sự là ...

Ở bài viết trước mình đã từng giới thiệu Service Object là gì và cách sử dụng chúng, bài dưới đây sẽ thể hiện tổng quan hơn việc service là gì và các loại service mà chúng ta có. Không chỉ riêng về service object trong rails.

Đôi khi trong model bạn đi qua một điều gì đó mà nó không thực sự là như vậy. Những hoạt động đó không hoàn toàn thuộc về một đối tượng đó được gọi là service. Service layer thường sống trong một lớp service riêng biệt, nó nằm giữa controllers và models.

Thiết kế ứng dụng với services và service layer là phổ biến trong cộng đồng Java J2EE/Spring. Tuy nhiên nó không phổ biến trong thế giới Rails. Điều này có phải do cộng đồng Ruby cho rằng Java phức tạp hay là do sự gia tăng của HTTP dựa vào JSON API làm cho kiến trúc này trở nên lỗi thời? Để trả lời những câu hỏi này, chúng ta hãy đi sâu hơn về services để thấy được lợi ích của chúng.

Service là gì?

Trong Domain-Driven Design, Evans định nghĩa một service là một hoạt động được cung cấp như một giao diện đứng một mình trong model. Nói một cách khác, service là một action có thể tương tác không phải là thing. Và thay vì forcing hoạt động vào một đối tượng đã tồn tại, chúng ta nên đóng gói chúng trong những service với trạng thái riêng biệt.

Không phải lúc nào chúng ta cũng cần phải rõ ràng những logic tạo thành một service. Và tách service ra càng nhỏ càng tốt và cần phân loại đúng service mà chúng ta sử dụng, để làm được điều đó chúng ta sẽ đi đến các định nghĩa phân loại services như sau:

Các loại services

Evans đã định nghĩa 3 loại service như sau:

  • Application
  • Domain
  • Infrastructure

Application Services

Một application service là một service cung cấp các hoạt động không liên quan đến infrastructure (cơ sở hạ tầng của phần mềm), nó sẽ không liên quan đến việc thảo luận về các miền model bên ngoài phần mềm, tức là trong môi trường tự nhiên của nó.

Ví dụ, export các transactions của một account dưới dạng file CSV trong ứng dụng banking là một application service vì nó được export dưới dạng một file, CSV, nó không có ý nghĩa trong miền của banking (Có nghĩa không liên quan gì đến lĩnh vực banking).

class AccountCSVExporter
  def self.to_csv(account)
    CSV.generate do |csv|
      account.transactions.each do |transaction|
        csv << [transaction.amount, transaction.created_on]
      end
    end
  end
end

Application service cải thiện sự gắn kết của các model bằng cách ngăn chặn các thực thi chi tiết vào đó.

Domain Services

Một domain service là kịch bản cho một use-case có liên quan đến nhiều đối tượng. Forcing logic này vào một object là sự không khéo léo, vì các use-cases thường liên quan đến các quy tắc, trách nhiệm bên ngoài và không phải là của một đối tượng duy nhất.

Tiếp tục với ví dụ liên quan đến banking, chuyển khoản ngân hàng sẽ là một ví dụ về domain service. Chuyển tiền nó không hoàn toàn liên quan đến account object hay một phần của customer object, vì vậy nó sẽ trở thành một dịch vụ độc lập.

class FundsTransferService
  def self.transfer(from, to, amount)
    Account.transaction do
      from.debit amount
      to.credit amount
    end
  end
end

Một ví dụ khác về domain service là tìm kiếm trên cả một trang web với nhiều models khác nhau. Do nó được tìm kiếm trên những model khác nhau nên nó không còn phù hợp với khái niệm trong bất kì model cụ thể nào cả. Thay vào đó chúng ta cần phải có một dịch vụ tìm kiếm riêng biệt cho việc này.

class SearchService
  def self.search(query)
    Sunspot.search(Document, Email, Appointment) do
      fulltext query
    end
  end
end

Infrastructure Services

Một infrastructure service đóng gói các truy cập vào một hệ thống bên ngoài. Các infrastructure services thường được sử dụng bới application và domain service. Như là gửi mail, gọi API từ bên ngoài ....

E-mailling và message queuing là 2 ví dụ về infrastructure services.

class AccountEmailService
  def self.overdrawn_account(account)
    email = AccountMailer.overdrawn_account account
    email.deliver
  end
end

class MessagingService
  def self.overdrawn_account_sms(account)
    Resque.enqueue SmsJob, "Account #{account.account_number} overdrawn!"
  end
end

Kết luận

Từ các định nghĩa trên có thể thấy rằng chúng ta hầy như là đang sử dụng 2 loại service trong ứng dụng Ruby là Domain service và Infrastructure service. Việc xác định đúng được loại service sẽ giúp chúng ta dễ dàng quản lý và tái sử dụng một cách tối ưu nhất mã code của mình.

0