Domain-Driven Design em C++: arquitetura para projetos complexos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que DDD não é sobre diagramas chatos, mas sobre arquitetura viva

\n

Quando um projeto em C++ ultrapassa o tamanho de uma aplicação "de brinquedo", os desenvolvedores frequentemente enfrentam o caos: a lógica de negócios espalhada pelos controladores, o banco de dados ditando a estrutura das classes, e os novatos com medo de tocar no código legado. Domain-Driven Design (DDD) não é um conjunto de regras abstratas, mas uma ferramenta prática que ajuda a domar a complexidade. Neste artigo, vamos explorar como implementar DDD em C++, usando exemplos concretos de código, e por que isso salvará seu projeto da "grande bola de lama".

\n\n

O que é DDD e por que um desenvolvedor C++ precisa dele?

\n

Domain-Driven Design (design orientado a domínio) é uma abordagem onde o foco principal está no modelo do domínio, e não nos detalhes técnicos. Em C++, isso é especialmente relevante: a linguagem oferece ferramentas poderosas (templates, RAII, ponteiros inteligentes), mas sem uma arquitetura adequada, o projeto se transforma em um monólito onde alterar uma funcionalidade quebra tudo.

\n

DDD propõe dois níveis:

\n
    \n
  • Modelagem estratégica: divisão do sistema em contextos (Bounded Contexts) e configuração da interação entre eles.
  • \n
  • Modelagem tática: blocos de construção — Entity, Value Object, Aggregate, Repository, Domain Service.
  • \n
\n

Vamos nos concentrar na modelagem tática, pois é ela que fornece padrões concretos para o código em C++.

\n\n

Arquitetura em camadas: o fundamento do DDD em C++

\n

DDD pressupõe uma divisão clara em camadas. A estrutura típica para um projeto C++ é a seguinte:

\n
    \n
  • Domain Layer (núcleo): entidades, value objects, agregados, serviços de domínio. Sem dependências de frameworks ou bibliotecas externas.
  • \n
  • Application Layer: casos de uso (use cases), orquestração. Depende apenas do Domain.
  • \n
  • Infrastructure Layer: implementação de repositórios (SQL, Redis, arquivos), integração com APIs externas. Implementa interfaces do Domain.
  • \n
  • Presentation Layer: interface do usuário (console, REST API, GUI).
  • \n
\n

Isso não é uma regra rígida, mas uma recomendação. O principal é que as dependências apontam para dentro: camadas externas podem depender das internas, mas não o contrário.

\n\n

Exemplo: como NÃO fazer

\n
// ❌ Ruim: lógica de negócios misturada com SQL\nclass UserController {\n    void createUser(const std::string& name) {\n        // Consulta SQL diretamente aqui\n        db.execute("INSERT INTO users (name) VALUES (?)", name);\n        // Lógica de validação também aqui\n        if (name.empty()) throw std::runtime_error("Name required");\n    }\n};\n
\n\n

Exemplo: estilo DDD

\n
// ✅ Bom: separação clara\nclass User : public Entity<User, int> {\n    std::string name_;\npublic:\n    explicit User(int id, std::string name) : Entity(id), name_(std::move(name)) {\n        if (name_.empty()) throw std::invalid_argument("User name cannot be empty");\n    }\n    const std::string& name() const { return name_; }\n};\n\n// Interface do repositório (Domain)\nclass IUserRepository {\npublic:\n    virtual ~IUserRepository() = default;\n    virtual void save(const User& user) = 0;\n};\n\n// Implementação (Infrastructure)\nclass SqlUserRepository : public IUserRepository {\n    void save(const User& user) override {\n        // Apenas SQL, sem lógica de negócios\n    }\n};\n
\n\n

Blocos de construção do DDD em C++

\n\n

Entity (Entidade)

\n

É um objeto com um identificador único que persiste ao longo do tempo. Em C++, é conveniente criar uma classe base template:

\n
template<typename T, typename IdType>\nclass Entity {\n    IdType id_;\npublic:\n    explicit Entity(IdType id) : id_(std::move(id)) {}\n    IdType id() const { return id_; }\n    bool operator==(const Entity& other) const { return id_ == other.id_; }\n                

Blogs

Book Recommendations