SlideShare a Scribd company logo
1 of 52
Aprendendo SOLID
  com exemplos
 Vinicius Baggio Fuentes ( @vinibaggio )
Atenção! Essa palestra
   pode ferir seus
    sentimentos!
$ whoami
Rails infelizmente fez
muita gente esquecer
 das boas práticas.

    Inclusive eu.
Rails: MUITAS
     convenções,
mas saiba quando você
   deve sair delas
Skinny Controller, Fat models,
           certo?
CUIDADO!
Fat ≠ Obese
Crie mais classes,
nao fique restrito a
      AR::B!
YMMV
SOLID

• Single Responsibility Rule (SRP)
• Open-Closed Principle (OCP)
• Liskov Substitution Principle (LSP)
• Interface Segregation Principle (ISP)
• Dependency Inversion Principle (DIP)
SRP


• Esse é óbvio.
class Post < ActiveRecord::Base
  belongs_to :author

 has_many :comments

 validates_presence_of :title, :body

 after_create :log_creation
 after_update :log_update
 after_destroy :log_deletion

  private

  def log_creation
    Log.create(:message => "Post '#{title}' was created.")
  end

  def log_update
    Log.create(:message => "Post '#{title}' was updated.")
  end

  def log_deletion
    Log.create(:message => "Post '#{title}' was deleted.")
  end

end
class Post < ActiveRecord::Base
  belongs_to :author

 has_many :comments            Pode, Arnaldo?
 validates_presence_of :title, :body

 after_create :log_creation
 after_update :log_update
 after_destroy :log_deletion

  private

  def log_creation
    Log.create(:message => "Post '#{title}' was created.")
  end

  def log_update
    Log.create(:message => "Post '#{title}' was updated.")
  end

  def log_deletion
    Log.create(:message => "Post '#{title}' was deleted.")
  end

end
Violação do SRP
• Callbacks são conveniente, mas são
  prejudiciais
• Chato de testar
• Comportamento que não tem nada
  relacionado com Post
• Comportamento inesperado (violação do
  Least Surprise Principle)
class Post < ActiveRecord::Base
  belongs_to :author

 has_many :comments

  validates_presence_of :title, :body
end
class AuditedPost
  def self.create(post_attributes)
    post = Post.create(post_attributes)
    Log.log_creation(post)

    post
  end

  def self.update(post, post_attributes)
    post.update_attributes(post_attributes)

    Log.log_update(post)

    post
  end

  def self.destroy(post)
    post.destroy

    Log.log_destruction(post)

    post
  end
end
OCP


• Open for extension, closed for modification
Que porra é essa?
class User < ActiveRecord::Base
  # ...
  def to_json(options=nil)
    # ...
  end

  def to_xml
    # ...
  end

  def to_atom
    # ...
  end
end


class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])

    respond_to do   |format|
      format.html   { render @user }
      format.json   { render :text => @user.to_json }
      format.atom   { render :text => @user.to_atom }
    end
  end
end
class User < ActiveRecord::Base
  # ...
  def to_json(options=nil)
    # ...
  end

  def to_xml
    # ...
  end

  def to_atom
    # ...
  end
end


class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])

    respond_to do   |format|
      format.html   { render @user }
      format.json   { render :text => @user.to_json }
      format.atom   { render :text => @user.to_atom }
    end
  end
