Dia 16 — Fechamento do trimestre: app completo

Informatica · Conteudo · publicado em 05/10/2026
Dia 16 de 16

Fechamento do trimestre: app completo

Aula 1

Estruturar o projeto e revisar a base

Estruturar o projeto e revisar a base

Estrutura é a decisão de onde cada arquivo mora, e ela vale mais quando é

simples de lembrar: um lugar para tela, um lugar para componente reaproveitado,

um lugar para o que fala com o servidor, e um lugar para o estilo.

src/
  telas/         uma tela por arquivo, com o nome da tela
  componentes/   o que e usado por mais de uma tela
  servicos/      o que fala com o servidor
  estilos/       cores, espacamento e o StyleSheet compartilhado
  dados/         constantes, tipos e o que nao tem estado

O exemplo desta página imprime a estrutura com a responsabilidade de cada

pasta ao lado do nome, e é a segunda coluna que importa: src/telas é uma tela

por arquivo, src/servicos é o que fala com o servidor, e src/dados é o que

não tem estado. Cinco pastas, cinco responsabilidades, e nenhuma sobreposição.

A regra que separa telas de componentes é o número de usos: o que uma

tela usa só ela, fica na tela; o que a segunda tela também usa, vira componente.

Componente em pasta de tela não é erro grave, mas componente que ninguém

consegue achar é — e o sintoma é o mesmo arquivo copiado em três pastas.

O exemplo aplica a regra em três casos e o resultado é o critério inteiro:

ListaPedidos usada por 2 telas vira componente, CartaoPedido usada por 3

também, e TelaConfig usada por 1 só fica na tela. O console traduz a

regra em uma frase — um item em duas telas vira componente, em uma só fica na

tela.

servicos é a camada que fala com o servidor, e ela é o que permite trocar de

fonte de dado sem tocar em tela. A tela chama listarPedidos() e recebe o

resultado; onde o dado veio — requisição, cache, dado de exemplo — é problema do

serviço. Sem essa separação, a tela gruda a fetch no componente e a troca de

fonte passa a ser reescrita de tela.

O exemplo troca a fonte do serviço e a tela não muda: com "servidor" ela

mostra "2 pedidos", e com "cache" o serviço devolve `{ origem: 'cache', itens:

[...] }` sem que nada na tela tenha sido tocado. É a linha final do parágrafo

medida: a tela não sabe de onde o dado veio, e por isso trocar a fonte é uma

linha no serviço.

revisar a base antes de fechar

Revisar o trimestre é olhar o que foi escrito com o critério de quem vai ler

depois, e há quatro perguntas que resolvem a maior parte:

  1. Há nome repetido de constante? Duas telas com #1f6feb escrito à mão é uma

cor que vai divergir.

  1. Há console.log que sobrou? Ele não quebra o aplicativo, e é o que impede o

teste de passar em silêncio.

  1. Há componente com nome de uma linha só? Nome de componente é uma frase sobre

o que ele faz: CartaoPedido, ListaPedidos, CampoTexto.

  1. Há função que faz duas coisas? Separar é o que permite testá-la.

O exemplo escreve os quatro critérios como pares de achado e correção, e cada

linha é uma regra aplicável: console.log no componente sai antes de fechar,

nome de uma palavra só vira frase, função que faz duas coisas é separada para

poder ser testada, e cor escrita à mão vai para o arquivo de estilos. A cor de

#1f6feb nomeada uma vez só resolve o primeiro critério, e é o que o exemplo

mostra no objeto de cores.

Refatorar com esses quatro critérios é diferente de reescrever. Reescrever

apaga o que funcionava; revisar com lista mantém o comportamento e tira o que

está atrapalhando.

Os nomes do exemplo fecham o critério 3 com os quatro nomes bons:

CartaoPedido, ListaPedidos, CampoTexto e CabecalhoTela. Cada nome diz o

que o componente é, e é o que permite a busca achar pelo nome — a mesma razão

que faz o eixo de termos do curso existir.

Exemplo

