Giter Club home page Giter Club logo

backend-microservice-ddd-arch's Introduction

server

Projeto que se tornará grande de estudo com DDD, Clean Architecture, Microservice, TDD, SOLID e Design Patterns.

Resumo

A ideia de criar um projeto que se tornará grande com tempo com vários packages veio para praticar várias tecnologias, padrões e arquiteturas.

Cada package será um Microservice com possibilidade do mundo se conectar via REST, Mensageria (básico) e outros conforme for possível/priorizada implementação (GraphQL, gRPC, Kafka, HabbitMQ, SQS, SNS e etc).

Projeto a estrutura do projeto, pense que cada packages/<package> é um git submodule. Tanto que é possível rodar cada um via docker ou skaffold separadamente mas também todos de uma vez. Note os arquivos Makefile.

Instalações necessárias

Neste projeto terá como formas de execução via Docker, Kubernetes e yarn pode ser Node. Instale-os para continuar.

Instalação do Docker e Compose

Instale-os caso queira rodar o projeto via make docker_dev e outros comandos disponíveis nos Makefile.

Instalação do Kubernetes

Instale-o caso queira rodar o projeto via make k8s_dev e outros comandos disponíveis nos Makefile.

Instalação do K8S no Linux

# Instalação para Linux
cd /usr/local/bin
sudo curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256"
sudo chmod +x /usr/local/bin/kubectl
kubectl version --output=yaml

Instalação do Skaffold no Linux

cd ~
curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
sudo install skaffold /usr/local/bin/

Instalação do Kind no Linux

cd ~
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.14.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

Referências

Execução

É possível rodar o projeto via comandos presentes nos Makefile. Seja via arquivo presente no root ou de cada package.

O Makefile do root levanta todos de uma vez. O presente em cada package permite levantar um de cada vez.

  • A implementar: reverse proxy com Traefik.

Segue os principais comandos presente em qualquer Makefile:

# Necessário na primeira vez
make bootstrap
# Via docker
make docker_init
make docker_common_dev # sempre deve ser rodado num terminal paralelo
make docker_database_create # criar os databases para rodar as migrações
make docker_build
make docker_dev # deve ser rodado em outro terminal
make docker_stop
# Via kubernetes
make k8s_init
make k8s_common_dev # sempre deve ser rodado num terminal paralelo
make k8s_database_create # criar os databases para rodar as migrações
make k8s_dev # ou k8s_debug deve ser rodado em outro terminal
make k8s_stop # ele deleta os containers mas é assim mesmo que skaffold funciona
make k8s_run # apenas para deploy (não rodar local)
make k8s_env # se alterar algum .env precisa rodar esse comando para atualizar

Para testar tudo tem por exemplo esses links e portas abaixo.

curl http://localhost:3001/health # Aplicação auth básica
curl http://localhost:16543 # pgadmin

Testes

Apliquei um jeito dos testes de API e integração rodarem via Jest e via "memory repository".

Na prática isso significa que os testes não irão se conectar ao banco de dados permitindo que todos rodem em paralelo e numa velocidade máxima.

Deixei embutido em cada package com 100% de coverage os testes: API, integração e unitário.

Note os arquivos abaixo para entender melhor:

packages/<module>/jest.(api|integration|unit).js
packages/<module>/jest.setup.(api)?.js
packages/<module>/src/test/mocks/index.ts
packages/<module>/src/infra/factory/__mocks__/RepositoryFactory.ts

Pastas

Uma estrutura de pasta comum que encontrei e que mais tem funcionado em disparado no exemplo de Microservice é a seguinte:

├── application/       só pode importar domain
|   ├── handler/       normalmente usado nos controllers das mensageria
|   ├── usecase/       orquestradores que retornam DTO e que instanciam entidades para repositórios
|   ├── query/         camada de busca de dados para CQRS
|   ├── mutation/      camada de mutação de dados para CQRS
├── domain/            parte mais core e interna que possui implementações e interfaces
|   ├── entity/        POO e Value Objects com validações ao serem instanciados
|   ├── environment/   implementação das variáveis via env-var
|   ├── constant/      implementação de enum e constantantes
|   ├── error/         classes de erros
|   ├── event/         interface ligada ao type do evento da mensageria
|   ├── factory/       interfaces de boundery context das fábricas
|   ├── repository/    interface dos agregados e repositórios
|   ├── service/       funções ou classes com métodos estáticos que processam dados
├── infra/             camada de implementações superiores e infra
|   ├── controller/    controller de http, queue e etc
|   ├── container/     orquestração de containers
|   |   ├── docker/    orquestração de containers
|   |   ├── kubernate/ orquestração de containers
|   ├── database/      interface do Connection e implementação dos Adapters do banco
|   ├── environment/   carregamento das variáveis via dotenv
|   ├── factory/       implementação das fábricas
|   ├── http/          interface do Http e implementação dos Adapters dos presenters
|   ├── queue/         interface do Queue e implementação dos Adapters da Mensageria
|   ├── repository/    implementação dos repositórios
|   |   ├── database/  implementação dos repositórios de banco
|   |   ├── memory/    implementação dos repositórios de memória
├── presentation/      camada de apresentação dos frameworks
|   ├── presenter/     frameworks de primeiro contato com mundo
|   |   ├── express/   implementação da execução do framework
├── test/              camada dos testes
|   ├── api/           testes de api e rotas
|   ├── integration/   testes de integração em especial usecases
|   ├── mocks/         arquivos de mocks onde é ideal não usar tanto mas cada teste ter seu mock
|   ├── unit/          testes unitários exemplo os de domínio

