boas práticas de design em aplicações ruby on rails
DESCRIPTION
5º Encontro Guru Sorocaba - Secot UfscarTRANSCRIPT
BOAS PRÁTICASDE DESIGN EMAPLICAÇÕES RAILSRINALDI FONSECArinaldifonseca.com@rinaldifonseca
sábado, 12 de maio de 12
sábado, 12 de maio de 12
UNCLE BOBMARTIN FOWLERSANDI METZE OUTROS
VAMOS CONSIDERAR PESSOAS COMO:
sábado, 12 de maio de 12
CLEAN CODEDESIGN PATTERNSSOLIDTODOS NÓS JÁ OUVIMOS FALAR
sábado, 12 de maio de 12
APLICAR NA PRÁTICAÉ DIFÍCIL
sábado, 12 de maio de 12
VAMOSPENSARNAESSÊNCIA
sábado, 12 de maio de 12
O DESIGN
sábado, 12 de maio de 12
O QUE É DESIGN??
sábado, 12 de maio de 12
O CÓDIGO
sábado, 12 de maio de 12
A ARTEDE ORGANIZARO CÓDIGO
sábado, 12 de maio de 12
CADA LINHACADA CLASSECADA TESTEFAZ PARTE DO DESIGN
sábado, 12 de maio de 12
E QUAL É O OBJETIVODO DESIGN?
sábado, 12 de maio de 12
REDUZIR O CUSTODA MUDANÇA
sábado, 12 de maio de 12
VAMOS PENSARQUE O CÓDIDODEVE FUNCIONAR HOJEE APENAS ISSO.
sábado, 12 de maio de 12
SER FÁCIL DE MUDARPARA SEMPRE.
DEVE
sábado, 12 de maio de 12
FIM DA PARTE 1
sábado, 12 de maio de 12
DICAS PRÁTICAS
sábado, 12 de maio de 12
AVISO:
O que vou falar, NÃO épapo de Javeiro =)
sábado, 12 de maio de 12
USAR CLASSES DE SERVIÇO
A.K.A. SERVICES
DICA 1
sábado, 12 de maio de 12
Rails e o MVC
sábado, 12 de maio de 12
FAT MODELSTHIN CONTROLLERS
sábado, 12 de maio de 12
DDD
DOMAIN DRIVEN DESIGN
ERIC EVANS
sábado, 12 de maio de 12
As vezes, lidamos com “coisas” que não se encaixam emdeterminados objetos
sábado, 12 de maio de 12
APPLICATION SERVICEDOMAIN SERVICEINFRASTRUCTURE SERVICE
sábado, 12 de maio de 12
Application Service
class AccountCSVExporter def self.to_csv(account) CSV.generate do |csv| account.transactions.each do |transaction| csv << [transaction.amount, transaction.created_on] end end endend
sábado, 12 de maio de 12
Domain Service
class FundsTransferService def self.transfer(from, to, amount) Account.transaction do from.debit amount to.credit amount end endend
sábado, 12 de maio de 12
Infrastructure Service
class MessagingService def self.overdrawn_account_sms(account) Rails.queue.push SmsJob, "#{account.number}!" endend
sábado, 12 de maio de 12
ENTITIES ANDVALUE OBJECTS
DICA 2
sábado, 12 de maio de 12
ENTITIES
Objetos identificáveis por suas identidades
São mutáveis(mantendo a identidade)
Possuem um ciclo de vida na aplicação
sábado, 12 de maio de 12
class Order < ActiveRecord::Base belongs_to :user has_one :addressend
class Address < ActiveRecord::Base belongs_to :orderend
sábado, 12 de maio de 12
VALUE OBJECTS
Objetos identificáveis por seu valores
São imutáveis
Descrevem “coisas”
sábado, 12 de maio de 12
class Address attr_reader :street, :city
def initialize(street, city) @street, @city = street, city end
end
sábado, 12 de maio de 12
class Order < ActiveRecord::Base belongs_to :user composed_of :address, :mapping => [%w(address_street street), %w(address_city city)]
end
sábado, 12 de maio de 12
PRESENTERS
DICA 3
sábado, 12 de maio de 12
*PRESENTERS*EXHIBTI OBJECTS
DECORATORSAttach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality. / Gang of Four
sábado, 12 de maio de 12
Lógica na View
<% if user_signed_in? %><%= product.name %><% else %><%= link_to product.name, product_path(product) %><% end %>
sábado, 12 de maio de 12
BasePresenter
require “delegate”class BasePresenter < SimpleDelegator attr_accessor :context
def initialize(model, context = nil, objects = []) objects.each do |key, value| self.class.send :define_method, key do value end end
@context = context super model endend
sábado, 12 de maio de 12
BasePresenter
class ProductPresenter < BasePresenter def display_name if user name else context.link_to name, context.product_path(self) end end
def display_description context.render “products/description”, :product => self endend
sábado, 12 de maio de 12
PresenterHelper
module PresenterHelper def present(presenter_class, model, objects) presenter = presenter_class.new(model, self, objects) yield presenter if block_given? presenter end
end
sábado, 12 de maio de 12
Utilização
<% present ProductPresenter, @product, :user => current_user do |presenter| %>
<%= presenter.display_name %> <%= presenter.display_description %>
<% end %>
sábado, 12 de maio de 12
ADAPTERS
DICA 4
sábado, 12 de maio de 12
ADAPTAR A INTERFACEDE UMA CLASSE
sábado, 12 de maio de 12
DEPENDÊNCIASEXTERNAS
GRANDES CHANCES DE MUDAR
sábado, 12 de maio de 12
Exemplo:
Gem Koalagithub.com/arsduo/koala
@graph = Koala::Facebook::API.new(oauth_access_token)@friends = @graph.get_connections("me", "friends")
sábado, 12 de maio de 12
Criando um Adapterclass FacebookAdapter attr_accessor :access_token, :adapter
def initialize(access_token, adapter = Koala::Facebook::API) @access_token = access_token @adapter = adapter.new(access_token) end
def friends adapter.get_connections("me", "friends", :fields => "name") endend
sábado, 12 de maio de 12
FINALIZANDO...
Ao codificar, vamospensar no DESIGN
sábado, 12 de maio de 12
OBRIGADO
sábado, 12 de maio de 12