// Estrutura do projeto: cada pasta tem uma responsabilidade, e o
// exemplo monta a arvore de arquivos e a regra que separa componente de
// tela. Tambem mostra os quatro criterios da revisao.
const { View, Text, StyleSheet } = require('react-native');

// (1) a estrutura, com a responsabilidade de cada pasta.
const estrutura = {
  src: {
    telas: 'uma tela por arquivo, com o nome da tela',
    componentes: 'o que e usado por mais de uma tela',
    servicos: 'o que fala com o servidor',
    estilos: 'cores, espacamento e o StyleSheet compartilhado',
    dados: 'constantes, tipos e o que nao tem estado',
  },
};
console.log('estrutura do projeto:');
for (const pasta of Object.keys(estrutura.src)) {
  console.log('  src/' + pasta.padEnd(13) + estrutura.src[pasta]);
}

// (2) a regra que decide tela x componente: quantas telas usam.
const usosPorArquivo = {
  'ListaPedidos': ['Pedidos', 'DetalhePedido'],
  'CartaoPedido': ['Pedidos', 'DetalhePedido', 'Painel'],
  'TelaConfig': ['Config'],
};
console.log('\nquem usa cada arquivo:');
for (const arquivo of Object.keys(usosPorArquivo)) {
  const usos = usosPorArquivo[arquivo];
  console.log('  ' + arquivo.padEnd(15), usos.length + ' tela(s)', usos.length > 1 ? '-> componente' : '-> fica na tela');
}
console.log('um item em duas telas vira componente; em uma so, fica na tela');

// (3) a camada de servico: a tela pede dado e nao sabe de onde veio.
function servicoListarPedidos(fonte) {
  return { origem: fonte, itens: [{ id: 'p41' }, { id: 'p42' }] };
}
function telaDePedidos() {
  // a tela chama o servico e nao conhece a fonte
  const resultado = servicoListarPedidos('servidor');
  return <Text>{resultado.itens.length + ' pedidos'}</Text>;
}
const arvore = telaDePedidos();
console.log('\na tela:', arvore.type, '|', arvore.props.children);
console.log('trocar a fonte e uma linha no servico:');
console.log('  ', JSON.stringify(servicoListarPedidos('cache')));
console.log('a tela nao muda, porque ela nao sabe de onde o dado veio');

// (4) revisao: cor repetida com o nome certo uma vez so.
const cores = { primaria: '#1f6feb', texto: '#101418' };
const estilos = StyleSheet.create({ botao: { backgroundColor: cores.primaria } });
console.log('\ncor nomeada:', JSON.stringify(StyleSheet.flatten(estilos.botao)));
console.log('duas telas com a cor escrita a mao e uma cor que vai divergir');

// (5) revisao: `console.log` que sobrou.
const revisao = [
  { achado: 'console.log no componente', correcao: 'remover antes de fechar' },
  { achado: 'nome de componente com uma palavra so', correcao: 'nomear com a frase do que ele faz' },
  { achado: 'funcao que faz duas coisas', correcao: 'separar para poder testar' },
  { achado: 'cor escrita a mao em duas telas', correcao: 'nomear no arquivo de estilos' },
];
console.log('\nos quatro criterios da revisao:');
for (const item of revisao) console.log('  ' + item.achado + ' -> ' + item.correcao);

// (6) o exemplo: nome de componente e uma frase sobre o que ele faz.
const nomeados = ['CartaoPedido', 'ListaPedidos', 'CampoTexto', 'CabecalhoTela'];
console.log('\nnomes de componente:', nomeados);
console.log('cada nome diz o que o componente e, e a busca acha pelo nome');

Saída real

estrutura do projeto:
  src/telas        uma tela por arquivo, com o nome da tela
  src/componentes  o que e usado por mais de uma tela
  src/servicos     o que fala com o servidor
  src/estilos      cores, espacamento e o StyleSheet compartilhado
  src/dados        constantes, tipos e o que nao tem estado

