-2

Na era da programação com IA, DDD supera o MVC tradicional?

Durante muitos anos, o MVC foi a escolha mais comum para desenvolver aplicações web. Ele é simples de entender, rápido de implementar e funciona muito bem para sistemas pequenos.

Por outro lado, o Domain-Driven Design costuma ser visto como complexo, caro e trabalhoso. Por isso, muitas equipes acabam evitando DDD mesmo quando o projeto possui regras de negócio importantes.

Mas a programação mudou.

Com o avanço das ferramentas de IA, o maior problema do desenvolvimento já não é apenas escrever código. Hoje, uma IA consegue gerar Controllers, Services, entidades, consultas SQL e testes em poucos segundos.

O problema mais difícil passou a ser outro:

Como manter os limites e as responsabilidades do sistema sob controle?

O MVC possui uma estrutura fácil de compreender:

Request
  ↓
Controller
  ↓
Service
  ↓
Repository
  ↓
Database

Para um CRUD simples, esse modelo funciona muito bem.

O desenvolvedor recebe uma requisição, cria um Controller, adiciona um Service, acessa o banco e retorna uma resposta. A quantidade de código é pequena e o resultado aparece rapidamente.

O problema começa quando o sistema cresce.

Uma nova regra é adicionada ao Controller. Depois outra regra vai para o Service. Uma integração externa é colocada no mesmo fluxo. Uma validação aparece em outro módulo. Uma exceção é tratada em um terceiro lugar.

No início, tudo parece organizado. Depois de algumas mudanças, o sistema começa a apresentar:

  • Controllers muito grandes
  • Services genéricos demais
  • Regras duplicadas
  • Entidades sem comportamento
  • Dependência excessiva do banco de dados
  • Módulos que conhecem detalhes demais uns dos outros
  • Alterações simples causando efeitos em várias partes do sistema

O MVC não impede esse problema. Ele organiza principalmente o fluxo da aplicação, mas não define com precisão os limites do negócio.

Por que o DDD não foi adotado em larga escala?

O DDD resolve parte desse problema, mas possui um custo inicial maior.

Antes de escrever o código, é necessário entender:

  • Quais são os conceitos importantes do negócio
  • Quais regras precisam ser protegidas
  • Quais objetos possuem identidade
  • Quais dados formam um Value Object
  • Quais operações pertencem a cada agregado
  • Onde termina um contexto e começa outro
  • Quais módulos podem conversar entre si

Esse trabalho exige análise, conversa com especialistas do negócio e decisões arquiteturais.

Em muitos projetos, principalmente aqueles com prazos curtos, isso parece lento e excessivo. É mais fácil criar uma tabela, um CRUD e alguns Services do que modelar corretamente o domínio.

Por isso, o MVC acaba vencendo no curto prazo.

Ele é simples de escrever.

O DDD é mais difícil de desenhar.

O impacto da programação com IA

A inteligência artificial alterou essa relação entre esforço e resultado.

Antes, uma parte significativa do trabalho estava em escrever código repetitivo. Hoje, ferramentas de IA conseguem gerar rapidamente:

  • Endpoints
  • DTOs
  • Controllers
  • Services
  • Repositories
  • Migrations
  • Testes básicos
  • Documentação inicial

Isso reduz o custo de implementar funcionalidades.

Porém, também aumenta um risco: gerar código rapidamente dentro de uma arquitetura mal definida.

Se o projeto não possui limites claros, a IA tende a seguir os padrões que já existem no código. Se encontra um Controller grande, pode criar outro Controller grande. Se encontra um Service que acessa cinco módulos, pode repetir o mesmo padrão.

A velocidade de geração não corrige uma arquitetura confusa. Em alguns casos, apenas faz o sistema ficar confuso mais rapidamente.

Por isso, na era da programação com IA, o principal problema deixa de ser:

Quanto tempo leva para escrever esta funcionalidade?

E passa a ser:

Em qual parte do sistema esta funcionalidade deveria existir?

DDD define limites antes da implementação

Uma das principais forças do DDD é que ele obriga a equipe a pensar nos limites do sistema.

Por exemplo, em uma plataforma de pagamentos, podemos ter contextos diferentes:

Customer Context
Payment Context
Billing Context
Notification Context

Cada contexto possui seus próprios conceitos e regras.

O objeto Customer do contexto de pagamentos não precisa ser exatamente igual ao Customer do contexto de notificações.

Essa separação evita que um único modelo seja usado para representar todos os significados possíveis do negócio.

No DDD, a arquitetura começa a responder perguntas importantes:

  • Quem é responsável por esta regra?
  • Qual módulo pode alterar este estado?
  • Qual contexto possui este conceito?
  • Esta integração pertence ao domínio ou à infraestrutura?
  • Esta operação é um caso de uso ou apenas uma consulta?
  • Este objeto pode ser compartilhado ou deve ser convertido?

