Blog
Architecture
8 de novembro de 20259 min

Refatorização React Native: de 800 linhas para 100 linhas

Há um momento em que você abre um arquivo e sente fisicamente o peso da dívida técnica. Minha tela principal tinha 800 linhas. Apenas um arquivo. Lógica de negócios, renderização de UI, gerenciamento de estado, chamadas de API — tudo misturado em um componente monolítico impossível de manter. E não era um caso isolado: eu tinha 16 telas no mesmo estado.

O que vou te contar aqui é como transformei um código caótico em uma arquitetura limpa. Não em uma revolução espetacular, mas em um refactoring metódico, tela por tela, erro por erro.

Pontos-chave a reter:
- Um hook customizado por tela separa a lógica de negócios da renderização da UI
- O padrão "orquestrador + subcomponentes" reduz os arquivos de 800 para 100 linhas
- ESLint com regras estritas (zero any, promessas awaited) elimina bugs silenciosos
- A dívida técnica é um custo real mensurável em tempo, bugs e motivação
- Refatorar tela por tela permite entregar continuamente sem quebrar o existente

Por que um componente de 800 linhas é um problema?

A resposta óbvia: é ilegível. Mas o verdadeiro problema é mais insidioso. Um componente monolítico:

  • Esconde bugs: quando tudo está no mesmo arquivo, os efeitos colaterais são imprevisíveis. Modificar a lógica de filtro pode quebrar a animação de transição sem que você entenda o porquê.
  • Atrasa o desenvolvimento: cada modificação exige a compreensão de todo o arquivo. Você passa 20 minutos "lendo" antes de poder escrever 5 linhas.
  • Torna a depuração impossível: quando um bug ocorre, você tem 800 linhas de suspeitos. Não há fronteira clara entre as responsabilidades.
  • Deteriora a motivação: abrir um arquivo monstruoso todas as manhãs é pesado. É o tipo de atrito invisível que atrasa um projeto indie.

"Você está sozinho, quem vai ler este código?" Eu. Eu daqui a três meses, quando tiver esquecido por que esta tela faz o que faz. A dívida técnica não é uma metáfora. É um custo real que se paga em tempo, em bugs e em motivação.

Espaço de trabalho de desenvolvedor organizado com duas telas mostrando código bem estruturado
Um código bem estruturado é como uma mesa bem organizada: tudo é encontrado mais rapidamente.

Que estratégia de divisão adotar?

Eu refatorei as 16 telas seguindo uma estrutura consistente. O padrão é simples, mas poderoso:

1. Um hook customizado para a lógica de negócios

Cada tela tem seu hook: useTaskDetail, useFeedScreen, useGroupScreen... O hook encapsula toda a lógica: carregamento de dados, gerenciamento de estado, callbacks. O componente apenas renderiza JSX.

Antes:

// TaskDetailScreen.tsx - 800 linhas
const TaskDetailScreen = () => {
  const [task, setTask] = useState(null);
  const [loading, setLoading] = useState(true);
  const [editing, setEditing] = useState(false);
  // ... 50 outros useState
  // ... 200 linhas de useEffect
  // ... 300 linhas de handlers
  // ... 250 linhas de JSX
}

Depois:

// TaskDetailScreen.tsx - 100 linhas
const TaskDetailScreen = () => {
  const { task, loading, editing, handlers } = useTaskDetail();
  return (
    <TaskDetailHeader task={task} onEdit={handlers.edit} />
    <TaskDetailBody task={task} />
    <TaskDetailActions handlers={handlers} />
  );
}

O hook useTaskDetail tem 200 linhas. Os subcomponentes têm de 50 a 100 linhas cada. No total, são mais linhas do que antes — mas cada arquivo é compreensível isoladamente.

2. Subcomponentes para a renderização

Cada seção visual da tela se torna um componente dedicado: TaskDetailHeader, TaskDetailBody, TaskDetailActions. Cada um recebe suas props e conhece apenas sua responsabilidade.

Este padrão é diretamente inspirado no Thinking in React oficial. Não é novo, mas é incrível como o esquecemos quando estamos com pressa para entregar.

3. Um componente principal para a orquestração

O componente principal se torna um maestro de 100 linhas: ele chama o hook, distribui as props para os subcomponentes e gerencia o layout global. Nada mais.

Quadro branco com diagramas de arquitetura de software mostrando a separação de componentes
O padrão hook + subcomponentes + orquestrador: simples e eficaz.

Como passar de 71 para 0 erros ESLint?

Paralelamente ao refactoring das telas, executei o ESLint no backend com regras estritas. Resultado: 71 erros.

A tentação: desativar as regras que geram mais erros. É o que 90% dos desenvolvedores fazem. Eu fiz o contrário: corrigi cada erro individualmente.

As correções mais impactantes

Eliminação de any: cada any no TypeScript é uma bomba-relógio. Compila, passa nos testes, mas trava em produção quando um valor inesperado chega. Substituí cada any por um tipo explícito. Alguns casos exigiram a criação de interfaces dedicadas, mas o resultado é um código autodocumentado.

Promessas corretamente awaited: chamadas assíncronas sem await que falhavam silenciosamente. Sem erro, sem aviso — apenas um comportamento incorreto em produção. O ESLint detectou 12 casos de promessas não awaited. 12 bugs potenciais eliminados em uma hora.

Variáveis não utilizadas: imports esquecidos, variáveis declaradas e nunca usadas. Não são bugs, mas ruído que torna o código mais difícil de ler. Cada linha inútil é uma distração para o "você do futuro" que tenta entender o código.

Deve-se refatorar tudo de uma vez ou progressivamente?