quem usa cada arquivo:
  ListaPedidos    2 tela(s) -> componente
  CartaoPedido    3 tela(s) -> componente
  TelaConfig      1 tela(s) -> fica na tela
um item em duas telas vira componente; em uma so, fica na tela

a tela: Text | 2 pedidos
trocar a fonte e uma linha no servico:
   {"origem":"cache","itens":[{"id":"p41"},{"id":"p42"}]}
a tela nao muda, porque ela nao sabe de onde o dado veio

cor nomeada: {"backgroundColor":"#1f6feb"}
duas telas com a cor escrita a mao e uma cor que vai divergir

os quatro criterios da revisao:
  console.log no componente -> remover antes de fechar
  nome de componente com uma palavra so -> nomear com a frase do que ele faz
  funcao que faz duas coisas -> separar para poder testar
  cor escrita a mao em duas telas -> nomear no arquivo de estilos

nomes de componente: [ 'CartaoPedido', 'ListaPedidos', 'CampoTexto', 'CabecalhoTela' ]
cada nome diz o que o componente e, e a busca acha pelo nome
Aula 2

Publicar o app e fechar o trimestre

Publicar o app e fechar o trimestre

Build de produção é outro pacote do que a versão de desenvolvimento. O

desenvolvimento entrega um servidor de código quase legível, para o

carregamento ser rápido e o erro aparecer com nome de arquivo. O build de

release entrega código comprimido, sem nada de console, e é esse que vai para

a loja.

A distinção que importa: console.log em produção mostra dado do usuário.

Publicar com registro ligado é a razão comum de vazamento em aplicativo real. O

build de release remove o registro por padrão, e essa é uma das razões para ele

existir separado do outro.

O exemplo desta página monta os dois builds e a diferença sai em três campos. O

de desenvolvimento tem 12 registros, código legível e tamanho 24800; o de

release tem 0 registros, código ilegível e tamanho 6400. A razão é a mesma

em todos: o release sai sem console, e é o que evita mostrar dado do usuário.

Versionar é o número que o usuário lê: 1.2.0 é maior, maior e correção. O

comprimento do número diz o tamanho da mudança — subir o terceiro porque

corrigiu um texto é exagero; subir o primeiro porque reescreveu a tela é o

mínimo. E o número só sobe depois que a entrega está pronta, não quando o

código começou.

O exemplo lista as três versões com data e mudança, e a comparação de números do

console devolve 1.1.1 como a maior. A linha seguinte diz a regra que os

números obedecem: a correção sobe o terceiro número e a tela nova sobe o

primeiro. É a diferença entre 1.0.0 para a primeira entrega e 1.1.1 para a

correção de um erro de salvamento.

o que o changelog registra

O changelog não é o histórico do git: é o que mudou para quem usa. "Corrigido

o travamento ao salvar um pedido" serve; "refatorado o serviço de pedido" não.

Quem lê o changelog quer saber se o defeito que ele afeta está

corrigido, e essa resposta vem em uma frase por versão.

As três frases do exemplo mostram o critério funcionando: a 1.0.0 diz o que

a primeira versão tem, a 1.1.0 diz que a lista parou de travar, e a 1.1.1

descreve o erro do salvamento sem cliente escolhido. Nenhuma das três menciona

refatoração, e é por isso que as três respondem a pergunta de quem lê.

o README é a primeira tela

O README é o que alguém abre antes de rodar o projeto, e ele responde a quatro

perguntas em ordem: o que é, o que precisa instalar, como se roda, e como se

testa. Um README que começa com a arquitetura é um README que ninguém lê até o

terceiro parágrafo.

O exemplo lista as quatro perguntas numeradas, na ordem que o parágrafo exige, e

a linha final traduz o erro de ordem: um README que começa pela arquitetura é um

README que ninguém lê até o terceiro parágrafo. A arquitetura tem lugar no

material — depois das quatro perguntas, e nunca antes delas.

limpar antes de publicar

Três coisas saem antes de publicar: código de teste que não tem mais uso, dado

