Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hexagonal Rails

Hexagonal Rails

A proposta dessa apresentação é mostrar uma alternativa para a construção de aplicações com Ruby on Rails que dão ênfase à modelagem de domínio, separando o código que resolve o problema de negócio do código do framework.

Luiz Costa

March 25, 2021
Tweet

More Decks by Luiz Costa

Other Decks in Programming

Transcript

  1. Levar as melhores experiências em serviços de saúde para todo

    o Brasil. Temos vagas! beepsaude.gupy.io
  2. Components within the layered architecture pattern are organized into horizontal

    layers, each layer performing a specific role within the application (e.g., presentation logic or business logic). Software Architecture Patterns, Mark Richards https://www.oreilly.com/library/view/software-architecture-patterns/9781491971437/
  3. Na versão mais “restrita” deste pattern, as camadas superiores só

    acessam as inferiores passando pela camada seguinte.
  4. Existem algumas variações, por exemplo, algumas camadas podem acessar diretamente

    outras camadas sem passar pela seguinte. Neste caso se diz que existem camadas “abertas”.
  5. Hexagonal Architecture, Alistair Cockburn https://bit.ly/2XBQHNx Allow an application to equally

    be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run- time devices and databases.
  6. Ports and Adapters Architecture, Alistair Cockburn http://wiki.c2.com/?PortsAndAdaptersArchitecture Each face of

    the hexagon (port) represents some "reason" the application is trying to talk with the outside world. Events arrive from the outside world at a port. The adapter converts it into a usable procedure call or message and passes it to the application. The application is blissfully ignorant of the nature of the input device…
  7. Ports and Adapters Architecture, Alistair Cockburn http://wiki.c2.com/?PortsAndAdaptersArchitecture Each face of

    the hexagon (port) represents some "reason" the application is trying to talk with the outside world. Events arrive from the outside world at a port. The adapter converts it into a usable procedure call or message and passes it to the application. The application is blissfully ignorant of the nature of the input device…
  8. uma aplicação pode ter várias portas e isso não se

    limita ao número de lados do hexágono O adaptador converte a mensagem e delega para os objetos de domínio
  9. Screaming Architecture, Robert Martin https://blog.cleancoder.com/uncle-bob/2011/09/30Screaming-Architecture.html Architectures are not (or should

    not) be about frameworks. Architectures should not be supplied by frameworks. Frameworks are tools to be used, not architectures to be conformed to. If you architecture is based on frameworks, then it cannot be based on your use cases.
  10. Screaming Architecture, Robert Martin https://blog.cleancoder.com/uncle-bob/2011/09/30Screaming-Architecture.html Architectures are not (or should

    not) be about frameworks. Architectures should not be supplied by frameworks. Frameworks are tools to be used, not architectures to be conformed to. If you architecture is based on frameworks, then it cannot be based on your use cases.
  11. Screaming Architecture, Robert Martin https://blog.cleancoder.com/uncle-bob/2011/09/30Screaming-Architecture.html Your architectures should tell readers

    about the system, not about the frameworks you used in your system. If you are building a health-care system, then when new programmers look at the source repository, their first impression should be: “Oh, this is a heath-care system”.
  12. the web is a delivery mechanism Architecture the lost years,

    Robert Martin https://youtu.be/WpkDN78P884?t=581
  13. O código de negócio fica dentro da pasta application. Dentro

    da desta pasta, todo acesso ao framework é feito por adaptadores.
  14. Código da aplicação web, escrita em rails fica dentro de

    web app. Esta pasta é a implementação de um delivery mechanism. O código negócio, que vive dentro de application, é acessado através de portas.
  15. Paciente Atendimento + qual nome, nascimento…? + qual dia do

    agendamento? + qual endereço de atendimento? Paciente Vacinação + como a caderneta de vacinação está organizada? + qual a próxima vacina? + qual vacina foi aplicada? Paciente Financeiro + qual custo das vacinas aplicadas? + alguma condição de desconto? + qual meio de pagamento utilizado? É responsabilidade de cada contexto modelar os dados da melhor maneira, de acordo com a as suas responsabilidades.
  16. implementação de um use case o fluxo de execução é

    simples e limpo As dependências são injetadas no construtor Usa um factory method* para manter o encapsulamento e diminuir o acoplamento com o objeto cliente * https://en.wikipedia.org/wiki/Factory_method_pattern application/src
  17. conectando a web app com o application Aqui o factory

    method é usado para instanciar o use case. A interface pública do use case é usada como Port para acessar o código da application * https://en.wikipedia.org/wiki/Factory_method_pattern web-app/app/controllers
  18. objetos de domínio são escritos em código ruby puro (PORO*)

    Não existe nenhuma relação direta com o Active Record *http://blog.jayfields.com/2007/10/ruby-poro.html
  19. Nas implementações padrão do rails, o model é uma subclasse

    de ApplicationRecord, isso faz com que o acoplamento com o banco de dados seja bem alto.
  20. O domain object é separado do model e o seu

    ciclo de vida é controlado por um Repositório*. O repositório é responsável por executar as consultas (queries), e mapear os objetos de domínio. Para isso pode ter a colaboração de uma Factory*. O model tem a responsabilidade garantir a consistência dos dados, de acordo com o modelo relacional. Pode definir algumas queries e ter validações de dados O domain object é quem tem a implementação das lógicas de negócio. *https://martinfowler.com/eaaCatalog/repository.html
  21. Um único Model pode dar origem a um modelo de

    domínio bem mais complexo. Neste caso, todos os dados do domain model são persistidos na mesma tabela (model) do banco de dados.
  22. Aqui o model é usado para tirar vantagem do Active

    Record. Uma factory é usada para fazer a construção do objeto de domínio. .active_nurses é uma query que está encapsulada no Model. O save também delega para o Active Record. implementação de um repositório
  23. para uma proposta de implementação O controlador acessa os módulos

    através de uma porta que expõe a interface pública de um caso de uso. A implementação do caso de uso, atua como uma adaptador. O repositório encapsula o acesso aos models, funcionando como mais um adaptador.
  24. para uma proposta de implementação O controlador acessa os módulos

    através de uma porta que expõe a interface pública de um caso de uso. A implementação do caso de uso, atua como uma adaptador. O repositório encapsula o acesso aos models, funcionando como mais um adaptador. Outside Inside Outside
  25. Deve permitir o paciente agendar a aplicação de vacina. Ao

    fazer o agendamento deve-se efetuar o pagamento e reservar o estoque dos produtos agendados.
  26. Deve permitir o paciente agendar a aplicação de vacina. Ao

    fazer o agendamento deve-se efetuar o pagamento e reservar o estoque dos produtos agendados.
  27. O ideal é que um contexto só exponha objetos de

    fronteira. Ex: Use Cases, Services ou Repositories Se precisar retornar um conjunto de dados mais complexo, dê preferência para Hashs ou Tuplas Mantenha o domain model protegido dentro do contexto. O ideal é não deixar “vazar" do contexto os objetos de domínio
  28. 1.

  29. Gestão de Agendas Pagamentos Neste caso os contextos se falam

    através dos objetos de fronteira: Services e Casos de Uso
  30. construa uma arquitetura que te permita atrasar as decisões https:/

    /8thlight.com/blog/uncle-bob/2011/11/22/Clean-Architecture.html
  31. 2.

  32. Gestão De Agendas Gestão de Estoque Os dois contextos se

    falam através de um domain event AgendamentoCriado
  33. Contexto de pagamento como microsserviço O único ponto de contato

    com o contexto de pagamento no agendamento, era o objeto de fronteira Pagamento. Este objeto vai precisar ser alterado, e ao invés de chamar o contexto diretamente, vamos introduzir uma service layer para implementar a chamada remota ao microserviço de pagamento O contexto de pagamento foi extraído e adicionado em uma nova aplicação rails. Foi necessário expor uma api para disponibilizar o acesso aos casos de uso. Neste caso, provavelmente os respositórios deverão ser alterados para conectar no banco de dados diferente.
  34. O único ponto de contato com o contexto de pagamento

    no agendamento, era o objeto de fronteira Pagamento. Este objeto vai precisar ser alterado, e ao invés de chamar o contexto diretamente, vamos introduzir uma service layer para implementar a chamada remota ao microserviço de pagamento O contexto de pagamento foi extraído e adicionado em uma nova aplicação rails. Foi necessário expor uma api para disponibilizar o acesso aos casos de usos. Neste caso, provavelmente os respositórios deverão ser alterados para conectar no banco de dados diferente. Contexto de pagamento como microsserviço
  35. Como extrair o contexto de Gestão de Estoque? Como lidar

    com o Domain Event AgendamentoCriado?
  36. Contexto de estoque como microsserviço O contexto de agendamento continua

    publicando o domain event AgendamentoCriado da mesma forma que antes, nada muda aqui. O Event Handler original é substituído por outro que public o evento em um Broker de mensagem. Ex: RabbitMQ, Kafka, ActveMQ No microserviço de estoque, é necessário adicionar na ACL, handlers que serão estimulados pelas mensagens entregues pelo broker. Estes handlers, delegam a execução para os caso de uso.
  37. Contexto de estoque como microsserviço O contexto de agendamento continua

    publicando o domain event AgendamentoCriado da mesma forma que antes, nada muda aqui. O Event Handler original é substituído por outro que public o evento em um Broker de mensagem. Ex: RabbitMQ, Kafka, ActveMQ No microserviço de estoque, é necessário adicionar na ACL, handlers que serão estimulados pelas mensagens entregues pelo broker. Estes handlers, delegam a execução para os caso de uso.