Progressivamente. Sempre progressivamente. Um "big bang refactoring" onde você reescreve tudo em uma semana é a receita para o desastre para um desenvolvedor solo. Você quebra tudo, não consegue mais entregar, e se um bug crítico surgir em produção, você não consegue corrigi-lo rapidamente.

Meu método:

  1. Escolher a tela mais dolorosa (aquela que você teme abrir)
  2. Extrair o hook customizado primeiro (a lógica, não a renderização)
  3. Testar se tudo ainda funciona exatamente como antes
  4. Extrair os subcomponentes um por um
  5. Entregar a tela refatorada, passar para a próxima

Cada tela refatorada levava entre 2 horas e meio dia. As mais complexas (o Feed, a tela de grupo) levaram um dia inteiro. Mas a cada etapa, o aplicativo permanecia funcional e entregável.

Este fluxo de trabalho é semelhante ao que Martin Fowler descreve em seu livro sobre refactoring: transformações pequenas, incrementais e sempre reversíveis.

Quais ganhos concretos após o refactoring?

Após duas semanas de trabalho:

  • 16 telas refatoradas: cada uma segue o mesmo padrão (hook + subcomponentes + orquestrador)
  • 0 erro ESLint no backend (contra 71 antes)
  • Tempo de compreensão dividido por 3: abrir uma tela e entender o que ela faz leva 2 minutos em vez de 10
  • Bugs reduzidos: as 3 semanas seguintes foram as mais estáveis do projeto
  • Motivação recuperada: abrir um arquivo limpo pela manhã muda tudo

O ganho menos mensurável, mas o mais importante: a confiança. Após o refactoring, eu não tinha mais medo de modificar uma tela. Eu sabia exatamente onde cada coisa estava, quais eram as dependências e o que uma mudança iria impactar.

Estante de livros de programação bem organizada com cadernos organizados, conceito de ordem e clareza
O refactoring é passar do caos para a clareza. Leva tempo, mas vale a pena.

Como a dívida técnica afeta um projeto solo?

A dívida técnica em um projeto solo tem efeitos específicos que não são encontrados em equipe:

Sem rede de segurança. Em equipe, um colega pode revisar seu código, detectar uma regressão ou corrigir um bug quando você está ausente. Sozinho, se seu código é incompreensível, é você — e somente você — quem paga o preço.

O efeito composto. Cada atalho que você toma hoje se multiplica. Um any aqui, um // TODO: fix later ali, e em alguns meses, você tem um código onde cada modificação leva 3x mais tempo do que deveria.

A espiral de desmotivação. Código sujo → bugs → frustração → patches rápidos → código ainda mais sujo. Eu vi essa espiral em outros projetos. O refactoring a quebrou completamente.

É a mesma lógica que aplico à reestruturação do banco de dados e à auditoria de segurança: investir tempo agora para ganhar exponencialmente mais tarde.

Quais regras ESLint recomendar para um projeto React Native?

Aqui estão as regras que tiveram o maior impacto na qualidade do código TAMSIV:

  • @typescript-eslint/no-explicit-any: proíbe any. Não negociável.
  • @typescript-eslint/no-floating-promises: detecta promessas não awaited. Crítico para evitar bugs silenciosos.
  • @typescript-eslint/no-unused-vars: elimina o ruído do código morto.
  • react-hooks/exhaustive-deps: verifica as dependências dos hooks. Essencial no React Native.
  • no-console: força o uso de um logger em vez de console.log em produção.

Ative todas no modo "error", não "warn". Um aviso é ignorado. Um erro é corrigido.

O que aprendi com esta semana de refactoring

Esta semana foi a melhor do projeto. Não a mais emocionante — nenhuma funcionalidade visível para o usuário. Mas a mais impactante para o futuro. Cada funcionalidade que construí depois — o sistema de gamificação, os grupos hierárquicos, o agenda colaborativa — se beneficiou desta arquitetura limpa.

Se você é um desenvolvedor solo e está adiando um refactoring porque "não entrega nada visível", pare. É o investimento mais rentável que você pode fazer. Não é glamoroso, não é emocionante, mas é fundamentalmente necessário.

A melhor semana do projeto. E eu repito sem hesitação.

FAQ

Quanto tempo leva um refactoring de 16 telas?

Para mim, cerca de duas semanas em tempo integral. Cada tela leva entre 2 horas e um dia, dependendo de sua complexidade. A tela mais simples (um formulário básico): 2 horas. A mais complexa (o Feed com gamificação): um dia completo.

O refactoring introduz novos bugs?

Esse é o principal risco. Para minimizá-lo, eu refatorava uma tela por vez e testava manualmente cada fluxo antes de passar para o próximo. Nenhuma regressão importante apareceu durante as duas semanas de refactoring.

É preciso escrever testes antes de refatorar?

Idealmente, sim. Na realidade, em um projeto solo com 16 telas para refatorar, escrever testes exaustivos antes do refactoring dobraria o tempo. Optei por testes manuais rigorosos e testes automatizados após o refactoring, na arquitetura limpa.

O padrão hook + subcomponentes funciona para todas as telas?

Sim, com variações. Algumas telas simples não precisam de subcomponentes — o hook sozinho é suficiente. Outras telas complexas têm vários níveis de subcomponentes. O princípio permanece o mesmo: separar lógica e renderização.

O ESLint atrasa o desenvolvimento diário?

Nas primeiras horas, sim — o tempo para corrigir os erros existentes. Depois, é o contrário: o ESLint acelera o desenvolvimento detectando erros antes mesmo de iniciar o aplicativo. É como um copiloto que corrige sua trajetória em tempo real.