Model of the colossus @ Rupy Brazil 2013
-
date post
12-Sep-2014 -
Category
Technology
-
view
920 -
download
2
description
Transcript of Model of the colossus @ Rupy Brazil 2013
![Page 1: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/1.jpg)
Model of the Colossus
![Page 2: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/2.jpg)
Mauro quem...
![Page 3: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/3.jpg)
![Page 4: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/4.jpg)
RSpec Best Friends
![Page 5: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/5.jpg)
maurogeorge.com.br
![Page 6: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/6.jpg)
Seu model, um grande colosso
![Page 7: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/7.jpg)
Seu model, um grande colosso
Rails 15 minutes blogMVC
Rails wayAplicações grandes
37 Signals stackERB
MySQLMiniTest
Fat Models, Skinny Controllers
Prime stackHaml
PostgreSQLRspec/Cucumber
Skinny models, controllers, and a service layer
![Page 8: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/8.jpg)
AR quebra o SRP
Alto acoplamentoCallbackObserverFinders
Falta de coesãoPersiste dados
Envia e-mailAcessa Api externas
![Page 9: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/9.jpg)
Anti-pattern
Model gerando conteúdo para a view
![Page 10: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/10.jpg)
class User < ActiveRecord::Base
# ...
def info %Q{ <ul> <li>#{name}</li> <li>#{email}</li> </ul> } endend
app/models/user.rb
Anti-pattern: Model gerando conteudo para a view
Alto acoplamento
Falta de coesão
![Page 11: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/11.jpg)
require 'delegate'
class UserDecorator < SimpleDelegator
def info %Q{ <ul> <li>#{name}</li> <li>#{email}</li> </ul> } endend
app/decorators/user_decorator.rb
Solução: Decorator
Baixo acoplamento
Alta coesão
# Exemplouser = User.find(1)user_decorator = UserDecorator.new(user)user_decorator.infouser_decorator.name
![Page 12: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/12.jpg)
class User < ActiveRecord::Base
# ...
def wrote_post?(post) if post.user_id == id "<p>O post #{post.title} foi escrito por #{name}</p>" end endend
app/models/user.rb
Anti-pattern: Model gerando conteudo para a view
Alto acoplamento
Falta de coesão
Método de Postou User
![Page 13: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/13.jpg)
class WritterPostPresenter
def initialize(user, post) @user, @post = user, post end
def post_is_wrote_by_writter? if wrote_post? "<p>O post #{post.title} foi escrito por #{user.name}</p>" end end
private
attr_reader :user, :post
def wrote_post? user == post.user endend
app/presenters/writter_post_presenter.rb
Solução: Presenter
Baixo acoplamento
Alta coesão
# Exemplouser = User.find(1)post = Post.find(1)writter_post_presenter = WritterPostPresenter.new(user, post)writter_post_presenter.post_is_wrote_by_writter?
![Page 14: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/14.jpg)
Presenters, decorators, exhibit, View Objects e helpers???
HelpersProcedurais
DecoratorsPara uma única entidade
PresentersPara multiplas entidades
![Page 15: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/15.jpg)
Anti-pattern
Model Callbacks
![Page 16: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/16.jpg)
class Post < ActiveRecord::Base
# ...
after_save :notify_users
# ...
private
def notify_users NotifyMailer.delay.notify(self) endend
app/models/post.rb
Anti-pattern: Model Callbacks
Alto acoplamento
Falta de coesão
Testes lentos
![Page 17: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/17.jpg)
class PostCreator
def initialize(post) @post = post end
def save post.save && notify_users end
private
attr_reader :post
def notify_users NotifyMailer.delay.notify(post) endend
app/models/post_creator.rb
Solução: PORO model
Baixo acoplamento
Alta coesão
Testes rápidos
![Page 18: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/18.jpg)
class PostsController < ApplicationController
# ..
def create @post = current_user.posts.new(post_params) if redirect_to posts_path, notice: "Post criado com sucesso!" else render 'new' end endend
app/controllers/posts_controller.rb
Solução: PORO model
@post.savePostCreator.new(@post).save
![Page 19: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/19.jpg)
Anti-pattern
Model salvando N models
![Page 20: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/20.jpg)
class User < ActiveRecord::Base
# ...
accepts_nested_attributes_for :postsend
app/models/user.rb
Anti-pattern: Model salvando N models
Alto acoplamento
Falta de coesão
![Page 21: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/21.jpg)
class UserWithPost include ActiveModel::Model
attr_accessor :user_name, :user_email, :post_title, :post_content validates :user_name, :user_email, :post_title, :post_content, presence: true
def save return false unless valid? user = User.create(name: user_name, email: user_email) user.posts.create(title: post_title, content: post_content) true end
end
app/models/app/models/user_with_post.rb
Solução: Form Object
Baixo acoplamento
Alta coesão
# Exemploparams = { user_name: "Mauro", user_email: "[email protected]",
post_title: "Post 1", post_content: "Content"}user_with_post = UserWithPost.new(params)user_with_post.save
![Page 22: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/22.jpg)
Anti-pattern
Scopes para um único problema
![Page 23: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/23.jpg)
class Post < ActiveRecord::Base
# ...
scope :from, ->(user) { where(user_id: user.id) } scope :recents, -> { order(created_at: :asc) } scope :top_likeds, -> { order(like_count: :asc) } scope :top_from, ->(user) { from(user).recents.top_likeds }
# ...
end
app/models/post.rb
Anti-pattern: Scopes para um único problema
Falta de coesão
![Page 24: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/24.jpg)
class TopPostQuery
def initialize(relation = Post.all) @relation = relation.extending(Scopes) end
def top_from(user) @relation.from(user).recents.top_likeds end
module Scopes
def from(user) where(user_id: user.id) end
def recents order(created_at: :asc) end
def top_likeds order(like_count: :asc) end# ...
app/queries/top_post_query.rb
Solução: Query object
Alta coesão
# Exemplouser = User.find(1)top_post_query = TopPostQuery.newtop_post_query.top_from(user)
![Page 25: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/25.jpg)
Anti-pattern
ActiveSupport::Concerns
![Page 26: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/26.jpg)
module Likeable extend ActiveSupport::Concern
def liked_by(user) return false if user_already_liked?(user) up_one_like add_user_as_voted(user) end
def unliked_by(user) return false unless user_already_liked?(user) down_one_like remove_user_as_voted(user) end
private
attr_reader :likeable, :user
def up_one_like # ... end
# ...
def down_one_like # ... end
def add_user_as_voted(user) # ... end
def remove_user_as_voted(user) # ... end
def user_already_liked?(user) # ... endend
app/models/concerns/likeable.rb
Anti-pattern: ActiveSupport::Concerns
Alto acoplamento
Falta de coesão
![Page 27: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/27.jpg)
class Post < ActiveRecord::Base include Likeable
# ...end
app/models/post.rb
Anti-pattern: ActiveSupport::Concerns
Esconde responsabilidade
![Page 28: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/28.jpg)
class LikeManager
def initialize(likeable, user) @likeable, @user = likeable, user end
def like return false if user_already_liked? up_one_like add_user_as_voted end
def unlike return false unless user_already_liked? down_one_like remove_user_as_voted end
private
attr_reader :likeable, :user
def up_one_like # ... end
def down_one_like # ... end
def add_user_as_voted # ... end
def remove_user_as_voted # ... end
def user_already_liked? # ... endend
app/services/like_manager.rb
Solução: Service
Baixo acoplamento
Alta coesão
Única responsabilidade
Duck Typing
# Exemplouser = User.find(1)post = Post.find(1)like_manager = LikeManager.new(post, user)like_manager.likelike_manager.unlike
![Page 29: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/29.jpg)
Bad Smells
Meu Model está virando um Colosso?
![Page 30: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/30.jpg)
class Post < ActiveRecord::Base
# ...
def popular_comments # ... end
def most_viewed_comment # ... end
def most_replied_comment # ... endend
app/models/post.rb
Bad Smell: N métodos com nome de outra entidade
![Page 31: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/31.jpg)
class Post < ActiveRecord::Base
# ...
def self.most_popular_from(user) self.top_posts_from(user) self.more_social_media_repercussion_from(user) # ... end
private
def self.top_posts_from(user) # ... end
def self.more_social_media_repercussion_from(user) # ... endend
app/models/post.rb
Bad Smell: N métodos recebendo o mesmo paramêtro
![Page 32: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/32.jpg)
class Post < ActiveRecord::Base
# ...
def self.most_popular self.most_commented self.more_social_media_repercussion # ... end
private
def self.most_commented # ... end
def self.more_social_media_repercussion # ... endend
app/models/post.rb
Bad Smell: N métodos privados que são usados em apenas um método
![Page 33: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/33.jpg)
Bad Smell
Classe gigante(Provavelmente uma God Class)
Prefira N classes pequenas
![Page 34: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/34.jpg)
Futuro
DCIFuncional
![Page 35: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/35.jpg)
Conclusão
Crie classes
Quebre Model e Classes grandes em classes menores
Divida responsabilidades
Classes que façam apenas uma coisa bem feita
![Page 36: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/36.jpg)
Obrigado
![Page 37: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/37.jpg)
maurogeorge.com.br
![Page 38: Model of the colossus @ Rupy Brazil 2013](https://reader034.fdocuments.net/reader034/viewer/2022051608/5412be658d7f72314e8b46e0/html5/thumbnails/38.jpg)
Referências
http://rubyweekly.com/archive/124.html
http://rubyweekly.com/archive/126.html
http://robots.thoughtbot.com/post/14825364877/evaluating-alternative-decorator-
implementations-in
http://mikepackdev.com/blog_posts/31-exhibit-vs-presenter
samuelmullen.com/2013/05/the-problem-with-rails-callbacks
http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-
models/
http://rubysource.com/ddd-for-rails-developers-part-1-layered-architecture/
http://blog.plataformatec.com.br/2012/03/barebone-models-to-use-with-actionpack-
in-rails-4-0/
http://www.youtube.com/watch?v=DC-pQPq0acs
http://objectsonrails.com/