Embrace multi-model thinking!

Embrace multi-model thinking!

F9c1a378a1e3926ea1a58cf724140000?s=128

Ivan Nemytchenko

April 29, 2019
Tweet

Transcript

  1. Embrace multi- model thinking! Ivan Nemytchenko, @inem, 2019

  2. • Consulting • Exploring apps architecture • Writing book •

    Teaching at Goodprogrammer.ru • Gitlabbing • Travelling Ivan Nemytchenko Omsk → Belgrade @inem http://inem.at
  3. Rubytrip! 40 days, 4 conferences, 8 countries + 1 meetup!

    - RubyConfBY Minsk - April 6 - RubyDay Verona - April 11 - RubyWine Kishinev - April 13 - RubyMN - April 29 - RailsConf Minneapolis - April 30 - Saint P RubyConf - June 1-2 railshurts.com/rubytrip
  4. railshurts.com/lifecycle

  5. None
  6. None
  7. None
  8. None
  9. None
  10. None
  11. None
  12. None
  13. What’s missing?

  14. Embrace multi- model thinking!

  15. ?

  16. OOP? Design patterns? SOLID? Functional Programming? DDD? 7 ways to

    refactor fat models … What should we take into account? Well…
  17. What should we take into account? Interaction with external world

    Applications vs libraries Layered architecture Levels of abstractions REST Domain Driven Design 12 factors Imperative vs Declarative Functional approach Side effects State management Types Polymorphism System thinking
  18. State

  19. 1.Invited 2.Registered 6.Deleted 3.Banned 5.Expired 4.Promoted User

  20. 1.Invited 2.Registered 6.Deleted 3.Banned 5.Expired 4.Promoted User Invoice 1.Created 2.Sent

    3.Delivered 4.Paid 5.Expired Task 1.Created 2.Assigned 3.Sheduled 4.Completed 5.Archived
  21. The natural way to implement states

  22. - if current_organisation_subscribed? %p You are currently subscribed, using the

    following payment method: %p== #{@org.card_brand}: **** **** **** #{@org.card_last4} %p== Expires #{@org.card_exp_month} / #{@org.card_exp_year} - if @org.last_charge %p== The last payment of $#{@org.last_charge.amount/100} was taken on #{@org.last_charge.created_at.strftime("%d %b % %p== The next payment of $100 is due to be taken on #{(@org.last_charge.created_at + 1.month).strftime("%d %b %Y")} = link_to "Update credit card", edit_subscription_path, class: "btn btn-primary" %p = link_to "Cancel my subscription", subscription_path, method: "DELETE", class: "btn btn-danger", data: {confirm: 'Ar sure?'} - else - if @org.trial_ended? %h2 Thank you for trialing our product %h4 To continue using our product please subscribe to the following plan: - else %h2== Thank you for trialing our product (#{distance_of_time_in_words(@org.created_at, Time.zone.now)} left) %h4 To continue using our product after trial please subscribe to the following plan: %p $100/month %p Up to 500 devices and 200 users %p 3 admin users %p CSV/XLS upload = link_to "Subscribe", new_subscription_path, class: 'btn btn-primary'
  23. - if current_organisation_subscribed? #... - if @org.last_charge #... - elsif

    @org.last_charge_status != 'success' #... #... - if @org.expires_at #... - else - if @org.trial_ended? #... - else #... #...
  24. if current_user.active && current_user.account && !current_user.account.deleted && current_org.trial_ends_at > Time.current

  25. Every flag doubles the number of states .trial_ended? .expired? .cancelled?

    .subscription_expired? 4 flags = 16 states!
  26. Flags can be hidden dates ranges, associations, status fields -

    if current_organisation_subscribed? #... - if @org.last_charge #... - elsif @org.last_charge_status != 'success' #... #... - if @org.expires_at #... - else - if @org.trial_ended? #... - else #... #...
  27. State Machines

  28. State Machines

  29. State Machines

  30. State Machines

  31. gem ‘aasm’ gem ‘state-machines’

  32. state_machine :state, initial: :trial do state :trial state :trial_ended state

    :subscribed state :cancelled_subscription state :not_subscribed state :payment_error event :subscribe do transition [:trial, :not_subscribed, :trial_ended] => :subscribed end event :disable_trial do transition :trial => :trial_ended end event :usage_period_ended do transition :cancelled_subscription => :not_subscribed end #... end
  33. - if current_org.trial? #... - elsif current_org.trial_ended? #... - elsif

    current_org.subscribed? #... - elsif current_org.cancelled_subscription? #... - elsif current_org.payment_error? #... - elsif current_org.not_subscribed? #... render partial: current_org.state
  34. def something(org) if org.new_record? # ... 16*2 = 32 states!

  35. Control the number of degrees of freedom of your app

  36. Painless Rails principles 1.Differentiate 'schema' from 'implementation' 2.Reduce entry point

    pressure 3.Control the number of degrees of freedom of the app 4.Don't mix layers of abstractions 5.Don't fight against the framework railshurts.com/rails-principles
  37. Sources SICP (Structure and Interpretation of Computer Programs) TAPL (Types

    and Programming Languages) by Benjamin C. Pierce DDD (Domain-driven design) by Eric J. Evans CC2e (Code Complete 2nd edition) by Steve McConnell railshurts.com/rails-principles ISO/IEC/ IEEE 42010 Systems and software engineering — Architecture description
  38. railshurts.com

  39. railshurts.com Stickers!!