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

The pillars of integration

The pillars of integration

Rodrigo Boniatti

December 07, 2018
Tweet

More Decks by Rodrigo Boniatti

Other Decks in Programming

Transcript

  1. The pillars of
    integration

    View Slide

  2. Rodrigo Boniatti
    Developer at Codeminer 42
    @boniattirodrigo
    rodrigoboniatti.com

    View Slide

  3. View Slide

  4. Communication issues

    View Slide

  5. In tech it’s not
    different

    View Slide

  6. View Slide

  7. • Ugly design;
    • Unsafe;
    • Hard to use and test;
    • Bad documented;

    View Slide

  8. View Slide

  9. How can we improve
    our communication?

    View Slide

  10. Architecture

    View Slide

  11. View Slide

  12. View Slide

  13. Hexagonal architecture

    View Slide

  14. Design patterns

    View Slide

  15. Adapter

    View Slide

  16. // Brazilian supplier
    product = {
    nome: 'Sofá 3 lugares',
    preco: 1450,
    quantidade: 1
    }
    // German supplier
    product = {
    name: 'Stuhl',
    preis: 200,
    menge: 1
    }

    View Slide

  17. class BrazillianProductAdapter < ActiveModel::Serializer
    attributes :name, :price, :quantity
    def name
    object[:nome]
    end
    def price
    object[:preco]
    end
    def quantity
    object[:quantidade]
    end
    end

    View Slide

  18. product = {
    nome: 'Sofá 3 lugares',
    preco: 1450,
    quantidade: 1
    }
    BrazillianProductAdapter.new(product).as_json
    {:name=>"Sofá 3 lugares", :price=>1450, :quantity=>1}

    View Slide

  19. View Slide

  20. Strategy

    View Slide

  21. class Product < ApplicationRecord
    validates :name, :price, :quantity, :partner, presence: true
    end

    View Slide

  22. class EcommerceA::TrackProductAccess
    def self.call(id)
    end
    end
    class EcommerceB::TrackProductAccess
    def self.call(id)
    end
    end
    class EcommerceC::TrackProductAccess
    def self.call(id)
    end
    end

    View Slide

  23. class TrackProductAccess
    def self.call(product)
    case product.partner
    when 'EcommerceA'
    EcommerceA::TrackProductAccess.call(product.id)
    when 'EcommerceB'
    EcommerceB::TrackProductAccess.call(product.id)
    when 'EcommerceC'
    EcommerceC::TrackProductAccess.call(product.id)
    else
    puts 'Partner not found'
    end
    end
    end
    Smell

    View Slide

  24. View Slide

  25. class TrackProductAccess
    class << self
    def call(partner, product_id)
    partner_module = partner.constantize
    partner_module::TrackProductAccess.call(product_id)
    end
    end
    end
    Refactored

    View Slide

  26. class TrackProductAccess
    class << self
    def call(partner, product_id)
    partner_module = partner.constantize
    partner_module::TrackProductAccess.call(product_id)
    end
    end
    end
    Dependency Injection
    Refactored

    View Slide

  27. class TrackProductAccess
    class << self
    def call(partner, product_id)
    partner_module = partner.constantize
    partner_module::TrackProductAccess.call(product_id)
    end
    end
    end
    Inversion of Control
    Dependency Injection
    Refactored

    View Slide

  28. View Slide

  29. Partners configuration
    could be saved in a
    YML file

    View Slide

  30. module Ecommerce
    class TrackProductAccess
    def self.call(product_id)
    self.new(product_id).track
    end
    def track
    EcommerceHttpClient.post do |req|
    req.url "/track_user/#{@product_id}"
    req.body = configurations
    end
    end
    private
    def initialize(product_id)
    @product_id = product_id
    end
    def configurations
    {
    version: 3,
    port: 5500,
    security: true,
    anonymous_user: false,
    cors_enable: true
    }
    end
    end
    end

    View Slide

  31. Better
    class TrackProductAccess
    def self.call(product_id, config = YAML.load_file('ecommerce_config.yml'))
    self.new(product_id, config).track
    end
    def track
    EcommerceHttpClient.post do |req|
    req.url "/track_user/#{@product_id}"
    req.body = @config
    end
    end
    private
    def initialize(product_id, config)
    @product_id = product_id
    @config = config
    end
    end

    View Slide

  32. Avoid hardcoded
    partners name

    View Slide

  33. Smell
    class Order < ApplicationRecord
    validates :stripe_status, presence: true
    validates :aws_s3_invoice_url, format: { with: URI.regexp }
    end

    View Slide

  34. Better
    class Order < ApplicationRecord
    validates :payment_status, presence: true
    validates :invoice_url, format: { with: URI.regexp }
    end

    View Slide

  35. Message broker

    View Slide

  36. View Slide

  37. https://github.com/mperham/sidekiq/wiki/Problems-and-
    Troubleshooting#my-sidekiq-process-is-crashing-what-do-i-do

    View Slide

  38. View Slide

  39. Advantages
    • Persistence;
    • Fault Resilience;
    • Delivery acknowledgements;
    • AMQP protocol;

    View Slide

  40. Error tracking

    View Slide

  41. View Slide

  42. View Slide

  43. Specs

    View Slide

  44. VCR
    • Cache your partners’ response;
    • Know when responses have changed;
    • Easy mock.

    View Slide

  45. What should we test
    in our partners?

    View Slide

  46. GraphQL

    View Slide

  47. GraphQL
    • Avoid chaining requests;
    • Documentation;
    • Single request for many resources.

    View Slide

  48. Webhooks

    View Slide

  49. Webhooks
    • Just call your API when something occurs;
    • Easy to setup;
    • Stop requests every X minutes.

    View Slide

  50. What should we test in our partners?
    • API Rate Limit;
    • Documentation;
    • GraphQL;
    • Webhooks.

    View Slide

  51. Have some response
    backups

    View Slide

  52. Your software dictates
    the rules

    View Slide

  53. View Slide

  54. Great developers think
    how others will use
    their tools

    View Slide

  55. Questions?

    View Slide

  56. Thanks ;)

    View Slide