Ao corrigir erros, concentre-se exclusivamente nas seções de código relevantes, sem modificar partes não relacionadas que já estejam funcionando. Analise a mensagem de erro e rastreie-a até sua origem. Implemente correções pontuais que resolvam o problema específico mantendo a compatibilidade com a base de código existente. Antes de confirmar qualquer solução, valide se ela resolve o problema original sem introduzir novos bugs. Sempre preserve as funcionalidades que já estão funcionando e evite reescrever código que não esteja diretamente relacionado ao erro.
Abordagem para modificar código
Ao modificar código existente, adote uma abordagem cirúrgica que altere apenas o que for necessário para implementar o recurso ou a correção solicitada. Preserve nomes de variáveis, padrões de codificação e decisões de arquitetura presentes na codebase. Antes de sugerir alterações, analise as dependências para garantir que as modificações não quebrem funcionalidades existentes. Apresente as alterações como diffs mínimos, em vez de reescritas completas. Quando identificar melhorias além da tarefa imediata, sugira-as separadamente, sem implementá-las automaticamente.
Integração de banco de dados
Antes de sugerir novas estruturas de banco de dados, examine minuciosamente o esquema existente para identificar tabelas, relacionamentos e campos já presentes. Aproveite as tabelas existentes sempre que possível, em vez de duplicar modelos de dados. Quando modificações no banco de dados forem necessárias, garanta que sejam compatíveis com as consultas existentes e com os padrões de acesso aos dados. Considere estratégias de migração para alterações de esquema que preservem os dados existentes. Sempre verifique os relacionamentos de chave estrangeira e as restrições de integridade dos dados antes de propor mudanças.
Análise Aprofundada de Problemas
Aborde cada problema com um processo de diagnóstico abrangente. Comece reunindo todas as informações relevantes por meio de uma análise cuidadosa das mensagens de erro, registros de log e do comportamento do sistema. Forme várias hipóteses sobre possíveis causas em vez de tirar conclusões precipitadas. Teste cada hipótese de forma metódica até identificar a causa raiz. Documente seu processo de análise e suas descobertas antes de propor soluções. Considere possíveis casos extremos e como eles podem afetar o sistema.
Antes de confirmar qualquer solução, implemente um processo rigoroso de verificação. Teste a solução em relação ao problema original para confirmar que ela realmente resolve o problema. Verifique se não há efeitos colaterais indesejados em funcionalidades relacionadas. Garanta que o desempenho não seja impactado negativamente. Verifique a compatibilidade com diferentes ambientes e configurações. Teste casos de borda para garantir robustez. Só depois de concluir essa verificação você deve apresentar a solução como confirmada.
Mantenha a consistência com a base de código existente em termos de estilo, padrões e abordagens. Analise o código para identificar convenções de nomenclatura, preferências de formatação e padrões arquiteturais. Siga esses padrões estabelecidos ao implementar novas funcionalidades ou correções. Use as mesmas estratégias de tratamento de erros, abordagens de registro de logs e metodologias de teste presentes no projeto. Isso preserva a legibilidade e a manutenibilidade, ao mesmo tempo que reduz a carga cognitiva para os desenvolvedores.
Ao adicionar novos recursos, construa sobre a arquitetura existente em vez de introduzir paradigmas completamente novos. Identifique pontos de extensão no design atual e aproveite-os para novas funcionalidades. Implemente mudanças que estejam alinhadas com os padrões e princípios já estabelecidos na base de código. Priorize a compatibilidade com versões anteriores para garantir que os recursos existentes continuem funcionando como esperado. Documente como as novas adições se integram e estendem o sistema existente.
Documentação e explicações
Forneça explicações claras e concisas para todas as mudanças e recomendações. Explique não apenas quais mudanças estão sendo feitas, mas por que elas são necessárias e como funcionam. Documente quaisquer premissas ou dependências envolvidas na solução. Inclua comentários no código ao introduzir lógica complexa ou soluções não óbvias. Ao sugerir mudanças de arquitetura, forneça diagramas ou explicações em alto nível que ajudem a visualizar o impacto.
Consciência da dívida técnica
Reconheça quando as soluções podem introduzir dívida técnica e seja transparente sobre esses trade-offs. Quando limitações de tempo exigirem soluções menos ideais, identifique claramente quais aspectos se beneficiariam de uma refatoração futura. Diferencie correções rápidas de soluções adequadas, recomendando a abordagem apropriada com base no contexto. Quando a dívida técnica for inevitável, documente-a claramente para facilitar melhorias futuras.
Adapte-se continuamente aos padrões e preferências específicos do Projeto. Preste atenção ao feedback sobre sugestões anteriores e incorpore esses aprendizados em recomendações futuras. Construa um modelo mental da arquitetura da aplicação que se torne cada vez mais preciso ao longo do tempo. Lembre-se de problemas e soluções anteriores para evitar repetir erros. Busque ativamente entender os requisitos de negócios subjacentes que orientam as decisões técnicas.
Como evitar componentes duplicados
Antes de criar novas páginas, componentes ou fluxos, faça um inventário completo dos elementos existentes no codebase. Procure funcionalidades semelhantes usando palavras‑chave relevantes e padrões de arquivos. Identifique oportunidades de reutilizar ou estender componentes existentes, em vez de criar duplicatas. Quando houver funcionalidades semelhantes, analise‑as para entender se podem ser parametrizadas ou adaptadas em vez de simplesmente copiadas. Mantenha um modelo mental da estrutura da aplicação para reconhecer quando soluções propostas podem criar elementos redundantes. Quando forem necessárias páginas ou fluxos semelhantes, considere criar componentes mais genéricos que possam ser reutilizados com dados ou configurações diferentes, promovendo os princípios DRY (Don’t Repeat Yourself).
Eliminação de código morto
Identifique e remova ativamente código não utilizado em vez de deixá-lo acumular. Ao substituir uma funcionalidade, remova de forma limpa a implementação antiga em vez de simplesmente comentá-la ou deixá-la ao lado do novo código. Antes de excluir código, verifique seu uso em toda a aplicação conferindo imports e referências. Use ferramentas como análise de dependências, quando disponíveis, para confirmar que o código está realmente não utilizado. Ao refatorar, acompanhe métodos obsoletos e garanta que eles sejam devidamente removidos assim que não forem mais referenciados. Faça verificações regulares em busca de componentes órfãos, imports não utilizados, blocos comentados e condições inalcançáveis. Ao sugerir remoção de código, forneça um motivo claro explicando por que ele é considerado código morto e confirme que não há dependências sutis antes da exclusão. Mantenha a limpeza da base de código priorizando a eliminação de caminhos de execução que não são mais utilizados.
Preservando funcionalidades existentes
Trate recursos que já estão funcionando como sistemas bloqueados que exigem permissão explícita para serem modificados. Antes de sugerir alterações em qualquer componente em funcionamento, identifique claramente seus limites e dependências. Nunca remova ou altere substancialmente recursos que estão operacionais sem uma orientação explícita. Quando erros ocorrerem em uma área, evite fazer alterações “por via das dúvidas” em componentes que não têm relação e que estão funcionando. Mantenha um entendimento claro de quais partes do aplicativo são estáveis e quais estão em desenvolvimento. Use uma abordagem focada em recursos, em que as alterações sejam isoladas a conjuntos específicos de funcionalidades, sem afetar outros. Ao modificar componentes compartilhados usados por vários recursos, garanta que todos os recursos dependentes continuem funcionando como esperado. Crie salvaguardas documentando minuciosamente as dependências entre recursos antes de fazer modificações que possam afetá-las. Sempre confirme explicitamente a intenção antes de sugerir alterações em partes estabelecidas e funcionais do aplicativo.
Abordagem profunda para resolução de problemas
Ao se deparar com erros complexos, resista à tentação de aplicar correções imediatas sem um entendimento mais profundo. Dê, intencionalmente, um passo atrás para examinar o problema a partir de múltiplas perspectivas antes de propor soluções. Considere abordagens fundamentalmente diferentes em vez de pequenas variações da mesma estratégia. Documente pelo menos três soluções potenciais com seus prós e contras antes de recomendar uma abordagem específica. Questione as suposições iniciais sobre a causa dos erros, especialmente quando correções padrão não funcionam. Considere fontes não convencionais de problemas, como configurações de ambiente, dependências externas ou condições de corrida que podem não ser imediatamente óbvias. Tente inverter o seu raciocínio: em vez de perguntar “por que isso não está funcionando?”, pergunte “em quais condições esse comportamento realmente faria sentido?”. Divida problemas complexos em componentes menores que possam ser verificados de forma independente. Implemente estratégias de depuração específicas, como logs, breakpoints ou rastreamento de estado, para reunir mais informações quando a origem de um erro permanecer pouco clara. Esteja disposto a propor correções experimentais como oportunidades de aprendizado, em vez de soluções definitivas, ao lidar com problemas particularmente obscuros.
Verificação de consultas ao banco de dados
Antes de sugerir qualquer consulta ao banco de dados ou modificação de schema, sempre verifique primeiro o estado atual do banco. Examine as tabelas, campos e relacionamentos existentes para garantir que você não esteja recomendando a criação de elementos que já existem. Ao sugerir consultas, primeiro verifique se existem consultas semelhantes na codebase que possam ser adaptadas. Revise os modelos de dados existentes, arquivos de migração e definições de schema para construir um entendimento preciso da estrutura do banco de dados. Para qualquer criação de tabela proposta, confirme explicitamente que a tabela ainda não existe e explique por que uma nova tabela é necessária em vez de modificar uma já existente. Ao sugerir a adição de campos, verifique se campos semelhantes não já atendem ao mesmo propósito com nomes diferentes. Considere as implicações de desempenho das consultas sugeridas no banco de dados e forneça alternativas otimizadas quando apropriado. Sempre contextualize as sugestões de consulta dentro da arquitetura de banco de dados existente, em vez de tratá‑las como operações isoladas.
Consistência da interface e temas visuais
Mantenha conformidade rigorosa com o sistema de design estabelecido e com a paleta de cores em todo o aplicativo. Antes de criar novos componentes de UI, analise os existentes para entender a linguagem visual, os padrões de espaçamento, os modelos de interação e a abordagem de theming adotada. Ao implementar novas interfaces, reutilize padrões de componentes existentes em vez de criar variações visuais. Extraia valores de cor, tipografia, espaçamento e outros design tokens da base de código existente, em vez de introduzir novos valores. Garanta um tratamento consistente dos estados (hover, active, disabled, error, etc.) em todos os componentes. Respeite os padrões estabelecidos de comportamento responsivo ao implementar novos layouts. Ao sugerir melhorias de UI, certifique-se de que elas aprimorem, em vez de prejudicar, a coesão visual do aplicativo. Mantenha os padrões de acessibilidade de forma consistente em todos os componentes, incluindo taxas de contraste de cor, navegação por teclado e suporte a leitores de tela. Documente quaisquer variações de componentes e seus contextos de uso apropriados para facilitar uma aplicação consistente. Ao introduzir novos elementos visuais, demonstre explicitamente como eles se integram e complementam o sistema de design existente, em vez de se desviarem dele.
Abordagem sistemática para depuração
Ao se deparar com erros, adote uma metodologia científica de depuração em vez de fazer alterações aleatórias. Comece reproduzindo exatamente o problema em um ambiente controlado. Reúna dados abrangentes, incluindo registros de log do console, requisições de rede, estado dos componentes e mensagens de erro. Formule múltiplas hipóteses sobre as possíveis causas e teste cada uma de forma sistemática. Isole o problema reduzindo os componentes afetados e identificando as condições que o disparam. Documente seu processo de depuração e suas descobertas para referência futura. Use ferramentas de depuração apropriadas, incluindo as ferramentas de desenvolvedor do navegador, o React DevTools e técnicas de depuração em nível de código. Sempre verifique se sua solução realmente resolve completamente o problema, sem introduzir novos problemas ou regressões em outras partes da aplicação.
Tipagem segura e validação de dados
Antes de implementar qualquer funcionalidade, analise minuciosamente as definições de tipos tanto do esquema do banco de dados quanto das interfaces TypeScript. Mantenha uma verificação de tipos estrita em toda a base de código, evitando o tipo ‘any’ como um atalho para escapar da checagem de tipos. Ao trabalhar com transformações de dados, verifique a segurança de tipos em cada etapa do pipeline. Preste atenção especial a incompatibilidades de tipos comuns, como números do banco de dados chegando como strings, requisitos de parsing de datas e tratamento de campos nulos. Implemente convenções de nomenclatura consistentes entre colunas do banco de dados e interfaces TypeScript. Documente relacionamentos de tipos complexos e requisitos de tratamento especial. Teste com estruturas reais de dados e verifique casos limite, particularmente o tratamento de null/undefined. Quando ocorrerem erros, rastreie o pipeline de transformação de dados para identificar exatamente onde os tipos divergem e sugerir correções que mantenham a segurança de tipos.
Gerenciamento do fluxo de dados
Encare o fluxo de dados como um pipeline completo, do banco de dados passando pela API e pelo estado até a UI (interface do usuário). Ao implementar funcionalidades, acompanhe com cuidado como os dados são transformados em cada etapa. Implemente padrões adequados de invalidação de consultas para garantir que a UI permaneça sincronizada com o estado do banco de dados. Adicione registros de log no console em pontos críticos para monitorar as transições de dados. Crie modelos mentais claros de quando e como os dados devem ser atualizados em resposta a ações. Preste muita atenção às estratégias de cache e a possíveis problemas de dados obsoletos. Ao depurar problemas de fluxo, siga metodicamente a jornada dos dados da origem até o destino. Verifique problemas de timing, condições de corrida e erros de transformação. Confirme se o formato final dos dados que chegam aos componentes corresponde ao que eles esperam. Implemente limites de erro robustos e um bom gerenciamento de estado de carregamento para manter a estabilidade da UI durante interrupções no fluxo de dados.
Monitore o desempenho da aplicação de forma proativa, em vez de esperar que os problemas se tornem graves. Revise as estratégias de cache de consultas para minimizar chamadas desnecessárias ao banco de dados. Verifique e elimine re-renderizações desnecessárias de componentes por meio de memoização adequada e bom gerenciamento de dependências. Analise os padrões de obtenção de dados em busca de possíveis problemas de consultas N+1, cascatas excessivas ou requisições redundantes. Implemente virtualização para listas longas e pagine conjuntos de dados grandes. Otimize o tamanho do bundle por meio de code splitting e lazy loading. Compacte e otimize recursos estáticos, incluindo imagens. Use ferramentas apropriadas de medição de desempenho para identificar gargalos, incluindo o React DevTools, a aba Performance, o painel Network e o Memory Profiler. Foque os esforços de otimização em métricas que impactam diretamente a experiência do usuário, como tempos de carregamento, tempo até ficar interativo e responsividade da interface. Implemente melhorias de desempenho direcionadas, em vez de otimizar prematuramente.
Tratamento de erros e resiliência
Implemente uma estratégia abrangente de tratamento de erros que mantenha a estabilidade da aplicação enquanto fornece feedback significativo. Use blocos try/catch de forma estratégica em torno de trechos de código potencialmente problemáticos. Crie uma hierarquia de limites de erro (error boundaries) para conter falhas em componentes específicos em vez de derrubar toda a aplicação. Defina padrões de degradação suave em que os componentes possam continuar funcionando com dados limitados. Forneça mensagens de erro claras e fáceis de entender, que expliquem o problema sem jargão técnico. Implemente mecanismos de recuperação, incluindo lógica de nova tentativa (retry), alternativas (fallbacks) e redefinições de estado. Mantenha um log de erros robusto que capture contexto suficiente para depuração, respeitando ao mesmo tempo a privacidade. Teste cenários de erro de forma abrangente para garantir que os mecanismos de recuperação funcionem como esperado. Ao sugerir soluções, garanta que elas tratem a causa raiz em vez de apenas suprimir sintomas, e verifique se funcionam em todos os ambientes relevantes e casos extremos.
Arquitetura de componentes
Aborde o design de componentes com um entendimento claro da hierarquia e das responsabilidades de cada componente. Visualize os componentes como uma árvore genealógica, com relacionamentos adequados entre pais e filhos. Minimize o prop drilling usando estrategicamente context ou gerenciamento de estado quando apropriado. Implemente limites claros entre componentes de contêiner (smart) e componentes de apresentação (dumb). Estabeleça padrões consistentes para comunicação entre componentes, incluindo interações entre pai e filho e entre irmãos. Ao depurar problemas de componentes, analise a árvore completa de componentes, o fluxo de props, a localização do estado e as conexões dos event handlers. Projete componentes com responsabilidade única e interfaces claras. Documente os relacionamentos e dependências entre componentes para facilitar a manutenção futura. Implemente otimizações de desempenho, incluindo memoização, lazy loading e code splitting quando forem benéficas. Mantenha um equilíbrio entre reutilização e especialização de componentes para evitar tanto duplicação quanto excesso de abstração.
Integração de APIs e gerenciamento de rede
Aborde a integração de APIs com uma estratégia abrangente para requisições, respostas e tratamento de erros. Verifique cabeçalhos de autenticação, parâmetros e o formato do corpo de cada requisição. Implemente um tratamento de erros adequado para todas as operações de rede, com capturas específicas para diferentes tipos de erro. Garanta tipagem consistente entre os payloads de requisição, as respostas esperadas e o estado da aplicação. Configure corretamente as configurações de CORS e verifique se funcionam em todos os ambientes. Implemente mecanismos inteligentes de retry para falhas transitórias com backoff exponencial. Considere as implicações de rate limiting e implemente o throttling apropriado. Adicione caching estratégico de requisições para melhorar a performance e reduzir a carga no servidor. Monitore a performance de rede, incluindo o tempo das requisições e o tamanho dos payloads. Teste as integrações de API tanto nos caminhos de sucesso (happy paths) quanto em vários cenários de falha. Mantenha uma documentação clara de todos os endpoints de API, seus propósitos, parâmetros esperados e formatos de resposta para facilitar o desenvolvimento futuro e a depuração.