Simula um caixa eletrônico, efetuando a entrega de notas para o cliente, sendo as condições de aceite:
- Entregar o menor número de notas;
- É possível sacar o valor solicitado com as notas disponíveis;
- Saldo do cliente infinito;
- Quantidade de notas finita;
- Notas disponíveis de
R$ 100,00
;R$ 50,00
;R$ 20,00
eR$ 10,00
Exemplos:
- Valor do Saque:
R$ 30,00
– Resultado Esperado: Entregar 1 nota deR$20,00
e 1 nota deR$ 10,00
. - Valor do Saque:
R$ 80,00
– Resultado Esperado: Entregar 1 nota deR$50,00
1 nota deR$ 20,00
e 1 nota de R$10,00
.
Faça clone do repositório:
git clone https://github.com/luizhsou1/cash-machine.git
Entre na pasta cash-machine
:
cd cash-machine
Crie o arquivo de variáveis de ambiente:
cp .env.sample .env
Instale a versão do projeto (Recomendado):
nvm install
nvm use
Faça a instalação das dependências do projeto:
npm install
Construa o projeto:
npm run build
Rode o projeto:
npm start
Obs: A variável de ambiente
EXECUTION_MODE
determina o modo de execução que a aplicação deve usar, sendo eles:
answer
: Deixa a cargo do usuário definir em qual modo deseja executar (console ou web).console
: Executa a aplicação direto no modo console.web
: Executa a aplicação direto no modo web.
src
│ ├── domain => Camada de domínio da aplicação
│ │ ├── errors => Diretório contendo arquivos com classes que estendem a classe Error
│ │ │ ├── persistence-error.ts => Classe que representa erros ocorridos ao persistir dados
│ │ │ └── validation-error.ts => Classe que representa erros de validação
│ │ ├── interfaces => Diretório contendo as abstrações que a camada de domínio precisa conhecer
│ │ │ └── imoney-repository.ts => Interface com funções para manipular um repositório de dados de notas
│ │ ├── cash-machine.ts => Classe que representa o caixa eletrônico no sistema
│ │ └── money.ts => Classe que representa as cédulas de dinheiro no sistema
│ ├── infra => Camada d infraestrutura da aplicação
│ │ └── repositories => Diretório contendo arquivos com implementações de repositórios de dados
│ │ └── memory-money-repository.ts => Implementação do ImoneyRepository em memória
│ ├── shared => Diretório contendo arquivos/funções que podem ser compartilhado entre as camadas
│ │ ├── constants.ts => Arquivo com constantes da aplicação
│ │ └── validations-util.ts => Arquivo com funções úteis de validação
│ └── ui => Camada que interage com usuário
│ ├── console => Diretório contendo arquivos para interação via console
│ │ ├── answer.ts => Fluxo de interação via console, perguntando sobre qual modo de execução usuário deseja usar
│ │ ├── console.ts => Fluxo de interação via cosole, executando efetivamente o sistema
│ │ └── console-util.ts => Arquivo com funções úteis para interação via console
│ └── web => Diretório contendo arquivos para interação via web
│ ├── app.ts => Arquivo contendo configurações e função para executar a aplicação web
│ ├── error-handling.ts => Arquivo contendo middleware de tratativa de erros da aplicação web
│ ├── routes.ts => Arquivo contendo configurações de rota do sistema, com seus respectivos middlewares
│ └── swagger.ts => Arquivo de configuração do swagger da aplicação web
test
│ ├── integrations => Diretório contendo arquivos de testes de integração
│ └── units => Diretório contendo arquivos de testes unitários
Explicação macro do algoritmo de retirada de notas, contido no arquivo src/domain/cash-machine
, na função withdraw
:
- Valida entrada;
- Busca notas disponíveis no repositório em ordem decrescente;
- Executa uma função recursiva que retorna uma lista contendo objetos da classe Money, com o máximo de notas que conseguiu tentando satisfazer o pedido, com a devida ordem de prioridade, tentando sempre retornar a menor quantidade de notas possível;
- Soma a (quantidade * valor) de cada nota obtida na etapa anterior;
- Se soma for diferente do valor requirido, lança execeção, se for igual, segue o fluxo;
- Percorre a lista de objetos da classe Money, para pegar o índice correspondente na lista de notas disponíveis, obtendo esse índice chama a função remove do objeto, passando a quantidade a ser removida;
- Atualiza a lista de notas disponíveis, depois de ter removido a quantidade devida;
- Retorna o resultado obtido.
Explicação macro do algoritmo de retirada de notas recursivo, contido no arquivo src/domain/cash-machine
, na função recursiveWithdraw
, basicamente em cada interação da recursão:
- Verifica a condição de parada, sendo ela, se não tem mais valor a ser retirado ou se não tem mais notas disponíveis para retirar;
- Calcula a quantidade ideal de notas daquele tipo que está sendo iterado no momento;
- Pega o menor valor entre a quantidade ideal e quantidade disponível do que está sendo iterado no momento;
3.1 Exemplo 1: se a quantidade ideal é 10, e a quantidade disponível é 5, obtenho 5 daquela nota;
3.2 Exemplo 2: se a quantidade ideal é 5, e a quantidade disponível é 10, obtenho 5 também daquela nota; - Calcula o valor efetivo que aquela interação pode contribuir;
- Se aquela iteração contribuir com alguma quantidade, retorna uma lista contendo um objeto Money e o resultado da chamada das proximas iterações recursivas. Se não contribuir, apenas chama a função recursiva novamente. Onde para cada chamada recursiva passo no primeiro argumento o (valor daquela interação - o valor efetivo que a iteração contribuiu) e no segundo argumento o restante da lista de notas disponíveis.
build
: Gera os arquivos javascript da aplicação e coloca na pastadist
.start
: Executar a aplicação obtida do build.dev
: Executa a aplicação em modo de desenvolvimento, monitorando mudanças no código.lint
: Valida estilo do código.lint:fix
: Valida e corrige estilo do código.test
: Executa testes unitários.test:integration
: Executa testes de integração.test:watch
: Executa testes unitários e monitora mudanças no código.test:coverage
: Executa testes unitários e apresenta um relatório de cobertura na saída do terminal e arquivocoverage/lcov-report/index.html
.
A corbertura de código foi configurada para monitorar apenas a camada de domínio, que é onde efetivamente escrevi os testes unitários.