Essas decisões criam fronteiras antes que o código seja escrito.

Um exemplo simples

Considere a regra:

Um pedido não pode ser confirmado sem itens e não pode ser confirmado duas vezes.

Em uma aplicação MVC pouco estruturada, essa regra pode acabar no Controller:

if (order.getItems().isEmpty()) {
    throw new BusinessException("Order without items");
}

if (order.getStatus() == CONFIRMED) {
    throw new BusinessException("Order already confirmed");
}

order.setStatus(CONFIRMED);

Mais tarde, outro Controller pode implementar uma versão ligeiramente diferente da mesma regra.

Em uma abordagem orientada ao domínio, o agregado protege suas próprias invariantes:

public class Order {

    private OrderStatus status;
    private final List<OrderItem> items = new ArrayList<>();

    public void confirm() {
        if (items.isEmpty()) {
            throw new DomainException("An order must have items");
        }

        if (status == OrderStatus.CONFIRMED) {
            throw new DomainException("Order is already confirmed");
        }

        status = OrderStatus.CONFIRMED;
    }
}

O caso de uso apenas coordena o fluxo:

public class ConfirmOrderUseCase {

    private final OrderRepository repository;

    public void execute(UUID orderId) {
        Order order = repository.findById(orderId)
            .orElseThrow(OrderNotFoundException::new);

        order.confirm();

        repository.save(order);
    }
}

A regra possui um lugar claro. Qualquer parte da aplicação que queira confirmar um pedido precisa passar pelo mesmo comportamento.

A diferença fundamental

O MVC normalmente começa pela pergunta:

Como receber uma requisição e retornar uma resposta?

O DDD começa por perguntas diferentes:

Qual é o problema de negócio?
Quais regras precisam ser protegidas?
Quem é responsável por cada comportamento?
Quais partes do sistema devem permanecer separadas?

Essa diferença é muito importante quando utilizamos IA para programar.

A IA é excelente em gerar código dentro de uma estrutura conhecida. Mas ela não deve decidir sozinha os limites do domínio.

Se os limites não foram definidos pela equipe, a IA tende a espalhar regras entre os lugares mais convenientes.

DDD não significa abandonar o MVC

É importante deixar claro que DDD e MVC não são alternativas incompatíveis.

Uma aplicação pode usar MVC na camada de entrada e DDD no núcleo do negócio:

Controller
    ↓
Application Service
    ↓
Domain Model
    ↓
Repository
    ↓
Infrastructure

O Controller continua existindo, mas possui uma responsabilidade menor.

Ele recebe a requisição e chama um caso de uso. A regra principal fica no domínio. A infraestrutura implementa detalhes técnicos sem dominar o modelo de negócio.

DDD também pode ser mal utilizado

Adotar DDD não significa criar dezenas de classes e interfaces sem necessidade.

Uma aplicação simples de cadastro de categorias provavelmente não precisa de uma arquitetura extremamente sofisticada.

O DDD faz mais sentido quando existem:

  • Muitas regras de negócio
  • Diferentes fluxos para o mesmo objeto
  • Integrações importantes
  • Estados e transições complexas
  • Risco financeiro ou operacional
  • Várias equipes trabalhando no mesmo sistema
  • Necessidade de evolução durante muitos anos

A questão não é usar DDD em absolutamente todos os projetos. A questão é reconhecer que a complexidade do domínio precisa de limites explícitos.

Conclusão

O MVC continua sendo uma excelente escolha para sistemas simples. Seu baixo custo inicial é uma vantagem real.

Mas, em projetos complexos, ele pode permitir que o código cresça sem uma separação clara de responsabilidades. A cada nova necessidade, mais lógica é adicionada aos mesmos Controllers, Services e módulos.

Na era da programação com IA, escrever código ficou mais barato. O que ficou mais valioso foi decidir onde o código deve existir.

É por isso que o DDD se torna cada vez mais relevante.

Ele não é importante apenas porque organiza melhor as classes. Ele é importante porque define limites, responsabilidades e regras antes que a implementação cresça de forma descontrolada.

A IA pode gerar milhares de linhas de código. Mas ainda precisamos decidir:

Qual é o limite de cada módulo?
Qual regra pertence a qual contexto?
O que este componente pode conhecer?
O que ele nunca deveria conhecer?

Essa é a parte da arquitetura que continua dependendo de uma boa compreensão do negócio.

Gostaria de saber como outras equipes estão utilizando DDD em projetos desenvolvidos com auxílio de ferramentas de IA.

Carregando publicação patrocinada...