end
Para adicionar um novo
  formato, eu preciso
  alterar o controller
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
                                           Horrível!
    respond_to do |format|
      format.html { render @user }
      format.json { render :text => @user.to_json }
      format.atom { render :text => @user.to_atom }
      format.jsonp { render :text => "#{params[:callback]}
(#{@user.to_json});" }
    end
  end
end

class ArticlesController < ApplicationController
  def show
    @article = Article.find(params[:id])

    respond_to do |format|
      format.html { render @article }
      format.json { render :text => @article.to_json }
      format.atom { render :text => @article.to_atom }
      format.jsonp { render :text => "#{params[:callback]}
(#{@article.to_json});" }
    end
  end
end
Nesse caso, a API de
Responders do Rails 3
   funciona bem!
class ApplicationController < ActionController::Base
  respond_to :html, :json, :atom, :jsonp
  # ...
end

class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    respond_with(@user)
  end
end

class ArticlesController < ApplicationController
  def show
    @article = Article.find(params[:id])
    respond_with(@article)
  end
end
Detectando cheiro de
  violação de OCP

• #is_a? / #is_kind_of?
• Reabrindo classes
LSP

• Especializações de alguma interface não
  devem mudar produtos de métodos pai
• Fácil de acontecer com Ruby, não
  precisamos respeitar assinaturas de
  método!
TypeError: can't dup Fixnum

 from (irb):2:in `dup'

 from (irb):2
irb :003 >
irb :001 > 5.respond_to? :dup
 => true




  TypeError: can't dup Fixnum
  
 from (irb):2:in `dup'
  
 from (irb):2
  irb :003 >
irb :001 > 5.respond_to? :dup
 => true

irb :002 > 5.dup


  TypeError: can't dup Fixnum
  
 from (irb):2:in `dup'
  
 from (irb):2
  irb :003 >
TypeError: can't dup Fixnum

 from (irb):2:in `dup'

 from (irb):2
irb :003 >
WTF?



TypeError: can't dup Fixnum

 from (irb):2:in `dup'

 from (irb):2
irb :003 >
WTF?
                  WTF?


TypeError: can't dup Fixnum

 from (irb):2:in `dup'

 from (irb):2
irb :003 >
WTF?
                     WTF?


WTF?
 TypeError:   can't dup Fixnum
   
 from (irb):2:in `dup'
   
 from (irb):2
   irb :003 >
WTF?
                     WTF?


WTF?
 TypeError:   can't dup Fixnum
   
 from (irb):2:in `dup'
                WTF?
   
 from (irb):2
   irb :003 >
WTF?
WTF?                 WTF?


WTF?
 TypeError:   can't dup Fixnum
   
 from (irb):2:in `dup'
                WTF?
   
 from (irb):2
   irb :003 >
WTF?
WTF?               WTF?
                  WTF?
WTF?
 TypeError:   can't dup Fixnum
   
 from (irb):2:in `dup'
                WTF?
   
 from (irb):2
   irb :003 >
WTF?
WTF?               WTF?
                  WTF?
WTF?
 TypeError:   can't dup Fixnum
   
 from (irb):2:in `dup'

  WTF?
   irb :003 >   WTF?
   
 from (irb):2
WTF?
WTF?         WTF?
       WTF? WTF?

WTF?
 TypeError:   can't dup Fixnum
   
 from (irb):2:in `dup'

  WTF?
   irb :003 >   WTF?
   
 from (irb):2
WTF?
WTF?               WTF?
     WTF? WTF?

WTF?        WTF? Fixnum
 TypeError: can't dup
   
 from (irb):2:in `dup'

 WTF?
   irb :003 >   WTF?
   
 from (irb):2
WTF?
WTF?               WTF?
 irb :001 > 5.respond_to? :dup
  => true
     WTF? WTF?

WTF?        WTF? Fixnum
 TypeError: can't dup
   
 from (irb):2:in `dup'

 WTF?
   irb :003 >   WTF?
   
 from (irb):2
WTF?
WTF?                  WTF?
  irb :001 > 5.respond_to? :dup
   => true
        WTF? WTF?
 irb :002 > 5.dup


WTF?           WTF? Fixnum
    TypeError: can't dup
    
 from (irb):2:in `dup'

  WTF?
    irb :003 >   WTF?
    
 from (irb):2
ISP

• Difícil de ver e exemplificar no Ruby por
  ser tipagem dinâmica
• Restringir/reduzir uma interface grande
  para um ‘cliente’
ISP [2]

• Rack Apps são ótimos exemplos disso!
• Para interface Rack funcionar, basta uma
  array com três itens:
  • Código da resposta, headers e corpo.
ISP [3]


• Ou seja, apps complexa de Rails, no final,
  retorna a mesma interface que a app a
  seguir
lambda {
    [200,
    {"Content-Type" => "text/plain"},
    "Hello World!"]
}
DIP


• Fácil de observar e implementar
module Outpost
  module Notifiers
    class Campfire
      def notify(outpost, campfire_adapter=Outpost::Campfire::TinderAdapter)
        campfire = campfire_adapter.new @subdomain, :token => @token
        room     = campfire.find_room_by_name @room

        status = outpost.last_status
        room.speak "System is #{status}: #{outpost.messages.join(',')}"
      end
    end
  end
end
module Outpost
  module Notifiers
    class Campfire
      def notify(outpost, campfire_adapter=Outpost::Campfire::TinderAdapter)
        campfire = campfire_adapter.new @subdomain, :token => @token
        room     = campfire.find_room_by_name @room

        status = outpost.last_status
        room.speak "System is #{status}: #{outpost.messages.join(',')}"
      end
    end
  end
end
DIP - Se quisermos usar outra lib,
                              basta usar outro adaptador


module Outpost
  module Notifiers
    class Campfire
      def notify(outpost, campfire_adapter=Outpost::Campfire::TinderAdapter)
        campfire = campfire_adapter.new @subdomain, :token => @token
        room     = campfire.find_room_by_name @room

        status = outpost.last_status
        room.speak "System is #{status}: #{outpost.messages.join(',')}"
      end
    end
  end
end
• SOLID é difícil e exige prática
• YMMV
• As violações normalmente não vêm
  isoladas!

• Leia LIVROS! Muita informação sobre o
  assunto

• Processo contínuo de aprendizado
That’s all, folks!
      Perguntas?

More Related Content

What's hot

Exception Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in RubyException Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in Ruby
Wen-Tien Chang
 

What's hot (20)

Get your teeth into Plack
Get your teeth into PlackGet your teeth into Plack
Get your teeth into Plack
 
JavaScript - From Birth To Closure
JavaScript - From Birth To ClosureJavaScript - From Birth To Closure
JavaScript - From Birth To Closure
 
Speedy TDD with Rails
Speedy TDD with RailsSpeedy TDD with Rails
Speedy TDD with Rails
 
Exception Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in RubyException Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in Ruby
 
Short Introduction To "perl -d"
Short Introduction To "perl -d"Short Introduction To "perl -d"
Short Introduction To "perl -d"
 
Unit Testing Lots of Perl
Unit Testing Lots of PerlUnit Testing Lots of Perl
Unit Testing Lots of Perl
 
Effective Doctrine2: Performance Tips for Symfony2 Developers
Effective Doctrine2: Performance Tips for Symfony2 DevelopersEffective Doctrine2: Performance Tips for Symfony2 Developers
Effective Doctrine2: Performance Tips for Symfony2 Developers
 
Effective Benchmarks
Effective BenchmarksEffective Benchmarks
Effective Benchmarks
 
Ruby for Java Developers
Ruby for Java DevelopersRuby for Java Developers
Ruby for Java Developers
 
Thor - RSLA - 13oct2009
Thor - RSLA - 13oct2009Thor - RSLA - 13oct2009
Thor - RSLA - 13oct2009
 
Smoking docker
Smoking dockerSmoking docker
Smoking docker
 
What's new in Perl 5.10?
What's new in Perl 5.10?What's new in Perl 5.10?
What's new in Perl 5.10?
 
Getting Testy With Perl6
Getting Testy With Perl6Getting Testy With Perl6
Getting Testy With Perl6
 
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
 
Devignition 2011
Devignition 2011Devignition 2011
Devignition 2011
 
Complex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBoxComplex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBox
 
Crafting Quality PHP Applications (ConFoo YVR 2017)
Crafting Quality PHP Applications (ConFoo YVR 2017)Crafting Quality PHP Applications (ConFoo YVR 2017)
Crafting Quality PHP Applications (ConFoo YVR 2017)
 
Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)Crafting Quality PHP Applications (PHP Joburg Oct 2019)
Crafting Quality PHP Applications (PHP Joburg Oct 2019)
 
Keeping objects healthy with Object::Exercise.
Keeping objects healthy with Object::Exercise.Keeping objects healthy with Object::Exercise.
Keeping objects healthy with Object::Exercise.
 
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
Dip Your Toes in the Sea of Security (ConFoo YVR 2017)
 

Viewers also liked

Apresentação programação orientada à objetos
Apresentação   programação orientada à objetosApresentação   programação orientada à objetos
Apresentação programação orientada à objetos
soncino
 
Conceitos básicos de programação orientada a objetos
Conceitos básicos de programação orientada a objetosConceitos básicos de programação orientada a objetos
Conceitos básicos de programação orientada a objetos
Leonardo Melo Santos
 

Viewers also liked (20)

ASP.NET MVC - Vinicius Quaiato
ASP.NET MVC - Vinicius QuaiatoASP.NET MVC - Vinicius Quaiato
ASP.NET MVC - Vinicius Quaiato
 
Apresentação programação orientada à objetos
Apresentação   programação orientada à objetosApresentação   programação orientada à objetos
Apresentação programação orientada à objetos
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
O que é código bonito?
O que é código bonito?O que é código bonito?
O que é código bonito?
 
Orientação a Objetos e Design Patterns
Orientação a Objetos e Design PatternsOrientação a Objetos e Design Patterns
Orientação a Objetos e Design Patterns
 
DNAD 2015 - Métricas de código, pra que te quero?
DNAD 2015 - Métricas de código, pra que te quero?DNAD 2015 - Métricas de código, pra que te quero?
DNAD 2015 - Métricas de código, pra que te quero?
 
Proposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações Web
Proposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações WebProposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações Web
Proposta: Métricas e Heurísticas para Detecção de Problemas em Aplicações Web
 
Você tem um xerife olhando seu código?
Você tem um xerife olhando seu código?Você tem um xerife olhando seu código?
Você tem um xerife olhando seu código?
 
Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...
Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...
Efeitos da Prática de Revisão de Código na Caelum: Um Estudo Preliminar em Du...
 
Como eu aprendi que testar software é importante?
Como eu aprendi que testar software é importante?Como eu aprendi que testar software é importante?
Como eu aprendi que testar software é importante?
 
Conheça a nova arquitetura do compilador do C# (DNAD 2015)
Conheça a nova arquitetura do compilador do C# (DNAD 2015)Conheça a nova arquitetura do compilador do C# (DNAD 2015)
Conheça a nova arquitetura do compilador do C# (DNAD 2015)
 
Build e release pipeline com docker
Build e release pipeline com dockerBuild e release pipeline com docker
Build e release pipeline com docker
 
ASP.NET Core com Linux, Docker e Azure
ASP.NET Core com Linux, Docker e AzureASP.NET Core com Linux, Docker e Azure
ASP.NET Core com Linux, Docker e Azure
 
ASP.NET Identity - O Novo componente de Membership do ASP.NET
ASP.NET Identity - O Novo componente de Membership do ASP.NETASP.NET Identity - O Novo componente de Membership do ASP.NET
ASP.NET Identity - O Novo componente de Membership do ASP.NET
 
Programação Orientada a Objetos - Conceitos básicos da linguagem JAVA
Programação Orientada a Objetos - Conceitos básicos da linguagem JAVAProgramação Orientada a Objetos - Conceitos básicos da linguagem JAVA
Programação Orientada a Objetos - Conceitos básicos da linguagem JAVA
 
Aplicações Conectadas com ASP.NET WebHooks
Aplicações Conectadas com ASP.NET WebHooksAplicações Conectadas com ASP.NET WebHooks
Aplicações Conectadas com ASP.NET WebHooks
 
ASP.NET MVC Core
ASP.NET MVC CoreASP.NET MVC Core
ASP.NET MVC Core
 
SOLID - Teoria e Prática
SOLID - Teoria e PráticaSOLID - Teoria e Prática
SOLID - Teoria e Prática
 
Conceitos básicos de programação orientada a objetos
Conceitos básicos de programação orientada a objetosConceitos básicos de programação orientada a objetos
Conceitos básicos de programação orientada a objetos
 
Programação orientada a objetos
Programação orientada a objetosProgramação orientada a objetos
Programação orientada a objetos
 

Similar to Aprendendo solid com exemplos

Scaling Twitter 12758
Scaling Twitter 12758Scaling Twitter 12758
Scaling Twitter 12758
davidblum
 
Java Bytecode Fundamentals - JUG.lv
Java Bytecode Fundamentals - JUG.lvJava Bytecode Fundamentals - JUG.lv
Java Bytecode Fundamentals - JUG.lv
Anton Arhipov
 
Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011
Anton Arhipov
 
Socket applications
Socket applicationsSocket applications
Socket applications
João Moura
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
Yi-Ting Cheng
 

Similar to Aprendendo solid com exemplos (20)

Monkeybars in the Manor
Monkeybars in the ManorMonkeybars in the Manor
Monkeybars in the Manor
 
Cramp websockets
Cramp websocketsCramp websockets
Cramp websockets
 
Scaling Twitter
Scaling TwitterScaling Twitter
Scaling Twitter
 
Scaling Twitter 12758
Scaling Twitter 12758Scaling Twitter 12758
Scaling Twitter 12758
 
Defly
DeflyDefly
Defly
 
Java Bytecode Fundamentals - JUG.lv
Java Bytecode Fundamentals - JUG.lvJava Bytecode Fundamentals - JUG.lv
Java Bytecode Fundamentals - JUG.lv
 
TDC 2015 - DSLs em Ruby
TDC 2015 - DSLs em RubyTDC 2015 - DSLs em Ruby
TDC 2015 - DSLs em Ruby
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011
 
Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010Código Saudável => Programador Feliz - Rs on Rails 2010
Código Saudável => Programador Feliz - Rs on Rails 2010
 
Socket applications
Socket applicationsSocket applications
Socket applications
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 
Adventurous Merb
Adventurous MerbAdventurous Merb
Adventurous Merb
 
Una Critica a Rails by Luca Guidi
Una Critica a Rails by Luca GuidiUna Critica a Rails by Luca Guidi
Una Critica a Rails by Luca Guidi
 
There and Back Again
There and Back AgainThere and Back Again
There and Back Again
 
Say Goodbye to Procedural Programming - Nick Sutterer
Say Goodbye to Procedural Programming - Nick SuttererSay Goodbye to Procedural Programming - Nick Sutterer
Say Goodbye to Procedural Programming - Nick Sutterer
 
JavaScript Cheatsheets with easy way .pdf
JavaScript Cheatsheets with easy way .pdfJavaScript Cheatsheets with easy way .pdf
JavaScript Cheatsheets with easy way .pdf
 
Design Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron PattersonDesign Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron Patterson
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Como programar un blog REST
Como programar un blog RESTComo programar un blog REST
Como programar un blog REST
 

Aprendendo solid com exemplos

  • 1. Aprendendo SOLID com exemplos Vinicius Baggio Fuentes ( @vinibaggio )
  • 2. Atenção! Essa palestra pode ferir seus sentimentos!
  • 4. Rails infelizmente fez muita gente esquecer das boas práticas. Inclusive eu.
  • 5.
  • 6. Rails: MUITAS convenções, mas saiba quando você deve sair delas
  • 7. Skinny Controller, Fat models, certo?
  • 9. Crie mais classes, nao fique restrito a AR::B!
  • 10. YMMV
  • 11. SOLID • Single Responsibility Rule (SRP) • Open-Closed Principle (OCP) • Liskov Substitution Principle (LSP) • Interface Segregation Principle (ISP) • Dependency Inversion Principle (DIP)
  • 12. SRP • Esse é óbvio.
  • 13. class Post < ActiveRecord::Base belongs_to :author has_many :comments validates_presence_of :title, :body after_create :log_creation after_update :log_update after_destroy :log_deletion private def log_creation Log.create(:message => "Post '#{title}' was created.") end def log_update Log.create(:message => "Post '#{title}' was updated.") end def log_deletion Log.create(:message => "Post '#{title}' was deleted.") end end
  • 14. class Post < ActiveRecord::Base belongs_to :author has_many :comments Pode, Arnaldo? validates_presence_of :title, :body after_create :log_creation after_update :log_update after_destroy :log_deletion private def log_creation Log.create(:message => "Post '#{title}' was created.") end def log_update Log.create(:message => "Post '#{title}' was updated.") end def log_deletion Log.create(:message => "Post '#{title}' was deleted.") end end
  • 15. Violação do SRP • Callbacks são conveniente, mas são prejudiciais • Chato de testar • Comportamento que não tem nada relacionado com Post • Comportamento inesperado (violação do Least Surprise Principle)
  • 16. class Post < ActiveRecord::Base belongs_to :author has_many :comments validates_presence_of :title, :body end
  • 17. class AuditedPost def self.create(post_attributes) post = Post.create(post_attributes) Log.log_creation(post) post end def self.update(post, post_attributes) post.update_attributes(post_attributes) Log.log_update(post) post end def self.destroy(post) post.destroy Log.log_destruction(post) post end end
  • 18. OCP • Open for extension, closed for modification
  • 19. Que porra é essa?
  • 20. class User < ActiveRecord::Base # ... def to_json(options=nil) # ... end def to_xml # ... end def to_atom # ... end end class UsersController < ApplicationController def show @user = User.find(params[:id]) respond_to do |format| format.html { render @user } format.json { render :text => @user.to_json } format.atom { render :text => @user.to_atom } end end end
  • 21. class User < ActiveRecord::Base # ... def to_json(options=nil) # ... end def to_xml # ... end def to_atom # ... end end class UsersController < ApplicationController def show @user = User.find(params[:id]) respond_to do |format| format.html { render @user } format.json { render :text => @user.to_json } format.atom { render :text => @user.to_atom } end end end
  • 22. Para adicionar um novo formato, eu preciso alterar o controller
  • 23. class UsersController < ApplicationController def show @user = User.find(params[:id]) Horrível! respond_to do |format| format.html { render @user } format.json { render :text => @user.to_json } format.atom { render :text => @user.to_atom } format.jsonp { render :text => "#{params[:callback]} (#{@user.to_json});" } end end end class ArticlesController < ApplicationController def show @article = Article.find(params[:id]) respond_to do |format| format.html { render @article } format.json { render :text => @article.to_json } format.atom { render :text => @article.to_atom } format.jsonp { render :text => "#{params[:callback]} (#{@article.to_json});" } end end end
  • 24. Nesse caso, a API de Responders do Rails 3 funciona bem!
  • 25. class ApplicationController < ActionController::Base respond_to :html, :json, :atom, :jsonp # ... end class UsersController < ApplicationController def show @user = User.find(params[:id]) respond_with(@user) end end class ArticlesController < ApplicationController def show @article = Article.find(params[:id]) respond_with(@article) end end
  • 26. Detectando cheiro de violação de OCP • #is_a? / #is_kind_of? • Reabrindo classes
  • 27. LSP • Especializações de alguma interface não devem mudar produtos de métodos pai • Fácil de acontecer com Ruby, não precisamos respeitar assinaturas de método!
  • 28. TypeError: can't dup Fixnum from (irb):2:in `dup' from (irb):2 irb :003 >
  • 29. irb :001 > 5.respond_to? :dup => true TypeError: can't dup Fixnum from (irb):2:in `dup' from (irb):2 irb :003 >
  • 30. irb :001 > 5.respond_to? :dup => true irb :002 > 5.dup TypeError: can't dup Fixnum from (irb):2:in `dup' from (irb):2 irb :003 >
  • 31. TypeError: can't dup Fixnum from (irb):2:in `dup' from (irb):2 irb :003 >
  • 32. WTF? TypeError: can't dup Fixnum from (irb):2:in `dup' from (irb):2 irb :003 >
  • 33. WTF? WTF? TypeError: can't dup Fixnum from (irb):2:in `dup' from (irb):2 irb :003 >
  • 34. WTF? WTF? WTF? TypeError: can't dup Fixnum from (irb):2:in `dup' from (irb):2 irb :003 >
  • 35. WTF? WTF? WTF? TypeError: can't dup Fixnum from (irb):2:in `dup' WTF? from (irb):2 irb :003 >
  • 36. WTF? WTF? WTF? WTF? TypeError: can't dup Fixnum from (irb):2:in `dup' WTF? from (irb):2 irb :003 >
  • 37. WTF? WTF? WTF? WTF? WTF? TypeError: can't dup Fixnum from (irb):2:in `dup' WTF? from (irb):2 irb :003 >
  • 38. WTF? WTF? WTF? WTF? WTF? TypeError: can't dup Fixnum from (irb):2:in `dup' WTF? irb :003 > WTF? from (irb):2
  • 39. WTF? WTF? WTF? WTF? WTF? WTF? TypeError: can't dup Fixnum from (irb):2:in `dup' WTF? irb :003 > WTF? from (irb):2
  • 40. WTF? WTF? WTF? WTF? WTF? WTF? WTF? Fixnum TypeError: can't dup from (irb):2:in `dup' WTF? irb :003 > WTF? from (irb):2
  • 41. WTF? WTF? WTF? irb :001 > 5.respond_to? :dup => true WTF? WTF? WTF? WTF? Fixnum TypeError: can't dup from (irb):2:in `dup' WTF? irb :003 > WTF? from (irb):2
  • 42. WTF? WTF? WTF? irb :001 > 5.respond_to? :dup => true WTF? WTF? irb :002 > 5.dup WTF? WTF? Fixnum TypeError: can't dup from (irb):2:in `dup' WTF? irb :003 > WTF? from (irb):2
  • 43. ISP • Difícil de ver e exemplificar no Ruby por ser tipagem dinâmica • Restringir/reduzir uma interface grande para um ‘cliente’
  • 44. ISP [2] • Rack Apps são ótimos exemplos disso! • Para interface Rack funcionar, basta uma array com três itens: • Código da resposta, headers e corpo.
  • 45. ISP [3] • Ou seja, apps complexa de Rails, no final, retorna a mesma interface que a app a seguir
  • 46. lambda { [200, {"Content-Type" => "text/plain"}, "Hello World!"] }
  • 47. DIP • Fácil de observar e implementar
  • 48. module Outpost module Notifiers class Campfire def notify(outpost, campfire_adapter=Outpost::Campfire::TinderAdapter) campfire = campfire_adapter.new @subdomain, :token => @token room = campfire.find_room_by_name @room status = outpost.last_status room.speak "System is #{status}: #{outpost.messages.join(',')}" end end end end
  • 49. module Outpost module Notifiers class Campfire def notify(outpost, campfire_adapter=Outpost::Campfire::TinderAdapter) campfire = campfire_adapter.new @subdomain, :token => @token room = campfire.find_room_by_name @room status = outpost.last_status room.speak "System is #{status}: #{outpost.messages.join(',')}" end end end end
  • 50. DIP - Se quisermos usar outra lib, basta usar outro adaptador module Outpost module Notifiers class Campfire def notify(outpost, campfire_adapter=Outpost::Campfire::TinderAdapter) campfire = campfire_adapter.new @subdomain, :token => @token room = campfire.find_room_by_name @room status = outpost.last_status room.speak "System is #{status}: #{outpost.messages.join(',')}" end end end end
  • 51. • SOLID é difícil e exige prática • YMMV • As violações normalmente não vêm isoladas! • Leia LIVROS! Muita informação sobre o assunto • Processo contínuo de aprendizado
  • 52. That’s all, folks! Perguntas?

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n