SlideShare uma empresa Scribd logo
1 de 111
Baixar para ler offline
design de aplicações
orientadas a objeto
uma visão rubista
hello
DEPRECATED PHOTO
Elaine Naomi Watanabe
Desenvolvedora de Software (Plataformatec)
Mestre em Ciência da Computação (USP)
github.com/elainenaomi
twitter.com/elaine_nw
http://careers.plataformatec.com.br
quais são os conceitos básicos de orientação a objeto
como identificar problemas na nossa base de código
como melhorar o design do nosso código
o que vamos ver?
orientação a objeto
uma versão super resumida
Objeto
Classe
Herança
Polimorfismo
Composição
objetos + mensagens = app
no mundo do Ruby...
$ gem install rails
$ gem install rails
+ Rails way
ViewModel
Controller
apresentação
intermediador
dados +
lógica de negócio
e se o projeto começa a crescer?
+ Funcionalidades
+ Funcionalidades
+ Modificações
+ Funcionalidades
+ Modificações
+ Bugs
Tamanho da base de código
Tempoparadeploy
como reconhecer os
sintomas?
Muitas regras de negócio nos controllers
Métodos muito longos
Classes muito grandes
Excesso de callbacks (controllers/models)
Dificuldade para escrever testes
Classes de difícil manutenção
Ctrl + F / ⌘ + F para qualquer alteração
Arquivos constantemente alterados
e agora, como faz?
DRY
don't repeat yourself
Helpers
Presenters
Single Table Inheritance
Polymorphic Association
Concerns (cuidado!)
Service Objects
Uso de Plain Old Ruby Object (PORO)
Casos de uso
Regras de negócio explícitas
class ReserveBookService
attr_reader :user, :book, :notification_service
def initialize(user, book, notification_service)
@user = user
@book = book
@notification_service = notification_service
end
def confirm!
user.books << book
notification_service.reservation_completed(user, book)
end
end
Mais padrões
Value Objects
Form Objects
Query Objects
View Objects
Policy Objects
http://bit.ly/object_patterns
SOLID
Single Responsibility Principle
O que a minha classe faz?
Indicativo de problemas: usar "e" ou "ou" na explicação
Métodos relacionados?
Uma única razão para mudar?
Alterações com efeitos previsíveis?
class BooksUser < ApplicationRecord
belongs_to: :book
belongs_to: :user
after_commit :send_notification_reservation_completed
def send_notification_reservation_completed
NotificationService.reservation_completed(user, book)
end
end
class BooksUser < ApplicationRecord
belongs_to: :book
belongs_to: :user
after_commit :send_notification_reservation_completed
def send_notification_reservation_completed
NotificationService.reservation_completed(user, book)
end
end
Uma classe de persistência não deveria saber sobre
notificações a um usuário, por ex.
Que tal um Service Object para isso?
class ReserveBookService
attr_reader :user, :book, :notification_service
def initialize(user, book, notification_service)
@user = user
@book = book
@notification_service = notification_service
end
def confirm!
user.books << book
notification_service.reservation_completed(user, book)
end
end
Open/Closed Principle
Adicionar nova regra = modificar uma ou mais classes?
Se sim, é um indicativo de problema
Aberto para extensão, fechado para modificação
Defina interfaces/super classes
Reduza o acoplamento
class FinancialReport
def generate(account, file_format)
case file_format
when :csv
file = FormatCSV.generate_file(account.transactions)
when :xml
file = XML.parse_list(account.transactions)
end
Mailer.send(account.email, file)
end
end
class FinancialReport
def generate(account, file_format)
case file_format
when :csv
file = FormatCSV.generate_file(account.transactions)
when :xml
file = XML.parse_list(account.transactions)
when :pdf
file = PDFGenerator.create(account.transactions)
end
Mailer.send(account.email, file)
end
end edição
class FinancialReport
def generate(account, file_format)
case file_format
when :csv
file = FormatCSV.generate_file(account.transactions)
when :xml
file = XML.parse_list(account.transactions)
when :pdf
file = PDFGenerator.create(account.transactions)
end
Mailer.send(account.email, file)
end
end
class FinancialReport
def generate(account, file_creator)
file = file_creator.create(account.transactions)
Mailer.send(account.email, file)
end
end
class FileCreator
def create(items)
raise NotImplementedError
end
end
contrato
class FileCreatorXML < FileCreator
def create(items)
XML.parse(items)
end
end
class FileCreatorCSV < FileCreator
def create(items)
FormatCSV.generate_file(items)
end
end
class FileCreatorPDF < FileCreator
def create(items)
PDFGenerator.generate(items)
end
end
adição
class FinancialReport
def generate(account, file_creator)
file = file_creator.create(account.transactions)
Mailer.send(account.email, file)
end
end
FinancialReport.new.generate(account, FileCreatorPDF.new)
Liskov Substitution Principle
Barbara Liskov
Institute Professor from MIT
The 2008 Turing Award winner
liskov at csail.mit.edu
Liskov Substitution Principle (1987)
Let φ(x) be a property provable about objects x
of type T. Then φ(y) should be true for objects y
of type S where S is a subtype of T.
Eita!
Design by contract
respeitar os contratos definidos pela classe base
Pré-condições: dados de entrada
classes derivadas só podem ser mais permissivas
Pós-condições: dados de saída
classes derivadas só podem ser mais restritivas
Não podemos criar comportamentos inesperados ou incorretos!
O comportamento da super classe precisa ser mantido
class CheckingAccount
# ...
def deposit(value)
raise InvalidValueError if value <= 0
self.balance = self.balance + value
end
def compute_bonus
self.balance = self.balance * 1.01
end
end
class PayrollAccount < CheckingAccount
class OperationNotAllowed < StandardError; end
# ...
def compute_bonus
raise OperationNotAllowed
end
end
CheckingAccount.all.each do |account|
account.compute_bonus
end
CheckingAccount.all.each do |account|
begin
account.compute_bonus
rescue PayrollAccount::OperationNotAllowed
false
end
end
CheckingAccount.all.each do |account|
begin
account.compute_bonus
rescue PayrollAccount::OperationNotAllowed
false
end
end contrato quebrado
class PayrollAccount < CheckingAccount
# ...
def deposit(value)
raise InvalidValueError if value <= 100
self.balance = self.balance + value
end
def compute_bonus
self.balance = self.balance * 1.01
end
end
class PayrollAccount < CheckingAccount
# ...
def deposit(value)
raise InvalidValueError if value <= 100
self.balance = self.balance + value
end
def compute_bonus
self.balance = self.balance * 1.01
end
end
contrato quebrado
Deveriam ser classes diferentes
Exemplo clássico:
Retângulo x Quadrado
class Rectangle
attr_reader :width, :height
def initialize(width, height)
@width = width
@height = height
end
def area
width * height
end
end
class Square < Rectangle
attr_reader :width, :height
def initialize(width)
@width = width
@height = width
end
end
contrato quebrado
Interface Segregation Principle
Uma classe derivada não deveria ser obrigada
a implementar métodos que ela não usa
class CoffeeMachine
def brew_coffee
# brew coffee logic
end
def fill_coffee_beans
# fill coffee beans
end
end
class Person
attr_reader :coffee_machine
def initialize
@coffee_machine = CoffeeMachine.new
End
def quero_cafe
coffee_machine.brew_coffee
end
end
class Staff
attr_reader :coffee_machine
def initialize
@coffee_machine = CoffeeMachine.new
end
def fill_coffee_beans
coffee_machine.fill_coffee_beans
end
end
Várias interfaces específicas é melhor do
que uma interface generalizada
class CoffeeMachineUserInterface
def brew_coffee
# brew coffee logic
end
end
class CoffeeMachineServiceInterface
def fill_coffee_beans
# fill coffee beans
end
end
class CoffeeMachineUserInterface
def brew_coffee
# brew coffee logic
end
end
class CoffeeMachineServiceInterface
def fill_coffee_beans
# fill coffee beans
end
end
class Person
attr_reader :coffee_machine
def initialize
@coffee_machine = CoffeeMachineUserInterface.new
end
def quero_cafe
coffee_machine.brew_coffee
end
end
`
class Person
attr_reader :coffee_machine
def initialize
@coffee_machine = CoffeeMachineUserInterface.new
end
def quero_cafe
coffee_machine.brew_coffee
end
end
`
`
class Staff
attr_reader :coffee_machine
def initialize
@coffee_machine = CoffeeMachineServiceInterface.new
end
def fill_coffee_beans
coffee_machine.fill_coffee_beans
end
end
class Staff
attr_reader :coffee_machine
def initialize
@coffee_machine = CoffeeMachineServiceInterface.new
end
def fill_coffee_beans
coffee_machine.fill_coffee_beans
end
end
Dependency Inversion Principle
Dependa de abstrações,
não de implementações
class FinancialReport
def generate(account, file_format)
case file_format
when :csv
file = FormatCSV.generate_file(account.transactions)
when :xml
file = XML.parse_list(account.transactions)
when :pdf
file = PDFGenerator.create(account.transactions)
end
Mailer.send(account.email, file)
end
end
class FinancialReport
def generate(account, file_creator)
file = file_creator.create(account.transactions)
Mailer.send(account.email, file)
end
end
class FileCreatorCSV < FileCreator
def create(items)
FormatCSV.generate_file(items)
end
End
FinancialReport.new.generate(account, FileCreatorCSV.new)
class FileCreatorCSV < FileCreator
def create(items)
FormatCSV.generate_file(items)
NewCSVGenerator.parse(items, header: false)
end
End
FinancialReport.new.generate(account, FileCreatorCSV.new)
TL;DR;
TL;DR:
Alta coesão
Baixo acoplamento
Encapsulamento
vamos refatorar tudo?
esses conceitos nos ajudam a criar
aplicações mais flexíveis
converse com seu time
analisem juntos os trade-offs
cuidado com big design up front
e não esqueçam:
codar é um processo de comunicação
Mais sobre design?
Padrões de projeto
TDD, DDD
minhas referências
Até a próxima!
obrigada
speakerdeck.com/elainenaomi

Mais conteúdo relacionado

Semelhante a Design orientado a objetos para aplicações Ruby

Relato Sobre a Migração de uma Aplicação Legada para Rails
Relato Sobre a Migração de uma Aplicação Legada para RailsRelato Sobre a Migração de uma Aplicação Legada para Rails
Relato Sobre a Migração de uma Aplicação Legada para RailsCássio Marques
 
JavaServer Faces Produtividade em Desenvolvimento
JavaServer Faces Produtividade em DesenvolvimentoJavaServer Faces Produtividade em Desenvolvimento
JavaServer Faces Produtividade em DesenvolvimentoEduardo Bregaida
 
Php women oficina iniciante de php
Php women   oficina iniciante de phpPhp women   oficina iniciante de php
Php women oficina iniciante de phpTais Reis
 
Produtividade com JavaServer Faces
Produtividade com JavaServer FacesProdutividade com JavaServer Faces
Produtividade com JavaServer FacesEduardo Bregaida
 
Hacking Evening - Liskov Substitution Principle
Hacking Evening - Liskov Substitution PrincipleHacking Evening - Liskov Substitution Principle
Hacking Evening - Liskov Substitution PrincipleElaine Naomi
 
Curso de Ruby on Rails - Aula 04
Curso de Ruby on Rails - Aula 04Curso de Ruby on Rails - Aula 04
Curso de Ruby on Rails - Aula 04Maurício Linhares
 
WEB 2 - Aula 01 - 02.08
WEB 2 - Aula 01 - 02.08WEB 2 - Aula 01 - 02.08
WEB 2 - Aula 01 - 02.08Gilson Silva
 
Interfaces ricas com Rails e React.JS @ Rubyconf 2015
Interfaces ricas com Rails e React.JS @ Rubyconf 2015Interfaces ricas com Rails e React.JS @ Rubyconf 2015
Interfaces ricas com Rails e React.JS @ Rubyconf 2015Rodrigo Urubatan
 
Ruby on Rails I - Modelos
Ruby on Rails I - ModelosRuby on Rails I - Modelos
Ruby on Rails I - ModelosTiago Lima
 

Semelhante a Design orientado a objetos para aplicações Ruby (20)

Working with legacy code 3
Working with legacy code 3Working with legacy code 3
Working with legacy code 3
 
Introdução a php
Introdução a phpIntrodução a php
Introdução a php
 
Mvc delphi
Mvc delphiMvc delphi
Mvc delphi
 
Relato Sobre a Migração de uma Aplicação Legada para Rails
Relato Sobre a Migração de uma Aplicação Legada para RailsRelato Sobre a Migração de uma Aplicação Legada para Rails
Relato Sobre a Migração de uma Aplicação Legada para Rails
 
JavaServer Faces Produtividade em Desenvolvimento
JavaServer Faces Produtividade em DesenvolvimentoJavaServer Faces Produtividade em Desenvolvimento
JavaServer Faces Produtividade em Desenvolvimento
 
Programando php com excelência
Programando php com excelênciaProgramando php com excelência
Programando php com excelência
 
Java - Primeiros passos
Java - Primeiros passosJava - Primeiros passos
Java - Primeiros passos
 
Php women oficina iniciante de php
Php women   oficina iniciante de phpPhp women   oficina iniciante de php
Php women oficina iniciante de php
 
Ruby & Rails
Ruby & RailsRuby & Rails
Ruby & Rails
 
Aula1
Aula1Aula1
Aula1
 
Produtividade com JavaServer Faces
Produtividade com JavaServer FacesProdutividade com JavaServer Faces
Produtividade com JavaServer Faces
 
Hacking Evening - Liskov Substitution Principle
Hacking Evening - Liskov Substitution PrincipleHacking Evening - Liskov Substitution Principle
Hacking Evening - Liskov Substitution Principle
 
Clean Code
Clean CodeClean Code
Clean Code
 
Aop Aspect J 1.5.4
Aop Aspect J 1.5.4Aop Aspect J 1.5.4
Aop Aspect J 1.5.4
 
Curso de Ruby on Rails - Aula 04
Curso de Ruby on Rails - Aula 04Curso de Ruby on Rails - Aula 04
Curso de Ruby on Rails - Aula 04
 
Aula 1 | Introdução a C++
Aula 1 | Introdução a C++Aula 1 | Introdução a C++
Aula 1 | Introdução a C++
 
WEB 2 - Aula 01 - 02.08
WEB 2 - Aula 01 - 02.08WEB 2 - Aula 01 - 02.08
WEB 2 - Aula 01 - 02.08
 
Interfaces ricas com Rails e React.JS @ Rubyconf 2015
Interfaces ricas com Rails e React.JS @ Rubyconf 2015Interfaces ricas com Rails e React.JS @ Rubyconf 2015
Interfaces ricas com Rails e React.JS @ Rubyconf 2015
 
Curso java script
Curso java scriptCurso java script
Curso java script
 
Ruby on Rails I - Modelos
Ruby on Rails I - ModelosRuby on Rails I - Modelos
Ruby on Rails I - Modelos
 

Mais de Elaine Naomi

Code Smells: o que eles dizem sobre seu código?
Code Smells: o que eles dizem sobre seu código?Code Smells: o que eles dizem sobre seu código?
Code Smells: o que eles dizem sobre seu código?Elaine Naomi
 
Guru SP: Decodificando o code review
Guru SP: Decodificando o code reviewGuru SP: Decodificando o code review
Guru SP: Decodificando o code reviewElaine Naomi
 
Bootcamp de Rails - CaquiCoders Meetup
Bootcamp de Rails - CaquiCoders MeetupBootcamp de Rails - CaquiCoders Meetup
Bootcamp de Rails - CaquiCoders MeetupElaine Naomi
 
TDC SP 2019 - Decodificando o code review
TDC SP 2019 - Decodificando o code reviewTDC SP 2019 - Decodificando o code review
TDC SP 2019 - Decodificando o code reviewElaine Naomi
 
Além da programação funcional com Elixir e Erlang
Além da programação funcional com Elixir e ErlangAlém da programação funcional com Elixir e Erlang
Além da programação funcional com Elixir e ErlangElaine Naomi
 
Code review: o que isso diz sobre a cultura dos times de desenvolvimento?
Code review: o que isso diz sobre a cultura dos times de desenvolvimento?Code review: o que isso diz sobre a cultura dos times de desenvolvimento?
Code review: o que isso diz sobre a cultura dos times de desenvolvimento?Elaine Naomi
 
Explorando o Paralelismo em Workflows Intensivos em Dados com o Uso de Anotaç...
Explorando o Paralelismo em Workflows Intensivos em Dados com o Uso de Anotaç...Explorando o Paralelismo em Workflows Intensivos em Dados com o Uso de Anotaç...
Explorando o Paralelismo em Workflows Intensivos em Dados com o Uso de Anotaç...Elaine Naomi
 
Uso de Anotações Semânticas para Exploração de Paralelismo em Workflows Inten...
Uso de Anotações Semânticas para Exploração de Paralelismo em Workflows Inten...Uso de Anotações Semânticas para Exploração de Paralelismo em Workflows Inten...
Uso de Anotações Semânticas para Exploração de Paralelismo em Workflows Inten...Elaine Naomi
 
Dealing with a search engine in your application - a Solr approach for beginners
Dealing with a search engine in your application - a Solr approach for beginnersDealing with a search engine in your application - a Solr approach for beginners
Dealing with a search engine in your application - a Solr approach for beginnersElaine Naomi
 
Um Método para Paralelização Automática de Workflows Intensivos em Dados
Um Método para Paralelização Automática de Workflows Intensivos em DadosUm Método para Paralelização Automática de Workflows Intensivos em Dados
Um Método para Paralelização Automática de Workflows Intensivos em DadosElaine Naomi
 
O que é BIG DATA e como pode influenciar nossas vidas
O que é BIG DATA e como pode influenciar nossas vidasO que é BIG DATA e como pode influenciar nossas vidas
O que é BIG DATA e como pode influenciar nossas vidasElaine Naomi
 
Introdução ao MongoDB
Introdução ao MongoDBIntrodução ao MongoDB
Introdução ao MongoDBElaine Naomi
 
Workflows científicos
Workflows científicosWorkflows científicos
Workflows científicosElaine Naomi
 
Algoritmos para economia de energia no escalonamento de workflows em nuvens c...
Algoritmos para economia de energia no escalonamento de workflows em nuvens c...Algoritmos para economia de energia no escalonamento de workflows em nuvens c...
Algoritmos para economia de energia no escalonamento de workflows em nuvens c...Elaine Naomi
 

Mais de Elaine Naomi (15)

Code Smells: o que eles dizem sobre seu código?
Code Smells: o que eles dizem sobre seu código?Code Smells: o que eles dizem sobre seu código?
Code Smells: o que eles dizem sobre seu código?
 
Guru SP: Decodificando o code review
Guru SP: Decodificando o code reviewGuru SP: Decodificando o code review
Guru SP: Decodificando o code review
 
Bootcamp de Rails - CaquiCoders Meetup
Bootcamp de Rails - CaquiCoders MeetupBootcamp de Rails - CaquiCoders Meetup
Bootcamp de Rails - CaquiCoders Meetup
 
TDC SP 2019 - Decodificando o code review
TDC SP 2019 - Decodificando o code reviewTDC SP 2019 - Decodificando o code review
TDC SP 2019 - Decodificando o code review
 
Além da programação funcional com Elixir e Erlang
Além da programação funcional com Elixir e ErlangAlém da programação funcional com Elixir e Erlang
Além da programação funcional com Elixir e Erlang
 
Code review: o que isso diz sobre a cultura dos times de desenvolvimento?
Code review: o que isso diz sobre a cultura dos times de desenvolvimento?Code review: o que isso diz sobre a cultura dos times de desenvolvimento?
Code review: o que isso diz sobre a cultura dos times de desenvolvimento?
 
Explorando o Paralelismo em Workflows Intensivos em Dados com o Uso de Anotaç...
Explorando o Paralelismo em Workflows Intensivos em Dados com o Uso de Anotaç...Explorando o Paralelismo em Workflows Intensivos em Dados com o Uso de Anotaç...
Explorando o Paralelismo em Workflows Intensivos em Dados com o Uso de Anotaç...
 
Uso de Anotações Semânticas para Exploração de Paralelismo em Workflows Inten...
Uso de Anotações Semânticas para Exploração de Paralelismo em Workflows Inten...Uso de Anotações Semânticas para Exploração de Paralelismo em Workflows Inten...
Uso de Anotações Semânticas para Exploração de Paralelismo em Workflows Inten...
 
Dealing with a search engine in your application - a Solr approach for beginners
Dealing with a search engine in your application - a Solr approach for beginnersDealing with a search engine in your application - a Solr approach for beginners
Dealing with a search engine in your application - a Solr approach for beginners
 
Um Método para Paralelização Automática de Workflows Intensivos em Dados
Um Método para Paralelização Automática de Workflows Intensivos em DadosUm Método para Paralelização Automática de Workflows Intensivos em Dados
Um Método para Paralelização Automática de Workflows Intensivos em Dados
 
O que é BIG DATA e como pode influenciar nossas vidas
O que é BIG DATA e como pode influenciar nossas vidasO que é BIG DATA e como pode influenciar nossas vidas
O que é BIG DATA e como pode influenciar nossas vidas
 
Introdução ao MongoDB
Introdução ao MongoDBIntrodução ao MongoDB
Introdução ao MongoDB
 
Workflows científicos
Workflows científicosWorkflows científicos
Workflows científicos
 
Algoritmos para economia de energia no escalonamento de workflows em nuvens c...
Algoritmos para economia de energia no escalonamento de workflows em nuvens c...Algoritmos para economia de energia no escalonamento de workflows em nuvens c...
Algoritmos para economia de energia no escalonamento de workflows em nuvens c...
 
Qt Apresentação
Qt ApresentaçãoQt Apresentação
Qt Apresentação
 

Design orientado a objetos para aplicações Ruby