Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

ࣗݾ঺հ 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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Fat Model 4

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

How to Deal with Fat Model 6

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

1st Approach Rails Way 17

Slide 18

Slide 18 text

18

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

ͦͷଞࡉ͔ΊͷςΫχοΫ • Serialize Attribute • jsonܕΧϥϜ΁ͷϝλσʔλอଘʹศར • ⚠ ʰSQLΞϯνύλʔϯʱ5ষ EAV • Value Object (compose_of) • ෳ਺ΧϥϜΛValueΦϒδΣΫτͱͯ͠ల։͢Δͱ͖ʹศར 28

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

ʮ1. Rails Wayʯ·ͱΊ • ! Rails Way͚ͩͰ͸Fat ModelΛ౗͢खஈͱͯ͠ख਺͕গͳ͘ ෺଍Γͳ͍ • ❌ Concerns, Validation ClassͳͲFat ModelΛDRYʹهड़͢ Δखஈʹ͸ͳΔ͕ɺߏ଄తʹμΠΤοτ͢Δखஈʹ͸ͳͬͯ ͳ͍ʢہॴతͳμΠΤοτࢭ·Γʣ • ❌ STI, PolymorphicͳͲ͸DBઃܭͱີ݁߹ͨ͠ιϦϡʔγϣ ϯͰɺ׬શͳίʔυϨϕϧͷղܾʹ͸ͳ͍ͬͯͳ͍ʢͦΕࣗ ମ͕ٕज़ෛ࠴ʹͳΓ͑Δߏ଄త໰୊ΛሃΜͰ͍Δʣ 30

Slide 31

Slide 31 text

2nd Approach Sub-Rails Way 31

Slide 32

Slide 32 text

32

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

View Model • ! gem • draper • active_decorator 36

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

ݖݶ؅ཧ • ! ؅ཧը໘Ͱಀ͛ΒΕͳ͍࣮૷͕ݖݶ؅ཧɾೝՄ • " ResourceͷCRUDͰϢʔβʔͷΞΫηε੍ޚ͢Δͷ͕ʮRails Β͍͠ʯݖݶ؅ཧ • # gem • pundit • banken • cancancan 38

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

Interactor Clean Architecture: Use Case (Interactor) 40

Slide 41

Slide 41 text

Interactor Rails x Clean Architecture 41

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

ಛఆͷ՝୊ͷղܾ • ࿦ཧ࡟আ • ! gem: discard, paranoia, acts_as_paranoid • ⚠ SQLΞϯνύλʔϯ ݬͷୈ26ষʮͱΓ͋͑ͣ࡟আϑϥ άʯ • ཁૉͷιʔτɾฒͼସ͑ • ! gem: acts_as_list, ranked-model 44

Slide 45

Slide 45 text

ಛఆͷ՝୊ͷղܾ • State Machine • ! gem: aasm, stateful_enum • Tagging • ! gem: acts-as-taggable-on • HashΛActiveRecordͬΆ͘ૢ࡞ • ! gem: active_hash 45

Slide 46

Slide 46 text

ʮͦΕ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

Slide 47

Slide 47 text

ʮͦΕ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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

SaaSʹ੾Γग़͢ • ! ϢʔβʔೝূϩδοΫΛ Auth0 ʹҠৡ • ೝূʹͱ΋ͳ͏MFAɺύεϫʔυϦηοτɺηΩϡϦςΟର ࡦͳͲͷ໘౗ͳ࣮૷ΛAuth0͕ݞ୅ΘΓ • " ͦͷଞͷࣄྫ • Τϥʔ௨஌Λ Sentry ʹҠৡ • APMΛ NewRelic / Datadog Ͱ΍Δ 50

Slide 51

Slide 51 text

ʮ2. Sub-Rails Wayʯ·ͱΊ • ! gem Λ࢖͏͜ͱͰ Fat Model ରॲ๏ͷόϦΤʔγϣϯ͕޿ ͕Δ • ✅ ಠ࣮ࣗ૷ͰModelΛଠΒͤͣɺ࢖͑Δgem͸ੵۃతʹར༻ ͠Α͏ • # ҰํɺgemΛ࢖Θͣͱ΋Railsඪ४ͰղܾͰ͖Δ͜ͱ΋ଟ ͍ͷͰݟۃΊ্ͨͰgemಋೖ͠Α͏ • $ બ୒ࢶ͸͞΄Ͳଟ͘ͳ͍͕ SaaS Λ࢖͏ͷ΋ Fat Model ର߅ खஈͷ̍ͭ 51

Slide 52

Slide 52 text

3rd Approach Non-Rails Way 52

Slide 53

Slide 53 text

53

Slide 54

Slide 54 text

ಠࣗ࿏ઢ 54

Slide 55

Slide 55 text

Form Model • Form Model = include ActiveModel ͨ͠RubyΫϥεʢ͍ΘΏ Δ Form Objectʣ • ϑΥʔϜ:Form Model = 1:1 • ! gem • reform • dry-rbγϦʔζ3 3 چɾvirtus 55

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

PORO 58

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

1 Table Multiple Models 62

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

ʮ3. Non-Rails Wayʯ·ͱΊ • 4ͭͷ Non-Rails 1. Form Model 2. PORO 3. Service Class 4. 1 Table Multiple Models • ! ͏·͘ಋೖͰ͖Ε͹ Fat Model Λ౗͢ڧྗͳ෢ثͱͳΔ • " ਖ਼ղ͸ͳ͍ͱࢥ͏ͷͰνʔϜʹ͋ͬͨख๏Λબ୒͢Δͱྑ͍ 64

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

! Thank You 68

Slide 69

Slide 69 text

ࢀߟจݙ • 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

Slide 70

Slide 70 text

ࢀߟࢿྉ • 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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

ࢀߟࢿྉ • தن໛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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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