de exemplo que ficou no lugar do real, e segredo nenhum no pacote — a base, o

token e a chave de assinatura não vão versionados. É a revisão que o trimestre

inteiro vinha preparando: os quatro critérios da revisão do dia anterior, com o

acréscimo de "isso é seguro mandar para fora?".

A função de conferência do exemplo roda sobre o pacote e devolve as três

linhas: código de teste sem uso em 1 arquivo, dado de exemplo no lugar do real

em 1 arquivo, e segredo no pacote em config/base.js. É o terceiro achado que

distingue esta revisão das quatro perguntas da aula anterior: as outras três são

sobre legibilidade, e esta é sobre segurança.

O fechamento do trimestre é essa revisão, e o que entra nele é o que o

trimestre seguinte vai assumir: componentes que se combinam, listas que não

travam, telas que trocam, e dado que chega de fora. O que falta aqui é o

guardar para depois — e ele fica para o trimestre seguinte, junto com o

SQLite.

O exemplo fecha o trimestre com as quatro entregas listadas e a linha do que fica

para depois: guardar o dado no aparelho. A árvore da tela inicial mostra a

versão como um Text com "versao 1.1.1", e o console explica por que esse

número aparece em um lugar só — o arquivo de versão é a fonte, e a tela apenas o

lê.

Exemplo

// Fechamento: build de release sem registro, versao, changelog e o
// README. O exemplo monta a versao, o changelog e a conferencia do que
// sai antes de publicar.
const { View, Text, StyleSheet } = require('react-native');

// (1) versao: maior, maior, correcao. O numero sobe depois da entrega.
const versoes = [
  { versao: '1.0.0', data: '2026-05-01', mudanca: 'tela de pedidos e detalhe' },
  { versao: '1.1.0', data: '2026-06-15', mudanca: 'lista com rolagem sem travar' },
  { versao: '1.1.1', data: '2026-07-20', mudanca: 'corrigido o erro ao salvar sem cliente' },
];

function maior(a, b) {
  const pa = a.split('.').map(Number);
  const pb = b.split('.').map(Number);
  for (let i = 0; i < 3; i += 1) {
    if (pa[i] !== pb[i]) return pa[i] > pb[i] ? a : b;
  }
  return a;
}

console.log('versoes publicadas:');
for (const v of versoes) console.log('  ' + v.versao, v.data, '-', v.mudanca);
console.log('a maior versao:', maior(maior(versoes[0].versao, versoes[1].versao), versoes[2].versao));
console.log('a correcao sobe o terceiro numero; a tela nova sobe o primeiro');

// (2) o changelog responde o que mudou PARA QUEM USA.
const changelog = {
  '1.1.1': 'Corrigido o erro que aparecia ao salvar um pedido sem cliente escolhido.',
  '1.1.0': 'A lista de pedidos parou de travar ao rolar com muitos itens.',
  '1.0.0': 'Primeira versao com tela de pedidos, detalhe e edicao.',
};
console.log('\nchangelog:');
for (const v of versoes) console.log('  ' + v.versao + ': ' + changelog[v.versao]);
console.log('o changelog nao e o historico do git: e o que mudou para quem usa');

// (3) build de release: sem registro, e sem dado de exemplo.
function saidaDoBuild(desenvolvimento) {
  const registros = desenvolvimento ? 12 : 0;
  return {
    registros,
    legivel: desenvolvimento,
    tamanho: desenvolvimento ? 24800 : 6400,
  };
}
console.log('\nbuild de desenvolvimento:', saidaDoBuild(true));
console.log('build de release:        ', saidaDoBuild(false));
console.log('o release sai sem console: e o que evita mostrar dado do usuario');