Clean Architecture e Onion Architecture com DDD

Basicamente será utilizado os conceitos mais importantes do Clean Archicture tais como:

  • Layers;
  • couplings;
  • Boundary context;
  • Dependency rules.

Camadas, Dependency rules e Onion Architecture

Como Clean Architecture possui as camadas abaixo:

  • Frameworks & Drivers >
  • Interface Adapters >
  • Application Business Rules >
  • Enterprise Business Rules

Ao misturar com DDD e Onion Architecture fica uma excelente estrutura tal como:

  • Presentation >
  • Infra >
  • Application >
  • Domain >

Conceitos

  • Cada um pode importar os de baixo. Ex: Os arquivos de Presentation pode importar todos;
  • Em cada um de baixo não pode importar os de cima. Ex: Os arquivos de Domain só pode importar dele mesmo (outros domain).

Boundary context

Como domain não pode ter importações das demais camadas ele precisa desse conceito. Basicamente são Interfaces.

Note os arquivos abaixo para entender melhor.

packages/auth/src/domain/factory/RepositoryFactory.ts
packages/auth/src/domain/repository/UserRepository.ts

Esses arquivos possuem implementações da camada de infra e para não acoplar em domain as interfaces entram em cena.

DDD

Repository & Aggregates & CQRS

Repository do DDD é o meio de aplicar Aggregates. É possível ter Aggregate de 1 Repository e sobre uma tabela ou até mais.

Outro exemplo que Aggregates podem acabar tendo 1 Repository que nele tem uma query como abaixo que trás dados de outras tabelas.

Quando se quer separar as queries das mutations o conceito de CQRS pode ser aplicado na camada de application.

Exemplo:

  • packages/<module>/src/application/query/GetOrdersQuery.ts ou;
  • packages/<module>/src/application/mutation/SaveOrdersItems.ts;
import Connection from '../../infra/database/Connection'

export default class GetOrdersQuery {
  constructor(readonly connection: Connection) {}

  execute() {
    return this.connection.query(
      "select code, total, (select array_agg(json_build_object('description', i.description, 'price', oi.price)) from ccca.order_item oi join ccca.item i using (id_item) where oi.id_order = o.id_order) as items from ccca.order o",
      [],
    )
  }
}

Event Driven Architecture

As principais pastas com implementações sobre, são:

packages/<module>/application/handler/
packages/<module>/domain/event/
packages/<module>/infra/queue

Quando é o momento de aplicar o conceito e implementação?

Um exemplo é de quando notar que um usecase está quebrando o princípio SRP (Single Responsibility Principle) do SOLID.

Quando perceber que o usecase está fazendo algo que não é dele e que poderia delegar para um processamento posterior, é aí que aplicar this.queue.publish(orderPlaced) por exemplo será bem-vindo.

Obs: Lembrando que a nomenclatura será sempre do ponto de vista de algo que já aconteceu.

i18n

Foi aplicado no projeto pt-BR como padrão, mas é possível via header, cookie e na routa alterar a linguagem de tradução tal como en. Veja:

Exemplo via rota: ?lng=en.

Container

Nesse projeto estarei usando Kubernetes e Docker para desenvolver e deploys via algumas das ferramentas. Instale-as para usar, sendo:

Estudos

Após as instalações e caso esteja estudando K8S e Skaffold, muito provavelmente você passará pelos comandos abaixo.

kind create cluster # Primeiro levante o cluster do kind para skaffold fazer push da imagem do máquina local
kubectl get nodes # Veja se deu certo
skaffold init # Prepare o ambiente. Escolha: 1) Dockerfile 2) None 3) Enter
skaffold run # Irá buildar e rodar os containers. Se precisar rode novamente
kubectl get pod # Ver os pods
kubectl get svc # Ver os IPs e portas
kubectl get all # Ver todos os pods
kubectl port-forward svc/auth 3001:3001 # Expor a porta do container para sua máquina local
skaffold delete # Deletar o que foi executado na pipeline inicial
skaffold run --port-forward # Irá reconstruir a imagem exportando as portas dos containers para máquina local
skaffold dev --port-forward # Rodar em modo desenvolvimento para exibição dos logs
skaffold debug --port-forward # Rodar em modo desenvolvimento com debug
helm list # Se o Kubernetes executar com Helm este comando irá listar aquilo que ele está trabalhando
kubectl describe pod <container> # Pegue o nome do container em execução via kubectl get pod

