Não foi possível carregar o Diqus. Se você é o moderador, por favor veja o nosso guia de problemas.

Nando Sousa • 10 anos atrás

Show de bola. sei que não está dentro do conteúdo do post, mas que ferramenta vc usa para fazer mockups? igual a esse do checkout.

Nando Vieira • 10 anos atrás
dcrec1 • 10 anos atrás

Eu gosto de utilizar a gem inherited resources. No caso do checkout, não acho que a action create deveria chamar Checkout.process e sim algo similar a Checkout.create, que acho que é o esperado. Como a action faria o esperado, as linhas poderiam ser apagadas e o a lógica delegada para o inherited resources.

Eu entendo que o método process faz mais coisas que somente criar algum recurso, mas eu teria estruturado esse código diferente. Me parece que com umas quantas poucas linhas a mais na classe Order todas aquelas linhas da classe Checkout poderiam ser apagadas. Eu lembro que voce mencionou que os modelos começam a ficar gordos, mas eu acho estranho ter um mailer chamado checkout que recebe um pedido e uma mensagem flash de checkout que fala também sobre o pedido, para mim claramente o que está sendo manipulado é um pedido e não um checkout.

Achei bem legal esse post para fazer refletir as pessoas, controllers complexos é o problema que mais acostumo ver em projetos.

Nando Vieira • 10 anos atrás

Eu não gosto de coisas mágicas como inherited resources. Já trabalhei em um projeto que usava e era o caos instaurado. Desde então, evito qualquer coisa do tipo.

O ponto do artigo é exatamente mostrar que você não precisa colocar no modelo, como você sugere. Neste exemplo, não estou lidando com um recurso, mas com um processo/workflow. É um pattern chamado Interactor.

Novamente, não vejo problemas em utilizar o nome "checkout" como base para todo esse fluxo, já que é exatamente isso o que está acontecendo. Meu problema com controllers complexos é justamente esse; pensar que tudo pode ser um resource, quando na verdade não é. Não estamos criando um pedido, mas fazendo um processo de checkout, que envolve muito mais que apenas o registro na tabela orders.

Quanto ao nome do email, sim, poderia ter sido usado um nome melhor como order_confirmation, tanto que vou fazer essa alteração no artigo. :)

James Pinto • 10 anos atrás

Ô Nando,
Posso sugerir uma gem pra se usar ao inves do inherited_resources?
https://github.com/before-a...
Por favor, da uma olhada e diz se voce acha se ajuda na reducao de complexidade

Gabriel Mazetto • 10 anos atrás

E quanto a organização dos arquivos? Quando o projeto cresce utilizar alguns namespaces se torna indispensável

Nando Vieira • 10 anos atrás

Sim, concordo. Normalmente coloco isso em um namespace 'mediators' ou 'interactors'.

andersondanilo2 • 10 anos atrás

Olá Nando, eu utilizo classes de serviços, como por exemplo CustomerService, tipo uma caixa de método relacionados, porém esta classe fica gigante.

Thiago Ramos • 10 anos atrás

Também faço isso andresondanilo2, mas as minhas classes de serviço não ficam grandes pois sigo a linha do Nando. A classe checkout no meu caso seria Um CheckoutService ou CheckoutProccess e quanto maior for o fluxo mais classes eu teria e o CheckoutProccess trataria de fazer as chamadas. A vantagem é deixar o controller fazendo só o que deve fazer que é passar atributos da view para baixo.

Leandro Nunes • 10 anos atrás

Nando, bacana! também não vejo resources nesse processo. Para extrair a complexidade dos controllers, venho usando o conceito de Form Models e Service Object, pescando as dicas do livro “Growing Rails Applications in Practice” by Henning Koch and Thomas Eisenbarth.

Thiago A. • 10 anos atrás

Nando, só por curiosidade, como você testaria, no contexto do happy path, se o pedido foi salvo com os dados corretos? Entendo que a criação de um "order" é um detalhe de implementação, mas um efeito importante a se testar... uma maneira que estou vendo de fazer isso usando o código do exemplo (que não me parece tão correta), seria obtendo o Order do banco de dados (usando o order_id) e verificando se foi salvo com os dados corretos... ou modificando o código com um callback do tipo "on_success", onde privadamente se passaria o objeto "order" recém-criado para consultar se foi salvo com os dados corretos? Ou usando mocks?

Nando Vieira • 10 anos atrás

Testaria após chamar Checkout.process à partir do Checkout#order_id. Como você disse, é um detalhe de implementação, mas um muito importante para não se testar.

Alternativamente você poderia criar uma classe responsável por fazer isso (e.g. OrderCreator.create(attrs)), e só verificar se a mensagem foi passada com um stub.

hlmerscher • 10 anos atrás

Muito bom Nando, ótima dica!

Tem um post antigo no blog da codeclimate também, com várias dicas de refactoring. Para quem quiser ler, segue o link:
http://blog.codeclimate.com...

Santiago • 10 anos atrás

Boas dicas!
Eu divido entre concern e service class (depois de muito tempo usando grails, é difícil acostumar quando outro framework não tem).
Não conhecia essa gem responders, parece ser bem útil, vou dar uma conferida depois.

Felipe Fontoura • 10 anos atrás

Excelente artigo!

Só uma dúvida, e o Sandi Matz Rules (https://robots.thoughtbot.c...

Neste artigo comenta o uso de Facades para extrair também a lógica do controller. Neste artigo eu entendi que está aplicando um "service".

Abs!

Nando Vieira • 10 anos atrás

Quero aplicar os conceitos da Sandi em um projeto, para ver como isso anda. Ao contrário do post da Thoughtbot, as regras são:

1. Classes de até 100 linhas
2. Métodos de até 5 linhas
3. Métodos com até 4 parâmetros
4. Actions do Rails podem ter 1 objeto de negócios e 1 de apresentação

Ela fez as correções em uma palestra (disponível no http://confreaks.tv). Esse último ponto é extremamente importante, pois facilita usar a abordagem que mostrei no artigo, com a possibilidade de se criar um objeto que será usado na apresentação (não que seja necessário neste caso em particular).

Felipe Fontoura • 10 anos atrás

Perfeito Nando, essa palestra não tinha assistido ainda!

Estamos seguindo a regra a risca e confesso que achei bem "estranho" essa etapa do Facade, mais estou analisando e comparando se vale a pena de verdade deixar apenas 1 objeto de negócio/apresentação. Me parece muito mais adequado seguir o passo 4 atualizado (um de negócio - service, e outro de apresentação).

Novamente obrigado pelo excelente artigo!

Luiz Felipe • 10 anos atrás

Nando, antes de mais nada: parabéns pelo post, muito bom.
Usando essa definição de model com o include ActiveModel::Model como ficaria o resto da implementação da persistencia? Digo, você usa o ActiveRecord como repository? Como fica essa implementação?

Romulo Martins Da Silva • 8 anos atrás

boa =)