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

Fat Modelの倒し方 / how to deal with fat model

Fat Modelの倒し方 / how to deal with fat model

銀座Rails#21 ( https://ginza-rails.connpass.com/event/173610/ ) の発表資料になります。

Ruby on Rails アプリケーションにおける Fat Model の解決方法を下記の3つに分けて紹介しています。
1. Rails Way
2. Sub-Rails Way
3. Non-Rails Way

本発表はBlogにも文書の形でまとめてありますのでそちらもあわせてご参照ください。
https://blog.toshimaru.net/how-to-deal-with-fat-model/

toshimaru

May 15, 2020
Tweet

More Decks by toshimaru

Other Decks in Technology

Transcript

  1. Fat Modelͷ౗͠ํ
    2020/5/15 ۜ࠲Rails#21
    1

    View full-size slide

  2. ࣗݾ঺հ
    toshimaru
    - GitHub: toshimaru
    - Twitter: toshimaru_e
    Rails Engineer @ MedPeer
    - We're Hiring

    OSS Activities:
    - Syntax Highlighted Go cat
    (toshimaru/nyan)
    - VSCode Color Theme
    (toshimaru/hybrid-next-plus)
    2

    View full-size slide

  3. Q.ංେԽͨ͠RailsΞϓϦέʔγϣϯ
    ࠷΋ਏ͍ϨΠϠʔ͸Ͳ͜
    1. Fat View
    2. Fat Controller
    3. Fat Model
    3

    View full-size slide

  4. Fat Rails Stage
    Fat Stage Railsशख़౓ Fat Layer
    1 ௿ Fat View
    2 த Fat Controller
    3 ߴ Fat Model1
    1 Buckblog: Skinny Controller, Fat Model
    5

    View full-size slide

  5. How to
    Deal with
    Fat Model
    6

    View full-size slide

  6. ࿩͢͜ͱ
    • Fat Model ʹରॲ͢ΔͨΊͷΞϓϩʔνΛ੔ཧ
    • Fat Model ରॲʹ͋ͨΓͲͷΞϓϩʔνΛऔΔ΂͖͔
    ࿩͞ͳ͍͜ͱ
    • ͦΕͧΕͷΞϓϩʔνͷ࣮૷ৄࡉɾ۩ମతͳ࣮૷ํ๏΍࣮૷ྫ
    • Fat Controller/Fat Viewͷରॲ๏
    7

    View full-size slide

  7. Fat Model ରॲͷͨΊͷ
    ̏ͭͷΞϓϩʔν
    1. Rails Way
    2. Sub-Rails Way
    3. Non-Rails Way
    8

    View full-size slide

  8. RailsΞϓϦέʔγϣϯͷ
    Model૚͕ݶքʹ
    Ϳ͔ͭΔͱ͖
    9

    View full-size slide

  9. Rails Modelͷݶք఺a
    a ApplicationModel ͷ͋Δ෩ܠ - Speaker Deck
    10

    View full-size slide

  10. Rails Modelͷݶք఺a
    a ApplicationModel ͷ͋Δ෩ܠ - Speaker Deck
    11

    View full-size slide

  11. Rails Modelͷݶք఺b
    b Ruby on Railsͷਖ਼ମͱ޲͖߹͍ํ - Speaker Deck
    12

    View full-size slide

  12. Rails Modelͷݶք఺
    • 1ͭͷModel͕ෳ਺ͷҟͳΔϢʔεέʔεʹີ݁߹࣮ͯ͠૷͞Ε
    Δͱ͖
    • → ͋Δ৚݅΍contextʹඥ෇͍ͨValidation/Callbackॲཧ
    • 1ͭͷϑΥʔϜͰෳ਺ͷαϒϦιʔε͕ߋ৽͞ΕΔͱ͖
    ʢϑΥʔϜͱModel͕1ର1Ͱඥ෇͔ͳ͍ͱ͖ʣ
    • → 1ͭͷModelΛى఺ͱͨ͠ෳ਺ModelΛލ͙τϥϯβΫ
    γϣϯॲཧ
    • Rails Model : DB Table = 1:1 ͷੈք؍ʹىҼ͢Δݶք
    13

    View full-size slide

  13. զʑ͕໨ࢦ࢟͢c
    c Growing Rails Applications in Practice
    14

    View full-size slide

  14. զʑ͕໨ࢦ࢟͢c
    c Growing Rails Applications in Practice
    15

    View full-size slide

  15. ΰʔϧ
    ίʔυϕʔε͕େ͖͘ͳͬͯ
    ΋ϖΠϯ͕૿େ͠ͳ͍Rails
    ίʔυϕʔε
    16

    View full-size slide

  16. 1st Approach
    Rails
    Way
    17

    View full-size slide

  17. Ϩʔϧʹ৐ͬͨ։ൃख๏
    19

    View full-size slide

  18. Concerns
    Model/Controllerͷڞ௨ͷؔ৺ࣄʢConcernʣΛmoduleʹ੾Γग़͢
    ʢ୅දྫ: DHH's Recording Class6ʣ
    6 https://twitter.com/dhh/status/964244090224128001
    20

    View full-size slide

  19. Concerns


    ConcernͷެࣜΨΠυ͸ͳ͍
    • DHH: Put chubby models on a diet with concerns
    • Modelͷ͍࣋ͬͯΔೳྗʢability = -able suffixʣʹண໨ͯ͠੾
    Γग़͍ͯ͘͠ͷ͕Rails WayͬΆ͍
    21

    View full-size slide

  20. STI
    Raiilsʹ͓͍ͯςʔϒϧͱModel͸1ର1Ͱ݁ͼ͕ͭ͘ɺSTIΛ࢖͑
    ͹1ͭͷςʔϒϧͰෳ਺Modelඥ෇͚Δ͜ͱ͕Ͱ͖Δ5
    5 PoEAA: Single Table Inheritance
    22

    View full-size slide

  21. STI
    companies ςʔϒϧʹඥͮ͘ Firm, Client Ϟσϧͷྫ:
    23

    View full-size slide

  22. Polymorphic Association
    1ͭͷϙϦϞʔϑΟοΫؔ࿈෇͚ఆٛͰෳ਺ͷςʔϒϧΛैଐͤ͞
    Δ͜ͱ͕Ͱ͖Δ
    24

    View full-size slide

  23. Polymorphic Association

    ʰSQLΞϯνύλʔϯʱ6ষ ϙϦϞʔϑΟοΫؔ࿈
    25

    View full-size slide

  24. accepts_nested_attributes_for
    ωετ͞ΕͨΞτϦϏϡʔτͰؔ࿈Ϧιʔεͷ࡞੒ɾߋ৽ɾ࡟আ
    Λߦ͏
    26

    View full-size slide

  25. accepts_nested_attributes_for


    ඇਪ঑ʁ
    • DHH͕ʮফ͍ͨ͠ʯͱൃݴ͍ͯ͠Δ7
    7 https://github.com/rails/rails/pull/26976#discussion_r87855694
    27

    View full-size slide

  26. ͦͷଞࡉ͔ΊͷςΫχοΫ
    • Serialize Attribute
    • jsonܕΧϥϜ΁ͷϝλσʔλอଘʹศར


    ʰSQLΞϯνύλʔϯʱ5ষ EAV
    • Value Object (compose_of)
    • ෳ਺ΧϥϜΛValueΦϒδΣΫτͱͯ͠ల։͢Δͱ͖ʹศར
    28

    View full-size slide

  27. ͦͷଞࡉ͔ΊͷςΫχοΫ
    • Ϋϥεͱͯ͠෼཭Մೳ
    • Validation Class
    • Callback Class
    • → ෼཭͢Δ͜ͱͰෳ਺ϞσϧͰ࠶ར༻Մೳʹ
    29

    View full-size slide

  28. ʮ1. Rails Wayʯ·ͱΊ

    !
    Rails Way͚ͩͰ͸Fat ModelΛ౗͢खஈͱͯ͠ख਺͕গͳ͘
    ෺଍Γͳ͍


    Concerns, Validation ClassͳͲFat ModelΛDRYʹهड़͢
    Δखஈʹ͸ͳΔ͕ɺߏ଄తʹμΠΤοτ͢Δखஈʹ͸ͳͬͯ
    ͳ͍ʢہॴతͳμΠΤοτࢭ·Γʣ


    STI, PolymorphicͳͲ͸DBઃܭͱີ݁߹ͨ͠ιϦϡʔγϣ
    ϯͰɺ׬શͳίʔυϨϕϧͷղܾʹ͸ͳ͍ͬͯͳ͍ʢͦΕࣗ
    ମ͕ٕज़ෛ࠴ʹͳΓ͑Δߏ଄త໰୊ΛሃΜͰ͍Δʣ
    30

    View full-size slide

  29. 2nd Approach
    Sub-Rails
    Way
    31

    View full-size slide

  30. ϨʔϧΛิڧɾ֦ுͭͭ͠
    Ϩʔϧʹ৐Δ
    33

    View full-size slide

  31. ϨʔϧΛԿΛ࢖ͬͯ
    ิڧɾ֦ு͢Δ͔ʁ
    1. gem
    2. SaaS
    34

    View full-size slide

  32. View Model
    • Modelʹ͓͚ΔViewؔ࿈ϩδοΫΛ View Model ͱͯ͠੾Γग़
    ͢
    • Development of Further PoEAA: Presentation Model
    • ModelΛDecoratorύλʔϯͬΆ֦͘ு͍ͯ͠ΔͷͰ Decorator
    ͱ΋ݺ͹ΕΔ8
    • Fat View ͷରॲͱͯ͠΋ػೳ͢Δ఺͕˓
    8 ࢀߟ: ʰRubyʹΑΔσβΠϯύλʔϯʱୈ11ষ ΦϒδΣΫτΛվྑ͢ΔɿDecorator
    35

    View full-size slide

  33. View Model

    !
    gem
    • draper
    • active_decorator
    36

    View full-size slide

  34. View Model
    !
    draper ͷ৔߹ʢArticleϞσϧͷDecoratorΫϥεʣ:
    37

    View full-size slide

  35. ݖݶ؅ཧ

    !
    ؅ཧը໘Ͱಀ͛ΒΕͳ͍࣮૷͕ݖݶ؅ཧɾೝՄ

    "
    ResourceͷCRUDͰϢʔβʔͷΞΫηε੍ޚ͢Δͷ͕ʮRails
    Β͍͠ʯݖݶ؅ཧ

    #
    gem
    • pundit
    • banken
    • cancancan
    38

    View full-size slide

  36. ݖݶ؅ཧ
    !
    pundit ͷ৔߹ʢPostϞσϧͷೝՄΫϥεʣ:
    39

    View full-size slide

  37. Interactor
    Clean Architecture: Use Case (Interactor)
    40

    View full-size slide

  38. Interactor
    Rails x Clean Architecture
    41

    View full-size slide

  39. Interactor

    !
    gem
    • interactor-rails
    • (not Rails) hanami's Interactor
    42

    View full-size slide

  40. Interactor
    !
    interactor-rails ͷ৔߹ʢϢʔβʔΛೝূ͢ΔΫϥεʣ:
    43

    View full-size slide

  41. ಛఆͷ՝୊ͷղܾ
    • ࿦ཧ࡟আ

    !
    gem: discard, paranoia, acts_as_paranoid


    SQLΞϯνύλʔϯ ݬͷୈ26ষʮͱΓ͋͑ͣ࡟আϑϥ
    άʯ
    • ཁૉͷιʔτɾฒͼସ͑

    !
    gem: acts_as_list, ranked-model
    44

    View full-size slide

  42. ಛఆͷ՝୊ͷղܾ
    • State Machine

    !
    gem: aasm, stateful_enum
    • Tagging

    !
    gem: acts-as-taggable-on
    • HashΛActiveRecordͬΆ͘ૢ࡞

    !
    gem: active_hash
    45

    View full-size slide

  43. ʮͦΕRailsͰͰ͖ΔΑʯ10

    !
    enumerize (Emumerized Attributes)
    • Rails 4.1: ActiveRecord enum

    !
    switch_point (Database R/W Split)
    • Rails 6: Multi-DB

    !
    activerecord-import (Bulk Import)
    • Rails 6: insert_all, upsert_all
    10 Ruby/Railsެࣜͷఏڙ͢Δػೳ͸gemΑΓශऑͩͬͨΓ͢ΔͷͰ͔͋͠Βͣ
    46

    View full-size slide

  44. ʮͦΕRailsͰͰ͖ΔΑʯ10

    !
    carrierwave, shrine (File Uploader)
    • Rails 5.2: Active Storage

    !
    config (YAML Config Management)
    • Rails Custom configuration:
    • Rails::Application.config_for
    • config.x
    10 Ruby/Railsެࣜͷఏڙ͢Δػೳ͸gemΑΓශऑͩͬͨΓ͢ΔͷͰ͔͋͠Βͣ
    47

    View full-size slide

  45. ʮͦΕRailsͰͰ͖ΔΑʯ10

    !
    friendly_id
    • ActiveRecord: to_param
    • ID/Passwordೝূ
    • ActiveModel: has_secure_password
    10 Ruby/Railsެࣜͷఏڙ͢Δػೳ͸gemΑΓශऑͩͬͨΓ͢ΔͷͰ͔͋͠Βͣ
    48

    View full-size slide

  46. ʮͦΕRubyͰͰ͖ΔΑʯ10

    !
    pry
    • Ruby 2.4: binding.irb
    • Ruby 2.7: REPL Syntax Highlighting
    10 Ruby/Railsެࣜͷఏڙ͢Δػೳ͸gemΑΓශऑͩͬͨΓ͢ΔͷͰ͔͋͠Βͣ
    49

    View full-size slide

  47. SaaSʹ੾Γग़͢

    !
    ϢʔβʔೝূϩδοΫΛ Auth0 ʹҠৡ
    • ೝূʹͱ΋ͳ͏MFAɺύεϫʔυϦηοτɺηΩϡϦςΟର
    ࡦͳͲͷ໘౗ͳ࣮૷ΛAuth0͕ݞ୅ΘΓ

    "
    ͦͷଞͷࣄྫ
    • Τϥʔ௨஌Λ Sentry ʹҠৡ
    • APMΛ NewRelic / Datadog Ͱ΍Δ
    50

    View full-size slide

  48. ʮ2. Sub-Rails Wayʯ·ͱΊ

    !
    gem Λ࢖͏͜ͱͰ Fat Model ରॲ๏ͷόϦΤʔγϣϯ͕޿
    ͕Δ


    ಠ࣮ࣗ૷ͰModelΛଠΒͤͣɺ࢖͑Δgem͸ੵۃతʹར༻
    ͠Α͏

    #
    ҰํɺgemΛ࢖Θͣͱ΋Railsඪ४ͰղܾͰ͖Δ͜ͱ΋ଟ
    ͍ͷͰݟۃΊ্ͨͰgemಋೖ͠Α͏

    $
    બ୒ࢶ͸͞΄Ͳଟ͘ͳ͍͕ SaaS Λ࢖͏ͷ΋ Fat Model ର߅
    खஈͷ̍ͭ
    51

    View full-size slide

  49. 3rd Approach
    Non-Rails
    Way
    52

    View full-size slide

  50. ಠࣗ࿏ઢ
    54

    View full-size slide

  51. Form Model
    • Form Model = include ActiveModel ͨ͠RubyΫϥεʢ͍ΘΏ
    Δ Form Objectʣ
    • ϑΥʔϜ:Form Model = 1:1

    !
    gem
    • reform
    • dry-rbγϦʔζ3
    3 چɾvirtus
    55

    View full-size slide

  52. Form Model
    ඥͮ͘ςʔϒϧ਺ Ϣʔεέʔε
    0 ໰͍߹ΘͤϑΥʔϜͳͲςʔϒϧ
    Λ࡞Δ·Ͱ΋ͳ͍ϑΥʔϜͰར༻
    1 - 4
    2Ҏ্ accepts_nested_attributes_for
    ͷ୅ΘΓͱͯ͠ෳࡶͳϑΥʔϜͷ
    ૊Έཱͯ࣌ʹར༻
    4 ςʔϒϧͱϑΥʔϜ͕1ର1Ͱඥͮ͘৔߹͸Rails WayͰղܾͤ͞·͠ΐ͏
    56

    View full-size slide

  53. PORO
    • PORO (Plain Old Ruby Object)
    • PoEAA: POJO (Plain Old Java Object)
    • ActiveRecord ͷػೳʹґଘ͠ͳ͍७ਮͳRuby࣮૷
    • include ActiveModel
    • ७ਮͳRuby࣮૷ͳͷͰ͋Δҙຯ Ruby Way ͱݴ͑Δ
    • Model ͷิॿྠత໾ׂ
    57

    View full-size slide

  54. Service Class


    αʔϏεͷఆٛ໰୊ → What is your "Service"?
    • PoEAA: Service Layer
    • DDD: Service Class
    • Onion Architecture: Application Service, Domain Service
    • Rails "Service"
    • ʮͲ͏͍͏จ຺ͷαʔϏε͔ʯΛ໌֬ʹ͠ͳ͍ͱService Class
    ͷఆٛɾ֓೦͕ϘϯϠϦ͢Δҹ৅
    59

    View full-size slide

  55. Service Class
    • αʔϏεΫϥεʹର͢Δݸਓతݟղ
    • Service Class ͷఆٛɾ࢖͍ํΛ໌֬ʹ্ͨ͠ͰνʔϜʹಋ
    ೖ͍ͯ͘͠ͷ͕٢
    • ʮಛఆͷϢʔεέʔεͷղܾʯͱ͍͏ҙຯʹ͓͍ͯ͸
    Interactor ͷ΄͏͕ʢগͳ͘ͱ΋Railsʹ͓͍ͯ͸ʣے͕ྑ͞
    ͦ͏
    • Լखʹ৽͍֓͠೦Λ࣋ͪࠐΉΑΓɺPORO ͱ͍͏֓೦Ͱࡶʹ
    ·ͱΊͨ΄͏͕޷Έ
    60

    View full-size slide

  56. 1 Table Multiple Models
    • Ұͭͷςʔϒϧʹෳ਺ͷModelΛඥ෇͚Δ
    • Rails WayͩͱSTIͰͷΈ࣮ݱՄೳ
    61

    View full-size slide

  57. 1 Table Multiple Models
    62

    View full-size slide

  58. 1 Table Multiple Models
    • 1 Table 1 ModelͷRailsͷύϥμΠϜʢن໿ʣΛյ͢ͷ͸͍͞͞
    ͔ةݥࢥ૝ͱ͍͏ҹ৅
    • ࣮ӡ༻ʹ͓͚Δ੒ޭྫ͋Ε͹ڭ͑ͯԼ͍͞
    63

    View full-size slide

  59. ʮ3. Non-Rails Wayʯ·ͱΊ
    • 4ͭͷ Non-Rails
    1. Form Model
    2. PORO
    3. Service Class
    4. 1 Table Multiple Models

    !
    ͏·͘ಋೖͰ͖Ε͹ Fat Model Λ౗͢ڧྗͳ෢ثͱͳΔ

    "
    ਖ਼ղ͸ͳ͍ͱࢥ͏ͷͰνʔϜʹ͋ͬͨख๏Λબ୒͢Δͱྑ͍
    64

    View full-size slide

  60. Non-Rails Way ͓͢͢ΊΞϓϩʔν
    • ෳࡶͳϑΥʔϜ: Form Model
    • ϢʔεέʔεʹಛԽͨ͠Ϋϥε: Service Class Interactor
    • ↑Ͱ଍Γͳ͍৔߹: PORO
    65

    View full-size slide

  61. શମͷ·ͱΊ
    Fat Model Λ౗ͨ͢Ίͷ3ͭͷΞϓϩʔν Λ঺հ͠·ͨ͠ɻ
    1. Rails Way: Railsͷن໿ʹԊͬͨ։ൃ
    2. Sub-Rails Way: Railsͷن໿ΛgemͰิڧɾ֦ு
    3. Non-Rails Way: Railsͷن໿͔Β֎ΕΔಠ࣮ࣗ૷
    66

    View full-size slide

  62. ݁࿦
    • ·ͣ͸ Rails Way + Sub-Rails Way ͰFat ModelΛμΠΤοτͰ
    ͖ͳ͍͔ߟ͑·͠ΐ͏ɻͦͷ্ͰඞཁʹԠͯ͡ద੾ͳ Non-
    Rails Way ΛऔΓೖΕ͍͖ͯ·͠ΐ͏
    • Non-Rails Way ͸νʔϜຖʹ࠷దղ͕͋Δͱࢥ͏ͷͰɺνʔϜ
    Ͱ߹ҙͰ͖Δಠࣗ࿏ઢΛબ୒ɾಋೖ͢Ε͹Α͍ͷͰ͸ͳ͍Ͱ
    ͠ΐ͏͔
    67

    View full-size slide

  63. !
    Thank You
    68

    View full-size slide

  64. ࢀߟจݙ
    • Patterns of Enterprise Application Architecture by Martin
    Fowler
    • Clean Architecture by Robert Cecil Martin
    • Domain-Driven Design by Eric Evans
    • Growing Rails Applications in Practice by Henning Koch and
    Thomas Eisenbarth
    69

    View full-size slide

  65. ࢀߟࢿྉ
    • Martin Fowler: Development of Further Patterns of Enterprise
    Application Architecture
    • Clean Coder Blog: The Clean Architecture
    • The Onion Architecture : part 1 | Programming with Palermo
    70

    View full-size slide

  66. ࢀߟࢿྉ
    • RailsެࣜυΩϡϝϯτ
    • Active Record Associations — Ruby on Rails Guides
    • Active Model Basics — Ruby on Rails Guides
    • accepts_nested_attributes_for
    • ActiveRecord::Inheritance
    • ActiveSupport::Concern
    71

    View full-size slide

  67. ࢀߟࢿྉ
    • தن໛Web։ൃͷͨΊͷMVC෼ׂͱϨΠϠΞʔΩςΫνϟ -
    Qiita
    • acceptsnestedattributes_forΛ࢖Θͣɺෳ਺ͷࢠϨίʔυΛอଘ
    ͢Δ | Money Forward Engineers' Blog
    • Concerns about Concerns - Speaker Deck
    • Model ͱը໘্ͷ form ͕1ର1ͰҰக͠ͳ͍৔߹ɺͲͷΑ͏ʹ
    ࣮૷͢Δͷ͕៉ྷͳͷ͔ʁ - clean-rails.org
    • Architecture: Interactors | Hanami Guides
    72

    View full-size slide

  68. ࢀߟࢿྉ
    • RailsͰॏཁͳύλʔϯpart 1: Service Objectʢ຋༁ʣʛ
    TechRachoʢςοΫϥονϣʣʙΤϯδχΞͷʮʁʯΛʮʂʯ
    ʹʙʛBPSגࣜձࣾ
    • Decorator ͱ Presenter Λ࢖͍෼͚ͯɺ Rails Λ ViewModel Ͱ
    ͖ͬ͢Γͤ͞Α͏ - KitchHike Tech Blog
    • ͯΊ͑ΒͷRails͸ΦϒδΣΫτࢦ޲͡ΌͶ͑ʂ·ͣ͸Callback
    ΫϥεɺValidatorΫϥεΛ׆༻͠Ζʂ - Qiita
    73

    View full-size slide

  69. ࢀߟࢿྉ
    • Why Service Objects are an Anti-Pattern — INTERSECT
    • Service Object͕ΞϯνύλʔϯͰ͋Δཧ༝ͱΑΓΑ͍୅ସ
    खஈʢ຋༁ʣʛTechRachoʢςοΫϥονϣʣʙΤϯδχΞ
    ͷʮʁʯΛʮʂʯʹʙʛBPSגࣜձࣾ
    • RailsͰෳ਺ϞσϧΛѻ͏ϑΥʔϜΛ͖ͬ͢Γॻ͘ʢFormΦϒ
    δΣΫτʣ - LiBz Tech Blog
    • ActiveRecordͷϞσϧ͕1ͭͩͱͭΒ͍ - Qiita
    74

    View full-size slide