Giới Thiệu
Việc phát triển ứng dụng web thường đòi hỏi sự hỗ trợ từ các framework và thư viện. Mặc dù chúng cung cấp cấu trúc và quy tắc rõ ràng, nhưng đôi khi bạn vẫn cảm thấy bối rối trong việc tổ chức mã nguồn. Bài viết này sẽ giới thiệu một số design patterns quan trọng mà bạn nên nắm vững, kèm theo ví dụ cụ thể bằng ngôn ngữ Ruby.
1. Service Object
Trong mô hình MVC (Model-View-Controller), controller đóng vai trò làm cầu nối giữa model và view. Dù vậy, không nên để controller chứa quá nhiều logic. Thay vào đó, bạn hãy tách các logic đó ra thành một service riêng biệt:
Ví dụ mà không có service:
ruby
class UsersController
def create
user = User.new(user_params)
if user.save
UserMailer.verify_email(user)
render json: { status: :success, user: user.as_json }
else
render json: { status: :error, errors: user.errors.messages }
end
end
end
Ví dụ khi sử dụng service:
ruby
class CreateUserService
def initialize(user_params)
@user = User.new(user_params)
end
def execute
return error_response unless @user.save
send_verify_email
success_response
end
private
attr_reader :user
def success_response
ServiceResponse.success(payload: @user.as_json)
end
def error_response
ServiceResponse.error(payload: @user.errors.messages)
end
def send_verify_email
UserMailer.verify_email(@user)
end
end
ruby
class UsersController
def create
render json: CreateUserService.new(user_params).execute
end
end
2. ServiceResponse
Khi bạn có nhiều service trong dự án, việc đồng nhất định dạng dữ liệu trả về là rất quan trọng. Ví dụ, bạn có thể sử dụng ServiceResponse
để tạo một cấu trúc dữ liệu đồng nhất:
ruby
class ServiceResponse
def self.success(message: nil, payload: {})
{ status: :success, message: message, payload: payload }
end
def self.error(message: nil, payload: {})
{ status: :error, message: message, payload: payload }
end
end
Sử dụng ServiceResponse
trong service:
ruby
class CreateUserService
# ...
def execute
return error_response unless @user.save
send_verify_email
success_response
end
private
def success_response
ServiceResponse.success(payload: @user.as_json)
end
def error_response
ServiceResponse.error(payload: @user.errors.messages)
end
end
3. Finder
Finder giúp bạn thực hiện các thao tác truy vấn cơ sở dữ liệu một cách gọn gàng hơn. Việc sử dụng finder giúp giảm thiểu khối lượng logic trong controller và cho phép tái sử dụng dễ dàng:
Ví dụ không có finder:
ruby
class EmployeesController < ApplicationController
def index
@employees = current_user.employees
@employees = @employees.id_in(params[:id]) if params[:id].present?
end
end
Ví dụ với finder:
ruby
class EmployeesFinder
def initialize(manager, params)
@manager = manager
@params = params
end
def execute
employees = @manager.employees
employees = filter_by_id(employees)
employees = filter_by_name(employees)
employees = filter_by_blocked(employees)
order(employees)
end
private
# Các phương thức filter_by_id, filter_by_name và filter_by_blocked
end
Sử dụng finder trong controller:
ruby
class EmployeesController < ApplicationController
def index
@employees = EmployeesFinder.new(current_user, params).execute
end
end
4. Decorator
Decorator cho phép bạn định dạng hoặc thêm các thông tin khác cho một record mà không làm phình to model:
Ví dụ sử dụng decorator:
ruby
class UserDecorator
def formatted_created_at
@user.created_at.strftime('%Y/%m/%d')
end
end
5. Presenter
Presenter giúp bạn quản lý logic phức tạp trong controller và view dễ dàng hơn. Khi sử dụng presenter, bạn có thể giảm số lượng biến instance trong controller:
Ví dụ:
ruby
class PostPresenter
def initialize(current_user, post)
@current_user = current_user
@post = post
end
# Các phương thức để lấy thông tin
end
6. Serializer
Serializer thường được sử dụng để định dạng phản hồi cho API, đảm bảo rằng dữ liệu được trả về có cấu trúc rõ ràng.
Ví dụ sử dụng serializer:
ruby
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :content
end
Kết Luận
Trên đây là một số design patterns quan trọng mà bạn nên tìm hiểu và áp dụng vào quá trình lập trình web. Việc lựa chọn đúng pattern giúp mã nguồn trở nên rõ ràng, dễ quản lý và mở rộng trong tương lai.
source: viblo