Outros comandos úteis

kubectl create deploy products --image=server/auth --dry-run -o yml > auth-definition.yml

Execução via Docker e Compose e ferramentas

Instale-os caso queira rodar o projeto via make docker_dev e outros comandos disponíveis no Makefile.

Execução via Kubernetes e ferramentas

Tem alguns comandos pré disponíveis nos Makefile do root ou projeto.

make bootstrap
make k8s_init
make k8s_common_dev # sempre deve ser rodado num terminal
make k8s_database_create # criar os databases para rodar as migrações
make k8s_dev # ou k8s_debug deve ser rodado em outro terminal
make k8s_run # apenas para deploy (não rodar local)
make k8s_stop # ele deleta os containers mas é assim mesmo que skaffold funciona
make k8s_env # se alterar algum .env precisa rodar esse comando para atualizar

Comandos úteis

# Ver os containers e seus nomes
kubectl get pods
# Entrar num container
kubectl exec -it <container> -- sh
# Criar configmap a partir do .env
kubectl create configmap server-auth-env --from-env-file=src/infra/environment/.env
# Ver configmap criado
kubectl get configmap server-auth-env -o yaml
# Editar configmap no editar padrão
kubectl edit secrets <container>
# Ver variáveis de ambiente dentro do container
kubectl exec <container> -- printenv
# Para ver os logs
kubectl logs <container>
# Para ver os volumes persistidos
kubectl get pv
# Para ver os volumes
kubectl get pvc
# Ver o IP e Port em que os containers estão rodando
kubectl get endpoints
# Estando dentro do container conseguirá ver o ip interno e porta em execução
netstat -ln

Mais informações sobre volumes

# Para ter mais informações sobre os volumes configurados nos arquivos k8s/*.yml e etc
kubectl describe pvc server-pgadmin-claim
kubectl get pvc
kubectl describe pv pvc-<uuid>

Scale

kubectl scale deployment/server-auth --replicas=2;

Dashboard

Para ter o Dashboard do Kubernetes faça o seguinte:

# Configurar dashboard
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recommended.yaml
# Ver se kubernetes-dashboard está presente
kubectl get ns
# Ver se está rodando
kubectl -n kubernetes-dashboard get pods -o wide
# Ver outros dados como ip e porta
kubectl -n kubernetes-dashboard get svc
# Altere no final "type: ClusterIP" para "type: LoadBalancer"
kubectl -n kubernetes-dashboard edit svc kubernetes-dashboard
# Caso queira obter informacões do cluster
kubectl cluster-info
# Criar um proxy entre sua máquina e servidor de API do Kubernetes
kubectl proxy
# Acessar a rota abaixo
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login
# Pegar token para incluir na rota selecionando Token
kubectl -n kubernetes-dashboard create token admin-user
# Para acessos futuros pode acessar via link abaixo
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/workloads?namespace=default
# Se quiser alterar a porta (não recomendo)
kubectl port-forward -n kubernetes-dashboard service/kubernetes-dashboard 8080:443

Postgres

Comandos úteis sobre Postgres com Kubernetes.

# Ver os containers para achar o nome do container postgres
kubectl get pods
# Entrar no bash do container do postgres
kubectl exec -it deployment/server-postgres -- sh
# Dentro do container rode para acessar o postgres
psql
# Ou
kubectl exec -it deployment/server-postgres -- psql
# Ou fora do container e caso tenha psql instalado na sua máquina
psql -h localhost -p 5432 -U postgres -d <db>
# Exemplo de comando postgres para ver os databases
# Mais comandos: https://postgrescheatsheet.com
\l
# Entrar num database para rodar as queries
\c auth

Referências


Skaffold

É um gerador de pipeline de desenvolvimento contínuo com Kubernetes. Ele gera um boilerplate para facilitar você fazer deploys especificando qual ambiente gostaria tal como: local, homolog, production.


Kind

É uma solução para criação de Cluster Kubernetes baseado em Docker.


Helm

Gerenciador de pacotes para fazer setup de aplicações no Kubernetes.


Kubectl

Orquestração de containers.


Cloud Code

Instale a extensão para trabalhar com as ferramentas de Cloud do Google. Ele te ajuda a debugar no Kubernetes e possui intellisense para trabalhar com Skaffold.

backend-microservice-ddd-arch's People

Contributors

jefferson-william avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.