Este tutorial documenta dois refactors realizados no projeto ClinicSync, uma aplicação de gestão de clínicas médicas desenvolvida como parte do meu MBA em Ruby on Rails. O objetivo foi aplicar boas práticas arquiteturais utilizando Service Objects para melhorar a legibilidade, manutenção e escalabilidade do sistema. O que são Service Objects? Service Objects são classes simples usadas para organizar lógicas de negócio que não pertencem diretamente a models, controllers ou views. Eles são uma forma de aplicar o princípio da Responsabilidade Única (SRP) na prática, deixando cada parte do sistema com um papel bem definido. Quando usar um Service Object? Use um Service Object quando: A lógica é complexa demais para ficar dentro de um controller A funcionalidade não pertence naturalmente a nenhum model Você precisa reutilizar a mesma lógica em mais de um lugar Quer escrever código mais limpo e fácil de testar Estrutura básica de um Service Object class NomeDoServico def self.call(params) new(params).call end def initialize(params) @params = params end def call # lógica principal aqui end end Refactor 1: AuthorizeUser Service Objetivo: Retirar dos controllers a lógica repetida de verificação de tipo de usuário. Antes: def require_admin unless user_signed_in? && current_user.is_a?(Admin) redirect_to root_path, alert: "You are not authorized to access this page." end end Depois: def require_admin unless user_signed_in? && AuthorizeUser.call(current_user, Admin) redirect_to root_path, alert: "You are not authorized to access this page." end end Service criado: class AuthorizeUser def self.call(user, user_type) user.is_a?(user_type) end end Benefícios: Lógica DRY Fácil de manter Código mais claro e reutilizável Refactor 2: AuthenticateUser Service Objetivo: Tirar do SessionsController a lógica de autenticação de usuário. Antes: if (user = User.authenticate_by(params.permit(:email_address, :password))) start_new_session_for user redirect_to home_path_for(user), notice: "Logged in successfully." else redirect_to new_session_path, alert: "Try another email address or password." end Depois: user = AuthenticateUser.call(params[:email_address], params[:password]) if user start_new_session_for user redirect_to home_path_for(user), notice: "Logged in successfully." else redirect_to new_session_path, alert: "Try another email address or password." end Service criado: class AuthenticateUser def self.call(email_address, password) User.authenticate_by(email_address: email_address, password: password) end end Benefícios: Controller mais limpo Fácil de expandir para login social, 2FA etc. Separacão de responsabilidades clara Conclusão Esses dois pequenos Service Objects deixaram o projeto: Mais limpo Mais testável Pronto para crescer Service Objects são uma forma poderosa de aplicar Clean Code e preparar sua aplicação Rails para o futuro. Escrito por: [Leonardo Quadros Fragozo]

Este tutorial documenta dois refactors realizados no projeto ClinicSync, uma aplicação de gestão de clínicas médicas desenvolvida como parte do meu MBA em Ruby on Rails. O objetivo foi aplicar boas práticas arquiteturais utilizando Service Objects para melhorar a legibilidade, manutenção e escalabilidade do sistema.
O que são Service Objects?
Service Objects são classes simples usadas para organizar lógicas de negócio que não pertencem diretamente a models, controllers ou views.
Eles são uma forma de aplicar o princípio da Responsabilidade Única (SRP) na prática, deixando cada parte do sistema com um papel bem definido.
Quando usar um Service Object?
Use um Service Object quando:
- A lógica é complexa demais para ficar dentro de um controller
- A funcionalidade não pertence naturalmente a nenhum model
- Você precisa reutilizar a mesma lógica em mais de um lugar
- Quer escrever código mais limpo e fácil de testar
Estrutura básica de um Service Object
class NomeDoServico
def self.call(params)
new(params).call
end
def initialize(params)
@params = params
end
def call
# lógica principal aqui
end
end
Refactor 1: AuthorizeUser
Service
Objetivo:
Retirar dos controllers a lógica repetida de verificação de tipo de usuário.
Antes:
def require_admin
unless user_signed_in? && current_user.is_a?(Admin)
redirect_to root_path, alert: "You are not authorized to access this page."
end
end
Depois:
def require_admin
unless user_signed_in? && AuthorizeUser.call(current_user, Admin)
redirect_to root_path, alert: "You are not authorized to access this page."
end
end
Service criado:
class AuthorizeUser
def self.call(user, user_type)
user.is_a?(user_type)
end
end
Benefícios:
- Lógica DRY
- Fácil de manter
- Código mais claro e reutilizável
Refactor 2: AuthenticateUser
Service
Objetivo:
Tirar do SessionsController
a lógica de autenticação de usuário.
Antes:
if (user = User.authenticate_by(params.permit(:email_address, :password)))
start_new_session_for user
redirect_to home_path_for(user), notice: "Logged in successfully."
else
redirect_to new_session_path, alert: "Try another email address or password."
end
Depois:
user = AuthenticateUser.call(params[:email_address], params[:password])
if user
start_new_session_for user
redirect_to home_path_for(user), notice: "Logged in successfully."
else
redirect_to new_session_path, alert: "Try another email address or password."
end
Service criado:
class AuthenticateUser
def self.call(email_address, password)
User.authenticate_by(email_address: email_address, password: password)
end
end
Benefícios:
- Controller mais limpo
- Fácil de expandir para login social, 2FA etc.
- Separacão de responsabilidades clara
Conclusão
Esses dois pequenos Service Objects deixaram o projeto:
- Mais limpo
- Mais testável
- Pronto para crescer
Service Objects são uma forma poderosa de aplicar Clean Code e preparar sua aplicação Rails para o futuro.
Escrito por: [Leonardo Quadros Fragozo]