Entrada, processamento e saída: o desenho de todo programa
O modelo entrada-processamento-saída aplicado a uma calculadora de troco: o que entra, o que o programa decide e o que sai, com execução no Node.
Entrada, processamento e saída são três papéis que todo programa desempenha: recebe dados, aplica uma regra e entrega um resultado observável. Separar esses papéis torna a mudança previsível e revela onde um erro começou.
O domínio desta lição é o caixa de uma livraria. O cliente entrega dinheiro, o sistema calcula a diferença e a tela informa o troco. Antes de pensar em sintaxe, escreva três caixas no papel: entra, transforma, sai. Esse mapa é um algoritmo em sua forma mais curta.
Todo programa é um funil: entra dado, sai resposta
Comece com números já disponíveis no programa. O exemplo mínimo deixa os três papéis visíveis:
const totalCompra = 37;
const valorRecebido = 50;
const troco = valorRecebido - totalCompra;
console.log(`Troco: R$ ${troco.toFixed(2)}`);As duas primeiras linhas são entrada; a subtração é processamento; o console.log é apresentação da saída. Pense num funil apenas como desenho do fluxo. O limite da analogia é que programas reais podem produzir várias saídas, guardar estado e voltar a pedir dados.
Entrada existe antes de virar variável
Um dado pode vir do teclado, de um formulário, de um sensor, de um arquivo ou de outra API. Ao entrar em JavaScript, texto continua sendo texto. Simule o que um campo de formulário entregaria:
const digitado = '50.00';
console.log(typeof digitado, digitado);
const recebido = Number(digitado);
console.log(typeof recebido, recebido);Converter não é detalhe do cálculo. É parte do contrato de entrada. Se a aplicação espera reais, precisa decidir se aceita vírgula, ponto, espaços, vazio e valor negativo antes de subtrair.
Processamento é a regra que ninguém vê
A regra pode ser uma conta, uma decisão ou uma sequência inteira. Coloque-a numa função que recebe valores e devolve valor, sem imprimir:
function calcularTroco(total, recebido) {
return recebido - total;
}
console.log(calcularTroco(37, 50));
console.log(calcularTroco(82.4, 100));O segundo resultado expõe ponto flutuante binário. O processamento matemático ocorreu, mas dinheiro pede uma representação mais segura. A decisão profissional é trabalhar em centavos inteiros e formatar apenas na saída.
Saída na tela não é o mesmo que devolver um valor
Uma função que só imprime não pode alimentar o próximo passo:
function mostrarTroco(total, recebido) {
console.log(recebido - total);
}
const resultado = mostrarTroco(37, 50);
console.log(`retorno: ${resultado}`);console.log conversa com quem observa o terminal. return conversa com o restante do programa. Quando você separa cálculo e apresentação, pode usar a mesma resposta numa tela, num recibo ou numa API.
A calculadora de troco nos três blocos
Agora normalize a entrada para centavos, processe com inteiros e apresente em reais:
function paraCentavos(valor) {
return Math.round(Number(valor.replace(',', '.')) * 100);
}
function calcularTroco(total, recebido) {
return recebido - total;
}
function formatar(centavos) {
return `R$ ${(centavos / 100).toFixed(2)}`;
}
const total = paraCentavos('37,40');
const recebido = paraCentavos('50,00');
console.log(formatar(calcularTroco(total, recebido)));Cada função tem uma responsabilidade observável. Aceitar centavos muda a conversão de entrada, não a subtração. Trocar o formato do recibo muda a saída, não o cálculo.
Trocando só a entrada sem tocar na regra
O mesmo processamento aceita dados de um pedido ou de uma promoção, desde que ambos entreguem centavos:
const calcularTroco = (total, recebido) => recebido - total;
const entradas = [
{ origem: 'caixa', total: 3740, recebido: 5000 },
{ origem: 'app', total: 8290, recebido: 10000 },
];
for (const entrada of entradas) {
console.log(entrada.origem, calcularTroco(entrada.total, entrada.recebido));
}O processamento não pergunta de onde o dado veio. Ele confia no contrato: inteiros em centavos. Essa fronteira reduz o número de linhas que mudam quando surge outra origem.
Quando a entrada não é o que o algoritmo esperava
Number('cinquenta') produz NaN sem lançar exceção. Se você não validar, o defeito atravessa o processamento e só aparece na saída:
function lerDinheiro(texto) {
const valor = Number(texto.replace(',', '.'));
if (!Number.isFinite(valor) || valor < 0) {
throw new TypeError(`Valor inválido: ${texto}`);
}
return Math.round(valor * 100);
}
try {
console.log(lerDinheiro('cinquenta'));
} catch (erro) {
console.log(`${erro.name}: ${erro.message}`);
}Leia a mensagem como diagnóstico: o processamento nem deveria começar. Corrija na fronteira e mantenha a regra central trabalhando com dados que cumprem o contrato.
Tudo grudado contra os três blocos separados
Uma alteração de formato mostra a diferença de manutenção. Na versão separada, o cálculo não muda:
const processar = ({ total, recebido }) => recebido - total;
const exibirReais = (centavos) => `R$ ${(centavos / 100).toFixed(2)}`;
const exibirCentavos = (centavos) => `${centavos} centavos`;
const saida = processar({ total: 3740, recebido: 5000 });
console.log(exibirReais(saida));
console.log(exibirCentavos(saida));Nos dois casos a regra é a mesma. Só a apresentação troca. Essa separação também melhora testes: você verifica 1260 sem depender de pontuação ou símbolo de moeda.
Missão: mapear um aplicativo que você usa
Escolha uma ação, como pedir transporte. Liste entradas (origem, destino, horário), processamento (rota, disponibilidade, preço) e saídas (estimativa, mapa, confirmação). Depois identifique uma entrada inválida e diga em qual fronteira ela deve parar.
Use este mapa como critério de revisão:
const mapa = {
entradas: ['origem', 'destino'],
processamento: ['calcular rota', 'estimar preço'],
saidas: ['tempo', 'valor'],
};
console.log(Object.entries(mapa).map(([etapa, itens]) => `${etapa}:${itens.length}`).join(' | '));Revise também a direção das dependências. A apresentação pode depender do resultado do cálculo, mas o cálculo não deveria depender de como a tela escreve reais. A validação conhece o formato recebido, enquanto a regra central conhece valores normalizados. Essa direção permite substituir terminal por formulário sem reescrever a subtração.
Em programas maiores, as três caixas aparecem em camadas: uma rota recebe a requisição, um serviço aplica a regra e uma resposta serializa o resultado. O desenho continua útil, desde que você não trate separação como obrigação de criar um arquivo por linha. Agrupe responsabilidades que mudam pelos mesmos motivos e teste os contratos entre elas.
Para conferir seu mapa, simule duas entradas que chegam por canais diferentes e exigem o mesmo processamento. Depois produza duas apresentações para o mesmo resultado. Se você consegue fazer cada troca sem alterar a regra central, as fronteiras estão claras. Se uma mudança de moeda obriga mexer na subtração, descubra onde unidade e formato foram misturados.
Quando as três caixas estiverem claras, avance para variável e tipo de dado, onde o contrato da entrada ganha nomes e tipos. O teste de mesa ajuda a seguir essas mudanças no papel, e o guia de lógica mostra a ordem completa.
Perguntas frequentes
Console.log é sempre a saída de um programa?
Validação faz parte da entrada ou do processamento?
Dúvidas e comentários
Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.
Entrar para perguntarÉ o mesmo login gratuito dos cursos.
Nenhuma dúvida por aqui ainda — a primeira pode ser a sua.
Todo o código deste artigo foi executado em Node v26.3.0, e as saídas exibidas são as reais — como produzimos este conteúdo.
Fontes consultadas
- Node.js — Process input and output — nodejs.org
- ECMAScript — Numeric Types — tc39.es


