Skip to content

Instantly share code, notes, and snippets.

@marcelgsantos
Created March 23, 2018 00:56
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save marcelgsantos/f630cbc41c5109ee8ee03d7960c6fa65 to your computer and use it in GitHub Desktop.
Save marcelgsantos/f630cbc41c5109ee8ee03d7960c6fa65 to your computer and use it in GitHub Desktop.
  • Qual é o problema com a arquitetura das aplicações atuais?
  • Um projeto, na maioria das vezes, é começado pequeno, por uma pessoa e sem saber como será a sua evolução.
  • Pode acontecer de novas pessoas entrarem no projeto e não conhecerem as regras que guiam a aplicação.
  • Um dos princípios de organização é o MVC ou Model View Controller.
  • No MVC a regra de negócio fica na Model, os templates na View e a mediação é feita pelo Controller.
  • O MVC não é suficiente para manter uma aplicação com código compreensível durante muito tempo.
  • A ideia de utilizar MVC veio de frameworks e a maioria das aplicações estão acopladas de alguma maneira a frameworks.
  • Um projeto é iniciado normalmente (1) escolhendo um framework, (2) instalando um esqueleto, (3) removendo códigos de demonstração, (4) gerando entidades e controllers automaticamente e (5) tendo o código final.
  • Essa é uma abordagem outside-in e esse não é o diferencial da sua aplicação.
  • A parte interna de um problema é a parte mais interessante.
  • O teste da parte de fora é mais lento.
  • As bibliotecas e frameworks são responsáveis pelo encapsulamento das coisas.
  • O código que é altamente acoplado ao mecanismo de entrega.
  • Isso torna a reusabilidade do código impossível.
  • É impossível executar o código mais de uma vez.
  • Falta a intenção do código ser explicitada.
  • São vistos apenas dados passando através das camadas e não sabemos nem como e nem porquê.
  • Normalmente utilizamos como referência código da documentação como RAD e não temos a intenção.
  • O CRUD é útil em diversas ocasiões mas não em todas.
  • Alguns problemas são:
    • acoplamento ao framework
    • acoplamento ao mecanismo de entrega (por exemplo, a web)
    • testes lentos
    • falta de intenção do código
  • Devemos encontrar o que é a essência da nossa aplicação.
  • A essência de uma aplicação pode ser chamada de core da aplicação ou coração da aplicação.
  • O termo coração da aplicação nos remete ao livro Domain-Driven Design do Eric Evans.
    • "The heart of software is its ability to solve domain-related problems to its users."
    • "All other features, vital though they may be, support this basic purpose."
  • O que é importante para a sua aplicação é o seu modelo de domínio ou domain model e as interações que são feitas com ele e isso constitui as uses cases da sua aplicação.
  • O que não é importante é saber qual banco de dados ou framework utiliza.
  • O core domain não precisa conhecer nada do mundo externo. Não importa se quem o chama é uma pessoa ou uma máquina.
  • A camada existente entre a aplicação (core domain) e o mundo externo é a camada de infra-estrutura.
  • Na camada de infra-estrutura existirá código responsável pela comunicação da aplicação com o mundo externo como a web, linha de comando, sistema de arquivo, sistema de filas, banco de dados ou envio de e-mail.
  • Uma camada é responsável pela separação de coisas.
  • Existem regras para cruzar uma camada como a comunicação só pode se dar em uma direção.
  • Uma camada possui limites.
  • Artigo Screaming Architecture do Robert Martin.
  • Uma arquitetura limpa é relacionada a uma arquitetura hexagonal.
  • Robert Martin propôs que caso haja dependências entre camadas que elas sejam das camadas mais externas para as camadas mais internas ou nas mesmas camadas.
  • O que cruza os limites das camadas são as mensagens ou chamadas de métodos.
  • As chamadas de métodos ou funções juntamente com seus argumentos são mensagens enviadas.
  • Os argumentos de métodos ou funções podem ser encapsulados em um objeto para serem enviados nas mensagens.
  • Uma aplicação permite o envio de mensagens ao expor as portas de entrada ou input ports. Por exemplo, rotas web, CLI ou REST API.
  • Cada lado do hexágono representa uma porta de entrada.
  • A motivo de ser um hexágono é qua a maioria das aplicações têm em média 6 portas de entrada.
  • Cada porta utiliza um protocolo de comunicação. Por exemplo, a porta web fala utilizando HTTP e a porta de mensagem fala utilizando AMQP.
  • Uma requisição HTTP é traduzida (utilizando Controllers, Requests e Forms) para conversar com a aplicação internamente (Entities, Value Objects e Repositories).
  • O processo de tradução de uma requisição HTTP para algo que possa ser utilizado pelo core domain é chamado de adapters. conjunto de código
  • Não confundir com o padrão de projeto Adapter.
  • Ports and Adapters é um alias para Hexagonal Architecture e foi inventado pelo Alistair Cockburn.
  • O artigo original sobre arquitetura hexagonal pode ser encontrada aqui.
  • As portas permitem que a comunicação aconteça.
  • Pensando na aplicação como um objeto (com a sua lógica interna escondida) as portas permitem que pessoas e sistemas se comuniquem com ela.
  • Para cada porta existe um adapter.
  • Os adapters são responsáveis por traduzir mensagens do mundo externo para algo que seja compreensível dentro da aplicação.
  • Um comando é criado a partir de uma requisição HTTP para representar a intenção de um usuário.
  • Um comando é um objeto auto-contido que não se trata mais de web, de objetos de requisição ou objetos de formulário.
  • É uma ótima ideia criar um comando a partir de uma requisição web pois se deixa clara a intenção do usuário.
  • Evita-se que a intenção do usuário seja perdida ao copiar os dados entre as camadas.
  • As principais características de um comando são:
    1. expressar a intenção desejada
    2. implicar em mudanças
      • diz que algo deve acontecer na aplicação
    3. independente de mecanismo de entrega
      • pode ser via web ou console
    4. tratar-se apenas de uma mensagem
      • não é capaz de fazer nenhuma alteração por si só
      • é passado para uma parte da aplicação capaz de fazer algo
  • Um command handler é a parte da aplicação responsável pela manipulação de um comando.
  • Um command handler pode ser chamado RegisterPatientHandler e aceitar um comando chamado RegisterPatient.
  • Um command bus pode ser utilizado para distribuir os comandos para seus respectivos handlers.
  • Pode-se utilizar alguma biblioteca para command bus como SimpleBus ou Tactician.
  • Recebe-se uma requisição HTTP através da porta web. A requisição HTTP passará pelas camadas de infraestrutura, aplicação até chegar na camada de domínio.
  • A camada de infraestrutura contém tudo o que é necessário para traduzir a requisição HTTP para algo compreensível pela aplicação. Por exemplo, objetos de Request, Controller e Form.
  • A camada de aplicação contém tudo o que é necessário para realizar ações. Por exemplo, objetos de command e command handler.
  • A camada de domínio contém o domínio da aplicação como entidades e repositórios.
  • Uma entidade, que está na camada de domínio, utiliza um entity manager, que está na camada de infraestrutura, para realizar a persistência utilizando a porta de persistência.
  • O problema é que uma uma camada interna não pode depender de uma camada externa.
  • Para solucionar esse problema utiliza-se o princípio de inversão de dependência.
  • Nesse caso, define-se o repositório como uma interface na camada de domínio e faça a implementação na camada de infraestrutura depender dela.
  • Uma vantagem da utilização dessa abordagem é utilizar uma implementação para testes de banco de dados em memória.
  • "A good software architecture allows decisions [...] to be defererd and delayed." por Robert Martin em Screaming Architecture.
  • A arquitetura hexagonal permite uma melhor separação de responsabilidade com as camadas de core (domínio e aplicação) e infraestrutura.
  • Alguns projetos podem separar os códigos em diretórios de domínio, aplicação e infraestrutura.
  • Códigos que se encontram em controllers podem ser movidos para os command handlers.
  • A arquitetura hexagonal dá suporte para ideias como DDD, TDD, BDD, CQRS e event sourcing.

Referências

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment