Caixa eletrônico em Ruby
Criado por Joshua Paling, @joshuapaling
Traduzido por Ricardo Yasuda, @shadowmaru
Neste exercício você vai escrever uma função para lidar com saques em um caixa eletrônico. A intenção é desafiar você! Prepare-se para fazer muitas perguntas, pesquisar, e sair um pouco do computador. Mas você aprenderá bastante!
Você deverá usar programação em par, grupo ou remota, para ter outras pessoas para discutir ideias. Você vai usar Test Driven Development. No entanto, todos os testes já foram pré-escritos para você, para que você possa focar no código em si.
Começaremos com algo simples, mas vamos aumentar muito a dificuldade perto do final!
Fluxo
Para cada passo, você vai precisar executar as ações a seguir:
1. Rodar os novos testes: Apague os testes do passo anterior, e cole os testes pré-escritos para o passo atual. (Testes para cada passo são exibidos no fim do mesmo.) Rode os testes para ver quais deles falham. No Sublime Text, você pode usar Ctrl+B para rodar os testes. Ou, você pode abrir um terminal, cd
para o seu diretório de trabalho, e executar ruby caixa_eletronico.rb
.
2. Faça os testes passarem: Edite seu código para satisfazer os requisitos funcionais do passo atual. Você saberá que conseguiu quando todos os testes ficarem verdes.
3. Refatore: Veja se você pode reescrever algo para fazer o código ficar o mais limpo e fácil de entender possível. Alguns passos têm pontos de discussão. Discuta-os com seus pares - eles vão ajudar a seguir em frente.
Você deve ter reconhecido estes passos como o fluxo red, green, refactor do TDD.
1. Notas de R$5
Imagine um caixa eletrônico que possui apenas notas de R$5. Escreva uma função que retorne true
se um valor pode ser sacado, senão retorne false
.
Exemplos:
withdraw(15)
deve retornartrue
withdraw(18)
deve retornarfalse
, porque R$18 não pode ser composto por notas de R$5
Dicas para fazer os testes ficarem verdes:
A operação módulo, %
obtém o resto de uma divisão. Por exemplo, 9 % 4
resulta em 1
(nove dividido por quatro tem resto 1).
Código inicial:
Crie um arquivo chamado caixa_eletronico.rb
. Cole o seguinte código nele. Ele contém a casca da sua função withdraw()
, com os testes.
Testes para o passo 1:
2. Quantas notas?
Agora, modifique sua função para que caso o valor possa ser sacado, retorne o número apropriado de notas, em vez de simplesmente true
Exemplos:
withdraw(15)
deve retornar3
, já que 3 notas de R$5 totalizam R$15withdraw(20)
deve retornar4
, já que 4 notas de R$5 totalizam R$20withdraw(11)
deve retornarfalse
, porque R$11 não pode ser composto por notas de R$5
Dicas para fazer os testes ficarem verdes:
O operador /
faz uma divisão. Por exemplo, se você quer saber a metade da sua idade, e guardar em uma variável, faça isso:
Em Ruby, quando você faz uma divisão com dois números inteiros (integers), o resultado é arredondado para baixo para o número inteiro mais próximo.
Testes para o passo 2:
3. Array de notas
Em programação, um array
é basicamente uma coleção de coisas. É como se fosse uma lista.
Ao invés de retornar o número de notas, modifique o código para ele retornar um array de notas (neste caso, todas de R$5).
Exemplos
withdraw(15)
deve retornar um array,[5, 5, 5]
. (É basicamente uma coleção de 3 notas de R$5)withdraw(11)
deve retornarfalse
, porque R$11 não pode ser composto por notas de R$5
Dicas para fazer os testes ficarem verdes:
[]
define um array vazio. [1, 2]
define um array com dois elementos (1 e 2).
O operador <<
adiciona um elemento a um array. Por exemplo, [10, 20] << 30
vai adicionar 30 ao array, resultando em [10, 20, 30]
.
O método times
executa um bloco de código várias vezes - por exemplo, 5.times { puts 'hello' }
vai imprimir ‘hello’ 5 vezes.
Juntando tudo:
Testes para o passo 3:
4. Notas de R$10
Agora imagine que o caixa retorne apenas notas de R$10. Modifique sua função para refletir isso.
Exemplos
withdraw(20)
deve retornar um array,[10, 10]
withdraw(15)
deve retornarfalse
, porque R$15 não pode ser composto por notas de R$10
Testes para o passo 4:
Refatore
Uma vez que seus testes passarem, é hora de refatorar.
Em programação, ‘Números Mágicos’ são algo ruim (não se deixe enganar pelo nome!). Eles se referem a um valor fixo que meio que aparece do nada, sem nenhuma explicação do que aquele número específico representa.
Considere o quão fácil/difícil é entender os seguintes pedaços de código:
Números mágicos são particularmente problemáticos quando os mesmos valores fixos aparecem em vários lugares.
Você usou números mágicos? Você pode refatorar seu código para eliminá-los?
5. Notas de R$5 e R$10
Imagine que seu caixa agora tem notas de R$5 e de R$10. As pessoas vão querer o menor número de notas possível.
Exemplos
withdraw(25)
deve retornar[10, 10, 5]
withdraw(11)
deve retornarfalse
, porque R$11 não pode ser composto por notas de R$5 e de R$10
Testes para o passo 5:
6. Notas de R$5, R$10 e R$20
Seu caixa agora tem notas de R$5, R$10 e R$20. Modifique seu código para refletir isso.
Nota: a esta altura, cada valor maior pode ser dividido por cada valor menor - por exemplo, R$20 / R$10 = 2. As coisas ficam mais difíceis quando não é o caso (por exemplo, notas de R$50 e de R$20). Para este passo, intencionalmente não lidaremos com este caso para deixar mais fácil.
Exemplos
withdraw(15)
deve retornar[10, 5]
withdraw(25)
deve retornar[20, 5]
withdraw(35)
deve retornar[20, 10, 5]
withdraw(11)
deve retornarfalse
, porque R$11 não pode ser composto por notas de R$5 e de R$10
Dicas para fazer os testes ficarem verdes:
Para saber se um array está vazio: my_array.empty?
Para saber se um array não está vazio: !my_array.empty?
ou my_array.any?
Para remover o primeiro elemento de um array: my_array.shift
. Por exemplo, [1, 2, 3].shift
resulta em [2, 3]
Testes para o passo 6:
Refatore
- Quantas linhas você teve que mudar, do passo 5 para o passo 6?
- E se disponibilizássemos notas de R$100? Você poderia fazer em uma única linha?
- Refatore seu código para que você possa mudar para notas de R$100, R$20 e R$10, mudando apenas uma linha.
- Qual é a solução mais à prova de futuro?
7. Discussões Finais
- Dado que uma solução particular funcione, o que faz dela um código ‘bom’ ou ‘ruim’?
- Você pode pensar em alguns princípios ou melhores práticas para guardar? Estrutura de código é importante? Por quê?
- Você teve algum momento ‘Aha!’? Quais foram eles?
- Digamos que você começou uma microempresa de caixas eletrônicos, que rapidamente expandiu para se tornar um sucesso global. O quão adequado é o seu código para lidar com todas as formas de moeda, em todos os países do mundo? Ele ficou mais adequado com cada passo?
Desafio! Notas de R$50 e de R$20
Até agora, nós evitamos intencionalmente o caso onde uma nota menor não encaixava em uma nota maior. Por exemplo, nós evitamos o caso de ter apenas notas de R$50 e R$20 (onde 20 não ‘cabe’ exatamente em 50). Você consege ver o porquê deste caso ser mais difícil? Se o seu código atual fosse incluir apenas notas de R$50 e R$20, o que aconteceria quando você tentasse sacar R$60, ou R$110? Na sua cabeça, ou no papel, você pode pensar qual lógica seria necesária para lidar com esses casos corretamente? Se estiver a fim de um desafio, tente lidar com este caso no seu código! (Você precisará escrever seus próprios testes para este passo).
Outros Guias
- Handy cheatsheet for Ruby, Rails, console etc.
- Guia 1: Tutorial de Instalação para Rails Girls
- Guia 2: Tutorial para criação da app Rails Girls
- Guia 3: Como enviar para o GitHub
- Guia 4: Colocando seu app online em…
- Guia 5: Funcionalidades de uma área de comentários para a app Rails Girls
- Guia 6: Adicione design à sua aplicação com HTML e CSS
- Guia 7: Thumbnails em listas de ideas
- Guia 8: Autenticação (para usuários) com Devise
- Guia 9: Adicionando Gravatar para a aplicação
- Guia 10: Melhorando seu design da sua aplicação com HTML e CSS
- Guia 11: Continuous Deployment
- Guia 12: Construindo um aplicativo de votação em Sinatra
- Guia 13: Construa um diário em Ruby on Rails
- Guia 14: Adicione back-end ao seu aplicativo (páginas de administração)
- Guia 15: Acesse explicações adicionais do app Rails Girls