Ferramentas de design necessárias quando desenvolvedores júnior pensam além do CRUD
Você completou as funcionalidades de CRUD, mas chega o momento em que a manutenção começa a dar medo. O hábito de começar pelo design das tabelas faz com que o sistema se torne emaranhado. Este artigo contém metodologias concretas para separar o código em unidades de domínio e padronizar o ambiente, limitando assim o escopo de modificações.
Aumentando a coesão do código: separando o acesso a dados da lógica
Se a lógica de negócios estiver misturada no controlador, você terá que reescrever o código toda vez que a estrutura do banco de dados mudar. Adote uma arquitetura em camadas para isolar ambos. É possível reduzir o tempo de manutenção da base de código em cerca de 40%.
As etapas para separar o acesso a dados da lógica são as seguintes:
- Mova o código de validação do controlador para o DTO de requisição e utilize anotações de validação.
- Reúna a lógica espalhada em transaction scripts dentro de métodos da entidade de domínio.
- Em vez de drivers de banco de dados específicos, declare uma interface que defina o comportamento de persistência para separar a camada de domínio.
Mesmo que um esquema de tabela específico mude, as regras centrais permanecem intactas.
Criando um ambiente de teste com injeção de dependência
Se você criar objetos diretamente dentro das classes usando o operador new, testes unitários tornam-se impossíveis. Implemente a Inversão de Controle (IoC) para realizar testes independentes com objetos simulados (Mock) sem a necessidade de servidores externos.
Estes são os procedimentos práticos para aumentar a eficiência dos testes:
- Declare os colaboradores que o objeto utilizará como interfaces, não como classes concretas.
- Configure o container externo para injetar a implementação adequada no momento da execução.
- Utilize ferramentas como
@automock/jest para automatizar a configuração de test doubles.
Ao usar essa estrutura, você pode melhorar a velocidade de execução dos testes em mais de 20%.
Isolando entidades e DTOs
Se você mapear a estrutura da UI e as tabelas do banco de dados um para um, terá que modificar o esquema do banco de dados toda vez que corrigir uma tela. Separe rigorosamente os DTOs, usados para mensagens de rede, das entidades de domínio.
Aqui está como isolar ambos usando mappers:
- Crie classes de mapper puras dedicadas apenas à conversão de dados.
- Transfira os dados apenas dentro do mapper para que não haja dependência direta entre DTOs e entidades.
- Force a camada de serviço a utilizar apenas entidades.
Mesmo que você troque o repositório de dados, não será necessária nenhuma modificação na lógica.
Ajustando o ambiente de desenvolvimento com Docker Compose
Se o ambiente local de cada desenvolvedor for diferente, a colaboração para. Sincronize o ambiente escrevendo a infraestrutura como código usando Docker Compose.
Procedimentos para criar um ambiente padrão:
- Escreva a versão do banco de dados e do servidor de cache, além das variáveis de ambiente, no arquivo
docker-compose.yml.
- Coloque o SQL de esquema inicial no diretório
/docker-entrypoint-initdb.d usando volume mount.
- Evite emaranhados de dependências usando um vinculador de pacotes como o pnpm Workspaces.
Ao concluir esta configuração, você poderá subir uma infraestrutura padrão em 3 segundos, sem se preocupar com as configurações da máquina local.
Modelando o domínio antes de projetar as tabelas
Se você desenhar o ERD primeiro, obterá apenas uma lógica fragmentada focada em dados. A Shopify, com mais de 800 engenheiros, deixou para trás o legado focado em esquemas físicos e migrou para uma modelagem focada em objetos de negócio.
Etapas para iniciar a modelagem de domínio:
- Liste os principais substantivos e verbos do domínio com base nos casos de uso e na linguagem onipresente (ubiquitous language).
- Defina entidades que exigem transições de estado e objetos de valor (value objects) com atributos imutáveis.
- Determine as raízes de agregação (aggregate roots) para verificar a integridade dos negócios por unidade de transação.
Essa abordagem mantém o escopo de modificação confinado dentro de um módulo específico, mesmo quando os requisitos mudam. Projetar sistemas complexos é a alternativa mais prática para eliminar a sensação de incerteza.