Domain-Driven Design em Swift: como parar de lutar contra a arquitetura

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 "mais um padrão"

\n\n

Você já reescreveu um projeto do zero só porque "a lógica de negócio se espalhou por todos os controladores"? Ou talvez seu UserManager tenha crescido para 2000 linhas, e ninguém entende o que ele realmente faz? Familiar?

\n\n

No mundo do desenvolvimento Swift, estamos acostumados com MVC, VIPER ou MVVM. Mas todos esses padrões resolvem o mesmo problema: como separar a UI da lógica. No entanto, eles quase não dizem nada sobre como organizar a própria lógica de negócio. E é aí que entra o Domain-Driven Design (DDD) — uma abordagem que coloca no centro não o framework, mas o domínio da sua aplicação.

\n\n

Neste artigo, vamos explorar como aplicar o Domain-Driven Design em Swift com exemplos reais. Você verá que DDD não é uma teoria abstrata, mas uma ferramenta poderosa que torna o código legível, testável e resistente a mudanças.

\n\n

O que é DDD em palavras simples

\n\n

Imagine que você está escrevendo um aplicativo para uma loja online. O MVC dirá: "Crie um modelo Product, um controlador ProductViewController e as views". Já o DDD perguntará: "O que é um 'produto' no seu negócio? Ele pode existir sem preço? O que acontece quando é adicionado ao carrinho?"

\n\n

Domain-Driven Design é uma forma de modelar software onde o código reflete com máxima precisão a linguagem e as regras do negócio. Em vez de entidades "técnicas" (como DataManager), você trabalha com objetos de domínio: Order, Customer, Invoice.

\n\n

Os principais blocos do DDD

\n\n

Para não se perder em termos, lembre-se de três conceitos principais:

\n\n
    \n
  • Entity (Entidade) — um objeto que possui identidade. Dois objetos com os mesmos campos são entidades diferentes (como duas pessoas diferentes com o mesmo nome).
  • \n
  • Value Object (Objeto de Valor) — um objeto que é definido apenas por seus atributos. Se dois objetos têm todos os campos iguais, são o mesmo objeto (como uma data ou um valor monetário).
  • \n
  • Aggregate (Agregado) — um grupo de objetos relacionados que é tratado como uma unidade. O agregado tem uma raiz (root entity), através da qual o acesso a todos os objetos internos é feito.
  • \n
\n\n

Parece seco? Vamos para o Swift.

\n\n

Escrevendo o modelo de domínio em Swift

\n\n

Suponha que estamos criando um aplicativo de gerenciamento de tarefas (TODO-list). Vamos começar com o mais simples — um Value Object para o status da tarefa.

\n\n
// Value Object: status da tarefa\nstruct TaskStatus: Equatable {\n    let rawValue: String\n    \n    static let todo = TaskStatus(rawValue: "todo")\n    static let inProgress = TaskStatus(rawValue: "inProgress")\n    static let done = TaskStatus(rawValue: "done")\n    \n    // Regra de negócio: só é possível transitar para o próximo status\n    func canTransition(to newStatus: TaskStatus) -> Bool {\n        switch (self, newStatus) {\n        case (.todo, .inProgress), (.inProgress, .done):\n            return true\n        default:\n            return false\n        }\n    }\n}
\n\n

Observe: não usamos enum, porque em um negócio real os status podem vir do servidor ou ser armazenados no banco de dados. TaskStatus é um objeto imutável que conhece suas próprias regras.

\n\n

Agora vamos criar uma Entity — a própria tarefa:

\n\n
// Entity: tarefa\nfinal class Task {\n    let id: UUID\n    var title: String\n    var description: String\n    private(set) var status: TaskStatus\n    let createdAt: Date\n    \n    init(id: UUID = UUID(), title: String, description: String, status: TaskStatus = .todo) {\n        self.id = id\n        self.title = title\n        self.description = description\n        self.status = status\n                

Blogs

Book Recommendations