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

De Rails à Phoenix - retour d'expérience sur une réécriture d'application SaaS

De Rails à Phoenix - retour d'expérience sur une réécriture d'application SaaS

Thibaut Barrère

July 12, 2016
Tweet

More Decks by Thibaut Barrère

Other Decks in Programming

Transcript

  1. Rails -> Phoenix
    Retour d'expérience sur une
    rewrite (en cours) d'application SaaS.
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  2. Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  3. Pourquoi une rewrite?
    4 Elixir flaggé "stratégique" sur mon radar tech !
    4 Produits SaaS et applications internes (dev solo)
    4 Consulting (scalabilité, ETL, ...)
    4 Robotique, IoT, ETL, Streaming.
    4 Rewrite = apprentissage & comparaison
    4 Comparaison des écosystèmes
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  4. Rewrite "side-by-side"
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  5. Comment débuter
    4 "Programming Elixir" de A à Z
    4 Koans (http://github.com/thbar/elixir-playground)
    test "function declaration and invocation" do
    sum = fn (a, b) -> a + b end
    assert sum.(2, 10) == 12
    tuple_sum = fn { a, b, c, d } -> a + b + c + d end
    assert tuple_sum.({ 10, 100, 1000, 10000 }) == 11110
    end
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  6. Frictions
    4 Vendor lock-in Ruby:
    4 Productivité très forte.
    4 Ecosystème très mûr et large.
    4 Zone de confort énorme.
    4 Accepter d'être lent au début.
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  7. Motivations
    4 Faire plus avec moins de personnes.
    4 Scaler plus fort avec moins de machines.
    4 Aller vers l'internet des choses, le streaming, le flux
    continu de données, le très scalable, le redondant.
    4 Même "bon feeling" qu'avec Rails en 2005.
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  8. T.B.D.D.D.D
    Tests & base de données driven-development
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  9. Exporter une base de dév depuis Rails
    $ rake db:seed
    $ pg_dump -O -x wisecash_dev -f legacy-dumps/rails-db-seed.sql
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  10. Importer la base Rails vers Ecto
    $ ecto.load --dump-path legacy-dumps/rails-db-seed.sql
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  11. Importer la base Rails vers Ecto,
    automatiquement, avant les tests
    defp aliases do
    [
    "test": [
    "ecto.create --quiet",
    "ecto.load --dump-path legacy-dumps/rails-db-seed.sql",
    "test"
    ]
    ]
    end
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  12. Continuous integration ❤
    (quelques heures pour la mise en place initiale sur CircleCI)
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  13. Se mettre à l'aise pour expérimenter
    4 Feedback-loop rapide avec mix_test_watch
    4 Tests "exploratoires"
    4 Colorisation de l'output avec apex
    defp deps do
    [
    {:mix_test_watch, "~> 0.2", only: :dev},
    {:apex, "~> 0.4.0", only: [:dev, :test]}
    ]
    end
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  14. Zoomer sur un problème à la fois
    ExUnit.configure(
    exclude: :test,
    include: :focus,
    ...
    )
    @tag :focus
    def test_this do
    # snip
    end
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  15. Débugger une dépendance facilement
    $ atom deps/openmaize_jwt/lib
    config :mix_test_watch,
    [
    "deps.compile openmaize_jwt",
    "test"
    ]
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  16. Adaptations Ecto ActiveRecord
    schema "entries" do
    timestamps inserted_at: :created_at
    end
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  17. Evènements récurrents
    Plusieurs tentatives:
    1. Postgres generate_series (ne colle pas au besoin) !
    2. Fonction PL/pgSQL (des contournements à faire) "
    3. Fonction Elixir (terminée en quelques heures) #
    Merci Timex.shift
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  18. Queries SQL sur des fonctions (avec Ecto 2)
    Logger.configure(level: :debug)
    Ecto.Adapters.SQL.query!(WisecashEx.Repo, query, [from, to])
    def postgres_setup!(repo) do
    source = File.read!(query_file("generate_recurring_events.sql"))
    Ecto.Adapters.SQL.query!(repo, source, [])
    end
    4 Ecto = plus limité que Sequel en Ruby
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  19. Authentification
    Choix large (comme avec Rails en 2005):
    4 Guardian (pas de gestion de BDD, JWT)
    4 Openmaize (BDD, code généré, JWT) !
    4 Addict
    4 ...
    Mais quelle solution sera réellement pérenne ???
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  20. Adaptation du schéma de Rails & Devise vers Openmaize
    schema "users" do
    field :email, :string
    field :encrypted_password, :string
    field :password, :string, virtual: true
    field :role, :string, virtual: true, default: "user"
    timestamps inserted_at: :created_at
    end
    config :openmaize, hash_name: :encrypted_password
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  21. Openmaize dans le contrôleur
    plug Openmaize.Login, [
    db_module: WisecashEx.OpenmaizeEcto,
    unique_id: :email
    ] when action in [:login_user]
    Reprise en main du code généré par Openmaize.
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  22. Tests d'acceptance (hound + phantomjs ❤)
    navigate_to("/")
    "/" = current_path
    find_element(:link_text, "Login")
    |> click
    "/login" = current_path
    find_element(:id, "user_email")
    |> fill_field("[email protected]")
    ``
    find_element(:id, "user_password")
    |> fill_field("testtest")
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  23. Tests d'acceptance (hound + phantomjs ❤)
    find_element(:tag, "form")
    |> submit_element
    assert visible_page_text =~ ~r/Logged as [email protected]/i
    find_element(:link_text, "Logout")
    |> click
    assert visible_page_text =~ ~r/You have been logged out/i
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  24. Déploiement
    4 Heroku: build-pack fonctionnel rapidement
    4 EngineYard: custom cookbooks, pas horrible
    4 Pas de hot-reloading pour le moment
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide

  25. Mes conclusions pour le moment
    4 Données immutables = fondation solide
    4 Effets de 2nd ordre (levier, composabilité)
    4 TDD = aide beaucoup pour prendre en main
    4 Librairies jeunes (perte de temps - maintenance)
    4 Confort très similaire à Ruby en régime de croisière
    4 Moins de "compromis duct-tape" qu'avec Ruby
    Thibaut Barrère ([email protected]) - juillet 2016

    View Slide