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

RubyConf BR 2019 - Domain Driven Rails

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

RubyConf BR 2019 - Domain Driven Rails

Esta talk fala sobre um case de sucesso em que conseguimos substituir uma abordagem rails-way usando MVC por uma solução mais elegante e expressiva para modelar o contexto de negócio usando apenas Ruby (sem dependências diretas de banco de dados) usando Domain Driven Design e uma arquitetura hexagonal.

Avatar for Gabriel Leopoldo Ferreira

Gabriel Leopoldo Ferreira

November 28, 2019

More Decks by Gabriel Leopoldo Ferreira

Other Decks in Technology

Transcript

  1. Refactoring no módulo de Antiphishing Novas telas de configurações do

    usuário Módulo de contabilização de crédito Dez 2018 Ago 2019 Nov 2019 Jun 2019
  2. Criando um e-mail Formulário Processamento Confirmação o formato de e-mail

    é válido o usuário tem permissão para criar e-mails o domínio selecionado é privado formato do e-mail e regra de unicidade respeitadas uma confirmação de e-mail deve ser exigida o usuário tem permissão para criar e-mails e-mail ainda existe na base e-mail de confirmação foi entregue com sucesso
  3. Criando um e-mail Formulário Processamento Confirmação a chamada para a

    API foi feita com sucesso o usuário clica duas vezes consecutivas no botão (sem loading) a API retorna um erro de validação um push para o Redis é feito somente após o COMMIT da transação a API retorna uma resposta em 200ms o link de confirmação pode ser acessado antes da TTL expirar o job retenta envios quando ocorrem erros temporários (ex. caixa cheia) o conteúdo retornado segue formato JSON
  4. APP 1 SHARD 1 SHARD II SHARD 1II SHARD 1V

    Account information Public metadata APP 1I
  5. APP 1 SHARD 1 SHARD II SHARD 1II SHARD 1V

    Account information Public metadata APP 1I EMKT CORE
  6. FRANKESTEIN OPERATION The user Rails + Vuejs hybrid app some

    vue components internal API API integration (lusing graphql) Server side rendering Shards access through emkt-core Sidekiq workers transactional side-effects and cumbersome processing
  7. FRANKESTEIN OPERATION The user Shards access through emkt-core Sidekiq workers

    transactional side-effects and cumbersome processing Rails + Vuejs hybrid app some vue components internal API API integration (lusing graphql) Server side rendering
  8. SPLIT AND CONQUER OPERATION + + The user Shards access

    through emkt-core Sidekiq workers transactional side-effects and cumbersome processing transactional side-effects and cumbersome processing
  9. MY ARCHITECTURE Customer panel Load balancer (reverse-proxy) Main database read

    as “master/slave’ ETL Layer Crunch data into human readable information “follow the line” layer TODO: make a backup’ why not?’ round robin
  10. “...we search for ways of increasing agility on the level

    of a larger data system, perhaps consisting of several different applications or services with different characteristics...” Kleppmann, Designing Data-Intensive Applications p.22
  11. View Layer - Web interface - JSON-API - GraphQL -

    Sidekiq / Queues Controller Layer - Services - Workers - Some business rules - Rails ecosystem Model Layer - Database validations - Data persistence - Data integrity Rails Layers
  12. View Layer - Web interface - JSON-API - GraphQL -

    Sidekiq / Queues Backend Layer - Services - Workers - Some business rules - Rails ecosystem Core Layer - Database models / shards - Data validation - More business rules Database Layer - Database validations - Data persistence - Data integrity Our architectural layers
  13. MVC Pattern (the rails way) the View layer the controller

    layer the model layer the database layer
  14. MVC Pattern (the rails way) the View layer the controller

    layer the model layer the database layer the Presenters layer
  15. MVC Pattern (the rails way) the View layer the controller

    layer the model layer the database layer the Presenters layer the Validators layer
  16. MVC Pattern (the rails way) the View layer the controller

    layer the model layer the database layer the Presenters layer the Validators layer the Services layer
  17. MVC Pattern (the rails way) the View layer the controller

    layer the model layer the database layer the Presenters layer the Validators layer the Services layer the Policy layer the Workers layer
  18. Linux (oversimplified view) top level interface S.O. internals (syscalls) hardware

    + drivers cat lsof tail curl ssh the most abstract && stable dependency direction dependency direction
  19. Linux (oversimplified view) S.O. internals (syscalls) hardware + drivers top

    level interface cat lsof tail curl ssh the most abstract && stable dependency direction dependency direction dependency direction custom shellscript
  20. Ports And Adapters BUSINESS RULES HTML View JSON View Database

    External API call Mailers GRAPHQL View most abstract && stable code
  21. Our new feature architecture Settings Senders Top-level use-case functions use-case

    functions Links domains Return-P ath use-case functions use-case functions P.O.R.O. data objects Repo abstract repository impl.
  22. Ports And Adapters Settings Module Senders Controllers Return-Path Controllers Links

    Controllers Database Repo Home Controller API Controller most abstract && stable code
  23. Settings::Sender Data Object Settings:: SenderActions Service Settings:: Repo Data persistence

    adapter Repo ActiveRecord implementation for Settings::Repo implements
  24. Settings::Sender Data Object Settings:: SenderActions Service Settings:: Repo Data persistence

    adapter Repo ActiveRecord implementation for Settings::Repo implements app specific details business rules domain Settings Connect both worlds
  25. Critical Path && Dependency inversion Redis queues database the user

    OLAP database user’s database read your own writes approach cron job to pull stuff from main DB cron job to pull stuff from main DB Most critical path
  26. Critical Path && Dependency inversion Redis queues database user’s database

    SELECT senders.id, senders.email FROM senders WHERE senders.state = ‘send_confirmation’ push bulk, just once redis hasn’t transaction statements cron-job running every minute, maybe
  27. Controlling dependencies Settings Module Dependencies: - - - - -

    - - - - - - - - ruby: 2.X.X 2.6.0 2.5.2 2.4.0 2.3.0 C.I. gitlab-ci / travis Rubocop Rubycritic
  28. Ports And Adapters Settings Module Customer API ETL Processor Metrics

    Generator Client/Server Integration Internal API Customer Panel most abstract && stable code 2.6.0 2.5.0 2.5.0 2.4.1 2.6.0 2.6.0 4.2.7 6.0.0 5.2.0 6.0.3 6.0.0
  29. Core Business Internal modules/classes Top-layer interface Repository Adapter Config. /

    Integration Layer Controller Layer Front-back integration Error handling View Layer JSON HTML Mobile
  30. Changing the storage layer Settings Senders Top-level use-case functions use-case

    functions Links domains Return-P ath use-case functions use-case functions Repo abstract repository impl. PG::Repo Neo4j::Repo Influx::Repo
  31. “... 20% of the input (time, resources, effort) accounts for

    80% of the output (results, rewards) ...” Pareto Principle