Olá! Sejam muito bem-vindos ao nosso curso de aplicação de padrões táticos do Domain-Driven Design. Meu nome é Vinícius Albano, sou o instrutor deste curso.
Audiodescrição: Vinícius é um homem branco, com cabelo castanho e barba curta. Ele está em seu escritório, onde o curso está sendo gravado.
Neste curso, vamos aprender a aplicar os padrões do Domain-Driven Design. A proposta é que compreendamos objetos de valor, entidades, agregados, repositórios, serviços de domínio e de aplicação. Também abordaremos noções básicas sobre eventos de domínio e como implementar uma arquitetura orientada a eventos de forma básica.
Trabalharemos com um projeto prático, um sistema de e-commerce, focando no contexto de pedidos. Vamos evoluir e construir todo o domínio até chegarmos à integração com o módulo de pagamentos. Essa integração será feita de forma assíncrona, e discutiremos os desafios que enfrentamos, como o acoplamento entre diferentes contextos delimitados. Além disso, realizaremos uma integração assíncrona orientada a eventos, demonstrando como é possível evoluir o sistema por meio dos eventos do domínio.
Este curso é recomendado para quem deseja aprender a aplicar o domínio de Event Design na prática, ou seja, durante a parte de codificação do projeto. Nós temos outros cursos orientados também a líderes técnicos e gerentes de projetos que abordam o DDD na parte mais estratégica, mas este curso é mais indicado para quem vai realizar a codificação dos projetos de verdade.
Para aproveitar este curso ao máximo, é recomendado que já tenhamos uma noção sólida de Node.js, TypeScript e que já tenhamos realizado algum projeto utilizando o Framework Nest, pois é ele que utilizaremos para a codificação. Não abordaremos o funcionamento completo do Nest, assumiremos que já temos esse conhecimento e aplicaremos os conceitos de DDD junto com o Nest.
Também é recomendado que já tenhamos concluído os outros dois cursos de DDD aqui na Alura, onde são abordados todos os fundamentos e a questão da modelagem estratégica. Nesses cursos, aprendemos a diferença entre os diferentes contextos delimitados, como eles funcionam e como funciona o mapa de contexto, pois utilizaremos esses conceitos ao longo deste curso.
Esperamos que aproveitem esta jornada e absorvam muito conteúdo interessante sobre como utilizar o DDD na prática com os padrões táticos. Boa jornada!
Olá, dev! Esperamos que estejam bem. Estamos muito felizes por estarem conosco no nosso terceiro curso de Domain Dreaming Design. Neste curso, finalmente colocaremos a mão na massa e aprenderemos a codificar nossos padrões táticos.
Já tivemos uma introdução sobre esses padrões no nosso primeiro curso de fundamentos. No segundo curso, sobre planejamento estratégico com Domain Dreaming Design, entendemos como funcionam os agregados e por que são importantes. Agora, é interessante desenvolvermos um projeto do zero. Vamos discutir um pouco sobre cada um dos padrões, por que eles existem e como podemos, de fato, realizar a modelagem.
No VS Code, temos o nosso repositório. Estamos na branch projeto base, onde temos uma estrutura inicial. Basicamente, instalamos o NestJS e fizemos algumas pequenas modificações no diretório. Criamos uma pasta de contextos, onde teremos nossos contextos delimitados.
Vocês sabem o que é isso?
Vamos criar o contexto de orders, nosso contexto de pedidos, dentro do nosso e-commerce. Aqui, basicamente, temos nosso módulo do aplicativo padrão do NestJS. Não há nada de extraordinário, apenas consumimos nosso módulo de pedidos. Importamos nosso controller de pedidos e nosso serviço de pedidos também. Não fizemos nada além de renomear as funcionalidades.
Para começar, vamos configurar o módulo principal do nosso aplicativo, o AppModule, que irá importar o módulo de pedidos:
import { Module } from '@nestjs/common';
import { OrdersModule } from './contexts/orders/orders.module';
@Module({
imports: [OrdersModule],
})
export class AppModule {}
Agora que configuramos o AppModule, vamos criar o OrdersModule, que irá gerenciar o nosso contexto de pedidos. Este módulo irá importar o OrdersController e o OrdersService:
import { Module } from '@nestjs/common';
import { OrdersService } from './application/orders.service';
import { OrdersController } from './infrastructure/orders.controller';
@Module({
imports: [],
controllers: [OrdersController],
providers: [OrdersService],
})
export class OrdersModule {}
O orderService retorna, por padrão, um getHello, que vem do NestJS. Vamos definir esse serviço agora:
import { Injectable } from '@nestjs/common';
@Injectable()
export class OrdersService {
getHello(): string {
return 'Hello World!';
}
}
Na infraestrutura, temos nosso controller com um teste que executa nosso serviço de pedidos também no método getHello. Vamos criar o OrdersController para lidar com as requisições HTTP:
import { Controller, Get } from '@nestjs/common';
import { OrdersService } from '../../application/orders.service';
@Controller('orders')
export class OrdersController {
constructor(private readonly ordersService: OrdersService) {}
@Get()
getHello(): string {
return this.ordersService.getHello();
}
}
Se acessarmos o terminal e executarmos npm start, iniciaremos nosso projeto. No console, veremos que ele será iniciado.
npm start
Uma novidade é que podemos usar a ferramenta api.http. Através da extensão REST Client, podemos procurar por ela nas extensões do VS Code, instalá-la e fazer requisições HTTP através desse arquivo. Funciona muito bem e é bastante útil. Podemos, por exemplo, clicar em sendRequest, que enviará uma ordem para nosso servidor. Veremos que a requisição foi enviada, com cabeçalhos e tudo mais, e recebemos um "Hello World".
Para testar nossa API, podemos usar o seguinte comando HTTP:
###
GET http://localhost:3000/orders
Essa é a estrutura inicial do nosso repositório. Não há segredos, é basicamente a aplicação padrão do NestJS com algumas modificações na pasta.
Gostaríamos de trazer um pouco do contexto deste projeto. No nosso projeto passado, no curso de DDD Estratégico, vimos o mapa de contextos. Nosso contexto de pedidos é um contexto central, muito importante, que se comunica com diversos outros contextos dentro do projeto Usedev. Decidimos trazer, neste projeto prático, a implementação desse contexto de pedidos. Vamos simular algumas interações com outros contextos delimitados, mas o principal foco será o contexto de pedidos.
Vamos modelar um carrinho de compras, um pedido, o pagamento e a integração com o contexto de precificação. Isso é o que veremos neste curso.
Voltando ao VS Code, temos nosso Readme. Recomendamos que o leia com atenção para entender como tudo funcionará, incluindo os comandos. É um projeto educacional em NestJS que demonstra os padrões práticos de DDD através do fluxo de gerenciamento de pedidos do e-commerce. Vamos cobrir desde a criação do carrinho, fechamento do pedido e pagamentos de forma simplificada. Não vamos integrar com gateways de pagamento, mas simular diversas interações para o aprendizado do DDD.
Teremos funcionalidades como criação do carrinho de compras, processamento do pagamento, eventos de domínio e consistência eventual com uma arquitetura orientada a eventos. Vamos cobrir técnicas como agregados, objetos de valor, entidades, repositórios, serviços de domínio e serviços de aplicação.
Falaremos sobre gateway, que é uma interface para simular ou isolar sistemas externos, e sobre a camada de corrupção. Também abordaremos outros contextos limitados, controlando as fronteiras com o padrão gateway e a camada de corrupção. Discutiremos eventos de domínio, message bus (camada de publicação de eventos) e arquitetura orientada a eventos de forma introdutória, pois teremos um curso específico sobre isso no futuro.
Este vídeo é uma introdução ao funcionamento do nosso repositório e ao projeto do curso. Em seguida, começaremos a implementação e colocaremos a mão na massa. Até já!
Vamos então colocar a mão na massa e começar a entender como criamos esses padrões táticos. No nosso VS Code, dado que trabalharemos com Domain Design (Design de Domínio), precisamos criar nossa camada de domínio.
Começamos pela pasta de contextos, onde temos nosso módulo e nosso contexto ilimitado de pedidos, orders. Temos aqui, primeiramente, nossa camada de aplicação e nossa camada de infraestrutura. Já possuímos nosso controller, que está chamando o serviço na camada de aplicação, mas ainda não temos nenhum comportamento de fato, apenas o básico que o Nest nos trouxe.
Vamos começar criando uma pasta de domínio, domain, e iniciar a codificação do nosso agregado de carrinho de compras. Vamos criar um arquivo shopping_cart.ts e discutir algumas ideias. Começaremos fazendo uma interface para discutir a relevância dos padrões táticos.
interface ShoppingCart {
}
Como as pessoas costumam fazer modelagens de sistemas em geral? A maior parte dos sistemas atuais não possui a camada de domínio, apenas uma camada de infraestrutura, onde a entidade está diretamente relacionada ao banco de dados. Por exemplo, nosso shopping cart (carrinho de compras) precisará de um identificador. Teremos um cartId, que será uma string.
interface ShoppingCart {
cartId: string;
}
Nosso carrinho também terá um dono, um cliente, ou um usuário ao qual ele pertencerá. Teremos, por exemplo, um customerId, também uma string.
interface ShoppingCart {
cartId: string;
customerId: string;
}
Além disso, teremos um status que representará em qual estágio do ciclo de vida o carrinho se encontra atualmente, também uma string.
interface ShoppingCart {
cartId: string;
customerId: string;
status: string;
}
Os itens do carrinho serão um array de objetos. Vamos definir um array de tipagem, onde teremos, por exemplo, o produtoId, que será uma string, e uma quantidade, quantity, que será um número.
interface ShoppingCart {
cartId: string;
customerId: string;
status: string;
items: Array<{
productId: string;
quantity: number;
}>
}
Assim, temos uma prototipagem básica de como seria essa camada de persistência, com esses campos e tipagens.
A diferenciação do Domain of Design (Design de Domínio) é que não tratamos de entidades apenas com dados, mas com entidades ricas. As entidades possuem comportamento, não apenas dados; não será apenas um getter e setter. Precisaremos incluir o comportamento do negócio. Na nossa interface, poderíamos incluir, por exemplo, métodos de negócio, como um método create para criar o carrinho.
interface ShoppingCart {
cartId: string;
customerId: string;
status: string;
items: Array<{
productId: string;
quantity: number;
}>;
create() {}
}
E outro método addItem para adicionar itens ao carrinho.
interface ShoppingCart {
cartId: string;
customerId: string;
status: string;
items: Array<{
productId: string;
quantity: number;
}>;
create() {}
addItem() {}
}
Nós poderíamos ter outro método aqui, getItem, onde receberíamos um parâmetro para retornar o item do nosso carrinho.
interface ShoppingCart {
cartId: string;
customerId: string;
status: string;
items: Array<{
productId: string;
quantity: number;
}>;
create() {}
addItem() {}
getItem() {}
}
Poderíamos ter, por exemplo, um método markAsConverted, para marcar que o nosso carrinho já foi convertido quando ele for transicionado para um pedido de fato.
interface ShoppingCart {
cartId: string;
customerId: string;
status: string;
items: Array<{
productId: string;
quantity: number;
}>;
create() {}
addItem() {}
getItem() {}
markAsConverted() {}
}
Tudo isso será modelado internamente no nosso agregado, na nossa entidade. Isso já funciona bem e ajuda bastante, mas também temos outros problemas.
Continuamos com tipos primitivos, como string e números na quantidade, além de um array de itens que também pode ter comportamento. Podemos, por exemplo, mudar a quantidade desses itens, adicionar um item novo ou remover um item. Seria ideal fazermos algumas modificações nessa entidade para adicionar outros padrões táticos do DDD.
Primeiramente, temos a questão dos objetos de valor. Podemos transformar nossos IDs, em vez de strings e tipos primitivos, em objetos de valor, para que tenham suas próprias regras e comportamentos. Por exemplo, nosso ID do carrinho pode ser implementado como um UUID, enquanto o ID de cliente pode ser uma string diferente, com um prefixo, em outro contexto ilimitado. Seria interessante termos objetos de valor que validem como esses IDs funcionam, como são gerados e como podemos compará-los ou realizar operações com eles.
E quanto aos status? Quais são os status válidos? Não pode ser qualquer coisa. Não é somente uma string; podemos ter um status como pendente ou convertido. Como modelamos isso? Nos nossos itens, seria ideal fazer uma transição para uma entidade própria, pois eles também terão um ciclo de vida. Teríamos um identificador do item do carrinho e métodos para alterar a quantidade, remover alguma quantidade, entre outros.
Com isso, começaríamos a ter uma modelagem mais rica, facilitando a modelagem do nosso carrinho como um todo, com os comportamentos dos outros padrões de DDD para nos ajudar. Tendo isso em mente, vamos começar a implementar os padrões de face do DDD, sabendo que uma modelagem anêmica não funciona e que uma modelagem muito orientada a primitivos também pode dificultar um pouco. No próximo vídeo, vamos começar a implementar nosso primeiro objeto de valor. Vamos juntos!
O curso DDD: aplicando padrões táticos possui 243 minutos de vídeos, em um total de 47 atividades. Gostou? Conheça nossos outros cursos de Node.JS em Programação, ou leia nossos artigos de Programação.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
2 anos de Alura
Matricule-se no plano PLUS 24 e garanta:
Jornada de estudos progressiva que te guia desde os fundamentos até a atuação prática. Você acompanha sua evolução, entende os próximos passos e se aprofunda nos conteúdos com quem é referência no mercado.
Mobile, Programação, Front-end, DevOps, UX & Design, Marketing Digital, Data Science, Inovação & Gestão, Inteligência Artificial
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você participa de eventos exclusivos, pode tirar dúvidas em estudos colaborativos e ainda conta com mentorias em grupo com especialistas de diversas áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
2 anos de Alura
Todos os benefícios do PLUS 24 e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Para estudantes ultra comprometidos atingirem seu objetivo mais rápido.
2 anos de Alura
Todos os benefícios do PRO 24 e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.
Conecte-se ao mercado com mentoria individual personalizada, vagas exclusivas e networking estratégico que impulsionam sua carreira tech para o próximo nível.