Este documento descreve um plano abrangente para refatorar a aplicação AI Task Manager, seguindo as melhores práticas de engenharia de software. O plano aborda separação de responsabilidades, organização de código e manutenibilidade.
- Módulos de servidor (.server.ts) jamais devem ser referenciados em arquivos de componentes React, a não ser que este arquivo seja um módulo de rota (vivendo em ~/app/routes)
Objetivo: Mover a lógica de negócios para camadas de serviço para separar responsabilidades e melhorar a testabilidade.
Estratégia de implementação:
-
Criar módulos de serviço robustos:
task.server.ts
: Implementar operações CRUD com tratamento de erros adequadochat.server.ts
: Implementar operações de gerenciamento de chat e processamento de mensagens- Usar classes de erro personalizadas para erros específicos do domínio
-
Estabelecer padrões consistentes para funções de serviço:
- Funções de serviço com parâmetros diretos (ex:
updateTask(id, data)
) - Funções manipuladoras para processar FormData (ex:
handleTaskCreateOrUpdate(formData)
) - Funções auxiliares para formatar e preparar dados (ex:
prepareMessagesForDisplay(messages)
)
- Funções de serviço com parâmetros diretos (ex:
-
Refatorar rotas específicas:
task-new.tsx
: Usar funções de serviço para criação/atualização de tarefastask-edit.tsx
: Substituir chamadas diretas ao Prisma por funções de serviçotask-view.tsx
: Delegar a busca de dados à camada de serviçotasks.tsx
: Usar funções de serviço para listagem e exclusãochats.tsx
: Usar funções de serviço para operações de chatapi.chat.ts
: Usar a camada de serviço para processamento de mensagens
Impacto esperado:
- Maior testabilidade da lógica de negócios
- Separação clara entre manipuladores de rota e operações de negócio
- Tratamento de erros centralizado
- Manutenção e extensões futuras facilitadas
Objetivo: Organizar componentes por domínio de funcionalidade para melhorar a descoberta de código.
Estratégia de implementação:
-
Criar diretórios específicos por funcionalidade:
- Criar diretório
app/features/chats
- Mover componentes relacionados a chat da pasta
tasks
para a pastachats
- Atualizar imports em todo o código
- Criar diretório
-
Organizar componentes específicos de tarefas:
- Manter toda a lógica e UI de tarefas em
app/features/tasks
- Garantir que cada componente trate de um único aspecto da funcionalidade
- Verificar consistência na nomenclatura
- Manter toda a lógica e UI de tarefas em
-
Extrair componentes de UI reutilizáveis:
- Criar componente
TaskDetails
emapp/features/tasks
- Simplificar
task-view.tsx
para focar no carregamento de dados
- Criar componente
-
Revisar componentes compartilhados:
- Manter componentes como NavMain, NavUser, AppSidebar, SiteHeader em
app/components
- Refatorar ChatInterface para aceitar props ao invés de usar
useLoaderData
diretamente
- Manter componentes como NavMain, NavUser, AppSidebar, SiteHeader em
Impacto esperado:
- Organização mais clara do código por domínio
- Melhor separação de responsabilidades
- Maior reutilização de componentes
- Manutenção facilitada com o crescimento da aplicação
Objetivo: Remover duplicação de código e centralizar operações comuns.
Estratégia de implementação:
-
Criar camada de serviço para operações consistentes:
- Implementar funções de serviço reutilizáveis entre rotas
- Estabelecer padrões consistentes de tratamento de erros
- Adicionar segurança de tipo com classes de erro personalizadas
-
Criar manipuladores para processamento de formulários:
handleTaskCreateOrUpdate(formData)
em task.server.tshandleTaskDelete(formData)
em task.server.tshandleChatUpdate(formData)
em chat.server.tshandleChatDelete(formData)
em chat.server.tshandleChatDataForTaskCreation(url)
em chat.server.ts
-
Unificar parsing/formatação de campos de tarefas:
- Criar funções utilitárias para operações comuns:
// Utilitário para converter string multilinha em array JSON
export function linesToJsonArray(str: string): string {
return JSON.stringify(
str
.split("\n")
.map((s) => s.trim())
.filter(Boolean)
);
}
// Utilitário para interpretar arrays JSON com segurança
export function parseJsonList(jsonStr?: string): string[] {
try {
return jsonStr ? JSON.parse(jsonStr) : [];
} catch {
return [];
}
}
- Padronizar padrões de UI:
- Extrair padrões comuns de tabelas e formulários
- Criar botões reutilizáveis para ações como deletar/editar
- Usar exibição de mensagens de erro consistente
Impacto esperado:
- Redução de duplicação de código
- Comportamento mais consistente na aplicação
- Manutenção e correção de bugs facilitadas
- Melhor experiência para desenvolvedores
Objetivo: Cada módulo deve ter uma única responsabilidade e razão para mudar.
Estratégia de implementação:
-
Implementar camada de serviço com responsabilidades claras:
task.server.ts
para lógica de tarefaschat.server.ts
para chats e mensagens- Cada função com um propósito claro e focado
-
Manter arquivos de rota enxutos:
- Focar exclusivamente no tratamento de requisição/resposta
- Delegar lógica de negócio para funções de serviço
- Retornar dados apropriados para a interface
- Nenhuma operação direta no banco de dados
-
Refatorar componentes de UI complexos:
- Dividir componentes como ChatsList se estiverem sobrecarregados
- Usar composição para interações complexas
-
Centralizar integração com IA:
- Manter toda lógica relacionada ao OpenAI em
chat.server.ts
- Documentar claramente interações com IA
- Manter toda lógica relacionada ao OpenAI em
Impacto esperado:
- Código mais fácil de entender e manter
- Separação de responsabilidades mais clara
- Testes unitários mais focados
- Menor complexidade nos módulos
Objetivo: Estabelecer convenções consistentes de nomes e padrões de código.
Estratégia de implementação:
-
Definir padrões consistentes de parâmetros:
- Parâmetros diretos para funções principais de serviço
- Objetos FormData para manipuladores
- Tratamento de erros com classes personalizadas
- Objetos de resposta padronizados (ex:
{ success: boolean, error?: string }
)
-
Padronizar nomenclatura de arquivos:
- Usar
task-form.tsx
,tasks-list.tsx
, etc. dentro da pasta de tarefas - Usar plural para listas, singular para visualizações individuais
- Nomes de arquivos em kebab-case, funções de componente em PascalCase
- Usar
-
Manter consistência nos imports:
- Atualizar todos os imports ao mover arquivos
- Usar padrões consistentes de importação
- Agrupar imports por tipo (React, bibliotecas, componentes locais)
Impacto esperado:
- Base de código mais previsível
- Navegação facilitada
- Melhor experiência de desenvolvimento
- Menos erros por padrões inconsistentes
Objetivo: Aprimorar e elevar a qualidade do código além das mudanças estruturais.
Estratégia de implementação:
-
Implementar tratamento de erros abrangente:
- Criar classes de erro personalizadas (ex:
TaskNotFoundError
,ChatUpdateError
) - Estabelecer formato consistente de resposta a erros
- Adicionar verificação de tipo adequada para erros desconhecidos
- Criar classes de erro personalizadas (ex:
-
Adicionar documentação:
- Comentários JSDoc em todas as funções de serviço
- Documentar requisitos de parâmetros e valores de retorno
- Documentar possíveis erros e casos extremos
- Comentários inline para lógica complexa
-
Considerar melhorias futuras:
- Abstração de repositório para operações no banco de dados
- Maior separação entre lógica de negócio e acesso a dados
- Padronização de formatos de resposta dos serviços
- Implementação consistente de exibição de erros na UI
-
Testar cuidadosamente:
- Verificar todos os fluxos após refatoração
- Testar casos de tratamento de erro
- Garantir preservação do comportamento existente
Para implementar este plano de refatoração, seguiremos estas etapas:
-
Criar módulos de serviço primeiro:
- Começar com operações CRUD essenciais
- Implementar tratamento de erros
- Adicionar operações especializadas
- Adicionar manipuladores para processamento de formulários
-
Refatorar rotas uma a uma:
- Começar com rotas mais simples como
tasks.tsx
etask-view.tsx
- Avançar para rotas mais complexas como
task-new.tsx
eapi.chat.ts
- Testar cada rota cuidadosamente após refatorar
- Começar com rotas mais simples como
-
Reorganizar estrutura de pastas:
- Criar novas pastas por funcionalidade
- Mover componentes e atualizar imports
- Testar para garantir funcionamento
-
Eliminar duplicação:
- Criar funções utilitárias
- Atualizar código para usar os utilitários
- Testar cuidadosamente
-
Melhorar documentação e polimento:
- Adicionar comentários JSDoc
- Garantir nomenclatura e padrões consistentes
- Corrigir inconsistências remanescentes