Salut. Je suis POROs - Hi. I am POROs

Khi đọc các bài viết về refactor fat model, fat controller, thì có các solution như sử dụng Service Object,.. với thuật ngữ POROs - một thuật ngữ chưa nắm rõ lắm. Do đó phải tim hiểu nó thôi.

POROs - Plain Old Ruby Objects : mình tạm dịch là “những đối tượng thuần túy của Ruby”


1. Đặt vấn đề.

Khi làm việc với Rails, bạn đã quá quen thuộc với cấu trúc MVC, và cách tổ chức code mở rộng với các thành phần như Job, validations,.. Bạn có thể chọn mở một trong các file trong source app để xem và biết chính xác nó làm gì. Trong quá trình phát triển app bạn muốn thêm những thứ mà không đến từ Rails , chính xác là những lib, module được xây dựng từ Standand Ruby Core. Đó chính xác là POROs.

Ví dụ điển hình nhất là

class NewClass
end

2. POROs giúp bạn làm những gì.

Lấy một ví dụ nhỏ: Có một action create của controller User có chức năng:

  • check valid IP
  • check valid “checked-button”
  • Save db
  • Add notice to admin
  • Send mail

Lúc đó ta sẽ có một controller như sau

class RegisterUserController < ApplicationController
   def create
          @user= User.new(params)
          if @user.valid? && valid_ip
             @user.save
             @user.add_notice
             send_mail
          end
    end
 end

Nhìn sơ thì đoạn code trên thật đơn giản và có thể giải quyết vấn đề. Tuy nhiên trên lý thuyết thì nó đã vi phạm nguyên tắc Single responsibility principle hay “Thin controller” vì chứa quá nhiều logic. Lúc này ta sẽ refactory code dùng “Service Object”

class RegistrationService
  def excute!(params)
    user = User.new(params)
    if user.valid? && valid_it(params[:param_ipư)
      user.save!
      after_registered_events(user)
    end
    user
  end

  private

  def after_registered_events(user)
    # do somthing here
  end
end

class RegisterUserController < ApplicationController
    def create
     @user = RegistrationServer.new.excute!(user_params)
    end
end

Và bây giờ ta thấy controller trở nên rõ ràng và clear hơn chỉ gọi lớp ResigterUser để thực hiện chức năng create user. Vấn đề được đặt ra là nếu nhiều file POROs như thế thì ta quản lý như thế nào.

3. Tổ chức POROs trong Rails

a Đặt trong thư mục lib

  • Trường ko có relation với các thành phần của Rails
  • Trường hợp này được sử dụng trong trường hợp module bạn viết ra ko có related với controller hay model, view thì bạn có thể để nó trong thư mục lib/

Cấu trúc như sau

Project
| - app/
| - lib/
|      - service/
|          # all poros file

Tất nhiên phương pháp này có nhược điểm trong quá trình phát triển source:

  • Nếu số lượng POROs quá lớn sẽ khó quản lý kiểu như liên tục nhồi nhét vào 1 cái túi
  • Sẽ ko theo dõi được class này để làm gì được sử dụng ở đâu. (Mất đi tính thân thiện của Rails)

b. Namespace.

Namespace class and module được sử dụng hầu hết trong các gem và các chương trình Ruby Giả sử ta có một controller là users.

  • List ra tất cả các user.
  • Phân trang
  • Check phân quyền.
  • new
  • update
  • v.vv

=> Mọi thứ nhồi nhéc vào trong 1 controller/index

class UserController < ApplicationController
   def index
    //code here
    end

    def new
    end
end

=> Di chuyển hết về một class module để “Thin controller”.

Tổ chức :

app
   |-controllers
        |- user_controller
             |- user.rb
        |-user_controller.rb

=> Ưu điểm dễ quản lý, đảm bảo được Thin controller.

Tất nhiên có thể áp dụng cho cả model.


Trên đây là những tóm tắt về POROs và ứng dụng để cấu trúc dự án của bạn một cách hợp lý.