// (4) o que sai antes de publicar.
function revisarParaPublicar(arquivos) {
  const problemas = [];
  const testes = arquivos.filter((a) => a.temTeste === false);
  if (testes.length) problemas.push('codigo de teste sem uso: ' + testes.length + ' arquivo(s)');
  const exemplos = arquivos.filter((a) => a.dadoDeExemplo === true);
  if (exemplos.length) problemas.push('dado de exemplo no lugar do real: ' + exemplos.length + ' arquivo(s)');
  const segredos = arquivos.filter((a) => a.temSegredo === true);
  if (segredos.length) problemas.push('segredo no pacote: ' + segredos.map((a) => a.nome).join(', '));
  return problemas.length ? problemas : ['nada a remover'];
}

const pacote = [
  { nome: 'telas/Pedidos.js', temTeste: true, dadoDeExemplo: false, temSegredo: false },
  { nome: 'servicos/pedidos.js', temTeste: true, dadoDeExemplo: false, temSegredo: false },
  { nome: 'dados/exemplo.js', temTeste: true, dadoDeExemplo: true, temSegredo: false },
  { nome: 'config/base.js', temTeste: true, dadoDeExemplo: false, temSegredo: true },
  { nome: 'telas/TesteAntigo.js', temTeste: false, dadoDeExemplo: false, temSegredo: false },
];
console.log('\no que sai antes de publicar:');
for (const linha of revisarParaPublicar(pacote)) console.log('  ' + linha);

// (5) o README responde quatro perguntas, nessa ordem.
const readme = [
  'o que e',
  'o que precisa instalar',
  'como se roda',
  'como se testa',
];
console.log('\no README, em ordem:');
readme.forEach((pergunta, i) => console.log('  ' + (i + 1) + '. ' + pergunta));
console.log('um README que comeca pela arquitetura e um README que ninguem le ate o terceiro paragrafo');

// (6) o que o trimestre entregou.
const entregue = [
  'componentes que se combinam',
  'listas longas que nao travam',
  'telas que trocam',
  'dado que vem de fora',
];
console.log('\no que o trimestre entregou:');
for (const item of entregue) console.log('  ' + item);
console.log('o que fica para o proximo trimestre: guardar o dado no aparelho');

// (7) a arvore da tela inicial, montada com a versao do app.
const estilos = StyleSheet.create({ versao: { padding: 8, fontSize: 12, textAlign: 'center' } });
function TelaDeVersao() {
  return <Text style={estilos.versao}>versao 1.1.1</Text>;
}
const arvore = TelaDeVersao();
console.log('\ntipo:', arvore.type, '| texto:', arvore.props.children);
console.log('a versao mostrada vem do arquivo de versao, em um lugar so');

Saída real

versoes publicadas:
  1.0.0 2026-05-01 - tela de pedidos e detalhe
  1.1.0 2026-06-15 - lista com rolagem sem travar
  1.1.1 2026-07-20 - corrigido o erro ao salvar sem cliente
a maior versao: 1.1.1
a correcao sobe o terceiro numero; a tela nova sobe o primeiro

changelog:
  1.0.0: Primeira versao com tela de pedidos, detalhe e edicao.
  1.1.0: A lista de pedidos parou de travar ao rolar com muitos itens.
  1.1.1: Corrigido o erro que aparecia ao salvar um pedido sem cliente escolhido.
o changelog nao e o historico do git: e o que mudou para quem usa

build de desenvolvimento: { registros: 12, legivel: true, tamanho: 24800 }
build de release:         { registros: 0, legivel: false, tamanho: 6400 }
o release sai sem console: e o que evita mostrar dado do usuario

o que sai antes de publicar:
  codigo de teste sem uso: 1 arquivo(s)
  dado de exemplo no lugar do real: 1 arquivo(s)
  segredo no pacote: config/base.js

o README, em ordem:
  1. o que e
  2. o que precisa instalar
  3. como se roda
  4. como se testa
um README que comeca pela arquitetura e um README que ninguem le ate o terceiro paragrafo

o que o trimestre entregou:
  componentes que se combinam
  listas longas que nao travam
  telas que trocam
  dado que vem de fora
o que fica para o proximo trimestre: guardar o dado no aparelho

tipo: Text | texto: versao 1.1.1
a versao mostrada vem do arquivo de versao, em um lugar so