Coisas que aprendi e
quero passar adiante
Lucas Húngaro
@lucashungaro
GoNow Tecnologia
Lucas
Culinária
Tecnologia
Apple
Home Cinema
Futebol
Café
Drinks
Games MúsicaSoftware
Cinema
Ruby
Duas partes
Serviços e bibliotecas
O que usei e recomendo
Gems e Plugins
bullet
oink
query_reviewer
rails_indexes
kasket
}db performance
& optimization
} caching
} profiling
cachy
Oink
Aug 12 11:31:15 Iron-Man rails[9541]: Memory usage: 101938 | PID: 9541
Aug 12 11:31:15 Iron-Man rails[9541]: Instanti...
Cachy
versionamento
evita o “dog pile effect”
caches interdependentes
várias outras features muito interessantes
http://gi...
Master/Slave
Para ActiveRecord, DBCharmer
Filas: Resque
Simples, fácil e eficiente
Resque
Resque
monitoramento
plugins
cuidado: json e símbolos
cuidado: tarefas antes seriais passam a ser paralelas
cuidado: local...
Arquitetura
Web App == DatabaseView
Utilize filas, caching, server push (Comet, Sockets etc)
Processamento síncrono mínimo
Cloud Computing
Muito cuidado com o hype
Hype não é algo ruim por si só, pois leva a mais inovação mas, sem o devido cuida...
Amazon
Noisy neighbors
Latência e I/O
Superpopulação
Caso a caso
Evite o hype
Benchmark
Amazon
Staging/QA/Homologação
Processamento paralelo/distribuído
CDN }The Good
Banco de Dados
I/O intensiva{The Bad
Aument...
Amazon
http://goo.gl/0fgw
Código eficiente
E como padrões ineficientes podem te atrapalhar
Maturidade
O conhecimento, tanto individual, quanto o do grupo, evolui de forma lenta
Excesso de observers/callbacks
Micro-gerenciamento
Ineficiente
Bug prone
Caching
Smart Keys FTW!
aka Versionamento
class User < ActiveRecord::Base
has_many :search_terms, :dependent => :destroy,
:order => "term ASC"
def save_search_term(...
def saved_search_terms
Rails.cache.fetch(cache_key_for_saved_searches,
:expires_in => 30.days) do
self.search_terms
end
en...
cache_proxy
http://github.com/lucashungaro/cache_proxy
Programação defensiva
Não assuma coisas
Principalmente sobre entrada
(robustness principle)
“Be conservative in what you send;
be liberal in what you accept.”
Postel’s Law
Programação defensiva
Gather input
Perform work
Deliver results
Handle errors
Law of Demeter
“Each unit should only talk to its
friends; don't talk to strangers.”
class Company < ActiveRecord::Base
has_many :addresses
def formatted_city
self.addresses.first.city.name
end
end
def forma...
SOLID
Jim Weirich
Amanhã, 17h
Single Responsibility
Principle
Uma e apenas uma razão para mudar
Negócios + Persistência
Esconde o domínio
Falta: flexibilidade, isolamento
Fat Models
Camadas Tudo junto e misturado
class ActivityService
def initialize(actor)
@actor = actor
@activities = []
end
def register(type, action, options = {})
r...
class SearchService
def initialize(classes = [])
@classes = classes
end
def add_class(klass)
@classes << klass
end
def exe...
let(:service) { SearchService.new([User]) }
it "should pass default options to the search wrapper" do
default_options = {
...
let(:service) { SearchService.new([User]) }
it "should pass default options to the search wrapper" do
default_options = {
...
Conclusões
Guidelines, not laws
Mantra
Se é difícil de testar em
isolamento, está mal projetado*
* 99,99% de chance ;)
Checklists
Uma boa forma de adquirir bons hábitos
ser explícita
ter um nome
ter uma localização clara
Lógica importante deve:
Ao finalizar spec e objeto:
aplica DRY?
tem apenas uma responsabilidade?
depende de componentes que mudam
menos que ele?
Zen of Python
>>> import this
Obrigado
Referências
http://gist.github.com/524462
Upcoming SlideShare
Loading in …5
×

Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010

6,884 views

Published on

Palestra apresentada na RubyConf Brasil 2010 mostrando dicas de bibliotecas úteis para aplicações web escritas em Rails e maneiras para conseguir código flexível, fácil de testar e modificar utilizando SOLID, defensive programming e outras técnicas.

Published in: Technology
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
6,884
On SlideShare
0
From Embeds
0
Number of Embeds
3,278
Actions
Shares
0
Downloads
23
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide

Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010

  1. 1. Coisas que aprendi e quero passar adiante Lucas Húngaro @lucashungaro GoNow Tecnologia
  2. 2. Lucas Culinária Tecnologia Apple Home Cinema Futebol Café Drinks Games MúsicaSoftware Cinema Ruby
  3. 3. Duas partes
  4. 4. Serviços e bibliotecas O que usei e recomendo
  5. 5. Gems e Plugins bullet oink query_reviewer rails_indexes kasket }db performance & optimization } caching } profiling cachy
  6. 6. Oink Aug 12 11:31:15 Iron-Man rails[9541]: Memory usage: 101938 | PID: 9541 Aug 12 11:31:15 Iron-Man rails[9541]: Instantiation Breakdown: Total: 39 | User: 20 | FeedItem: 10 | Tag: 9
  7. 7. Cachy versionamento evita o “dog pile effect” caches interdependentes várias outras features muito interessantes http://github.com/grosser/cachy
  8. 8. Master/Slave Para ActiveRecord, DBCharmer
  9. 9. Filas: Resque Simples, fácil e eficiente
  10. 10. Resque
  11. 11. Resque monitoramento plugins cuidado: json e símbolos cuidado: tarefas antes seriais passam a ser paralelas cuidado: locale dos workers (sobem outro contexto) O Resque adiciona um componente à sua infra-estrutura, mas é feito para ser facilmente monitorado, estendido e distribuído. Muitas vantagens a um preço muito baixo (e “improvisar” filas no banco de dados da sua app pode custar bem mais caro)
  12. 12. Arquitetura Web App == DatabaseView Utilize filas, caching, server push (Comet, Sockets etc) Processamento síncrono mínimo
  13. 13. Cloud Computing Muito cuidado com o hype Hype não é algo ruim por si só, pois leva a mais inovação mas, sem o devido cuidado, podemos “errar por empolgação”
  14. 14. Amazon Noisy neighbors Latência e I/O Superpopulação Caso a caso Evite o hype Benchmark
  15. 15. Amazon Staging/QA/Homologação Processamento paralelo/distribuído CDN }The Good Banco de Dados I/O intensiva{The Bad Aumento instantâneo de throughput
  16. 16. Amazon http://goo.gl/0fgw
  17. 17. Código eficiente E como padrões ineficientes podem te atrapalhar
  18. 18. Maturidade O conhecimento, tanto individual, quanto o do grupo, evolui de forma lenta
  19. 19. Excesso de observers/callbacks Micro-gerenciamento Ineficiente Bug prone Caching
  20. 20. Smart Keys FTW! aka Versionamento
  21. 21. class User < ActiveRecord::Base has_many :search_terms, :dependent => :destroy, :order => "term ASC" def save_search_term(term) self.update_attribute(:last_saved_search_at, Time.now.utc) search_terms.create(:term => term) end def remove_search_term(term_id) self.update_attribute(:last_saved_search_at, Time.now.utc) self.search_terms.destroy(term_id) end
  22. 22. def saved_search_terms Rails.cache.fetch(cache_key_for_saved_searches, :expires_in => 30.days) do self.search_terms end end private def cache_key_for_saved_searches timestamp = self[:last_saved_search_at].to_s.gsub(" ","_").gsub(":","-") "User/#{self[:id]}/search_terms-#{timestamp}" end end
  23. 23. cache_proxy http://github.com/lucashungaro/cache_proxy
  24. 24. Programação defensiva Não assuma coisas Principalmente sobre entrada
  25. 25. (robustness principle) “Be conservative in what you send; be liberal in what you accept.” Postel’s Law
  26. 26. Programação defensiva Gather input Perform work Deliver results Handle errors
  27. 27. Law of Demeter “Each unit should only talk to its friends; don't talk to strangers.”
  28. 28. class Company < ActiveRecord::Base has_many :addresses def formatted_city self.addresses.first.city.name end end def formatted_city main_address.city.name end private def main_address self.addresses.first end
  29. 29. SOLID Jim Weirich Amanhã, 17h
  30. 30. Single Responsibility Principle Uma e apenas uma razão para mudar
  31. 31. Negócios + Persistência Esconde o domínio Falta: flexibilidade, isolamento Fat Models
  32. 32. Camadas Tudo junto e misturado
  33. 33. class ActivityService def initialize(actor) @actor = actor @activities = [] end def register(type, action, options = {}) raise ActionrgumentError("Every action needs a valid object") unless options[:object] (...) # complex treatment of the activity data end def process(queue_manager = Resque) queue_manager.enqueue(ActivityProcessor, @activities, I18n.locale) end (...) end SOLID: SRP: a razão para mudar se torna única - apenas a formatação das opções. Quem cuida da busca é o wrapper. OCP: fechada para modificação da implementação, mas aberta para extensão via modificação do wrapper e injeção da dependência DIP: duck typing + injeção de dependência - a dependência é gerenciada pelo cliente, liberando o código e tornando-o mais flexível
  34. 34. class SearchService def initialize(classes = []) @classes = classes end def add_class(klass) @classes << klass end def execute(query, options = {}, wrapper = ThinkingSphinx) (...) # options processing (defaults and so on) wrapper.search(query, options_for_engine) end (...) end SOLID: SRP: a razão para mudar se torna única - apenas a formatação das opções. Quem cuida da busca é o wrapper. OCP: fechada para modificação da implementação, mas aberta para extensão via modificação do wrapper e injeção da dependência DIP: duck typing + injeção de dependência - a dependência é gerenciada pelo cliente, liberando o código e tornando-o mais flexível
  35. 35. let(:service) { SearchService.new([User]) } it "should pass default options to the search wrapper" do default_options = { :page => 1, :per_page => 20, :match_mode => :extended } ThinkingSphinx.expects(:search)... # suppressed service.execute("teste") end Sem utilizar a injeção de dependência, acabamos manipulando o comportamento da classe diretamente, revelando a falta de flexibilidade do código.
  36. 36. let(:service) { SearchService.new([User]) } it "should pass default options to the search wrapper" do default_options = { :page => 1, :per_page => 20, :match_mode => :extended } wrapper = mock('search_wrapper') wrapper.expects(:search)... # suppressed service.execute("teste", {}, wrapper) end Com a injeção da dependência, podemos utilizar objetos fake para especificar o comportamento esperado sem setup adicional, graças ao duck typing. Também conseguimos o efeito descrito em “Mock roles, not object states” (http://www.infoq.com/ news/2008/08/Mock-Roles-Pryce-and-Freeman)
  37. 37. Conclusões Guidelines, not laws
  38. 38. Mantra Se é difícil de testar em isolamento, está mal projetado* * 99,99% de chance ;)
  39. 39. Checklists Uma boa forma de adquirir bons hábitos
  40. 40. ser explícita ter um nome ter uma localização clara Lógica importante deve:
  41. 41. Ao finalizar spec e objeto: aplica DRY? tem apenas uma responsabilidade? depende de componentes que mudam menos que ele?
  42. 42. Zen of Python >>> import this
  43. 43. Obrigado
  44. 44. Referências http://gist.github.com/524462

×