Talk at Rails DM Day3 extreme
See also https://railsdm.herokuapp.com/issues/78
ϑΥʔϜΦϒδΣΫτͱͷ ͖߹͍ํ2018-07-11Rails Developers Meetup 2018 Day 3 Extreme ॾڮګհ @moro
View Slide
‣ (ࣸਅ)Title
Kyosuke MOROHASHImoro moro
גࣜձࣾΤεɾΤϜɾΤεۀɺ౦ূҰ෦্ɻߴྸࣾձΛհޢɾҩྍɾΩϟϦΞɾϔϧεέΞɾγχΞϥΠϑͱଊ͑ɺߴྸࣾձʹదͨ͠ใαʔϏεΛଟ։ൃɾӡӦ
https://www.wantedly.com/companies/sms
͖ΐ͏ͷ
‣ “RailsͷΩϨΠͳઃܭ"࠷ॳ͔Βͯ͢ઃܭ͢Δͷ Ή͔͍ͣ͠ͷͰ෮ͯ͠࡞ΔͱΑͦ͞͏ɻ‣ ʰॅΈͳ͕Β૿ங͍ͯ͘͠ײ͡ʱ@m_seki https://speakerdeck.com/m_seki/re-iterative-development-iteration-4?slide=57‣ Railsʹ͓͍ͯɺͦͷͱ͔͔ͬΓͱͯ͠ϑΥʔϜʹ ண͢Δͷѱ͘ͳͦ͞͏ɻ͖ΐ͏ͷ
എܠ
‣ DBͷςʔϒϧʹ΄΅Ұகͨ͠ߏͷσʔλ͕POST͞Ε͖ͯͯɺͦΕΛARͰγϯϓϧʹӬଓԽ͢Δɻ‣ ͳ͔ͳ͔ͦ͏ߦ͔ͳ͍͜ͱଟ͍ΑͶɻૉͳRails͕ఆ͍ͯ͠Δ͜ͱ
‣ Ϣʔβʔ͕ʹ͢Δใ୯Ґ(≒ϑΥʔϜͷߏ)ͱɺਖ਼نԽ͞ΕͨσʔλߏҟͳΔɻ‣ DBʹӬଓԽ͢Δ͚ͩͰࡁ·ͳ͍͜ͱ͕͋Δɻ‣ ϝʔϧΛૹΔɺϩάΛऔΔɺඇಉظδϣϒΛΩοΫ͢ΔɺΠϕϯτͱͯ͠Publish͢ΔɺɺɺͳͲͳͲ“ͦ͏ߦ͔ͳ͍͜ͱ”
ࠩҟΛຒΊΔςΫχοΫ͏·͘ߦ͖ͦ͏͚ͩͲͬ͘͠Γ͜ͳ͍ͭ
‣ ίϯτϩʔϥʔͰARϞσϧʹ٧Ί͢ɻ‣ ͍ΘΏΔFat ControllerʹͳΓ͕ͪ‣ ͷͰϞσϧʹدͤΔɺͱFat Model‣ ·͍͍͋ͯ͑͠Ϟσϧ͕Ͱ͔͍΄͏͕·ͩϚγ…ࠩҟΛຒΊΔςΫχοΫ
‣ accept_nested_attributes ͰҰ࿈ͷσʔλΛ ·ͱΊͯೖྗͤ͞Δ‣ ϑΥʔϜίϯτϩʔϥʹɺӬଓԽͷσʔλάϥϑ͕࿐ग़͢Δ‣ ͓͢͢Ί͠·ͤΜɻࠩҟΛຒΊΔςΫχοΫ
‣ ʮӬଓԽ͢Δ͚ͩʯͰͳ͍ॲཧΛίʔϧόοΫͱ࣮ͯ͠ݱ͢Δɻ‣ ίϧόοΫ͍ͨ͠ͱ͖ͱɺ୯ʹσʔλΛอଘ͍ͨ͠ͱ͖ͷหผ͕͍ͨΜ‣ ίʔϧόοΫʹͨ͘͞Μͷ if ͕Ͱ͖ͯ͘Δͷ͕༧ஹࠩҟΛຒΊΔςΫχοΫ
‣ 7 Patterns to Refactor Fat ActiveRecord Models‣ https://codeclimate.com/blog/7-ways-to-decompose-fat-activerecord-models/‣Realworld Domain Model on Rails‣ https://speakerdeck.com/joker1007/realworld-domain-model-on-rails͍ͨΜͩΑͶɺɺɺͱ͍͏ͷ͕ΒΕ͖ͯͨ
͡Ί͔ΒͪΌΜͱઃܭ͢ΔͷΉ͔͍ͣ͠
ܧଓతʹҭͯΔҰา
“࠷༗༻ͳઃܭݪଇʹɺϓϩάϥϜʢϢʔβʔΠϯλʔϑΣΠεʣͷϓϨθϯςʔγϣϯͱͦͷଞͷػೳΛ͏·͚͘Δɺͱ͍͏ͷ͕͋Γ·͢ɻϓϨθϯςʔγϣϯͱυϝΠϯͷ http://bliki-ja.github.io/PresentationDomainSeparation/
‣ Webͷೖྗ = request ʹू͞Ε͍ͯΔσʔλ‣ ͱͦΕΛಋͨ͘ΊͷϑΥʔϜͦͷଞը໘‣ϦϯΫͰͷGETભҠೖྗͱ͍͑ೖྗ͚ͩͲɺ ͜͜Ͱ;Ε·ͤΜɻ‣ඇಉظδϣϒͰ AJ#perform ͷҾڥมͳͲ͕ ೖྗͱͳΔɻRailsͷϓϨθϯςʔγϣϯ
‣ ʮͦͷଞͷػೳʯ‣ 1ͭҎ্ͷςʔϒϧʹҰ࿈ͷσʔλΛ·ͱΊͯӬଓԽ͢Δ‣ ࿈ܞγεςϜʹ͚ͯΠϕϯτΛPub͢Δ‣ ͳͲͳͲRailsͰ͍͏υϝΠϯ
‣ ϓϨθϯςʔγϣϯͷ͕ࣝɺʮͦͷଞͷػೳʯʹϦʔΫ͠ͳ͍Α͏ʹɻ·ͣೖྗΛ͖ͬΓͤ͞Δɻʮ͏·͘ʯ͚Δ
‣ ίϯτϩʔϥʹͯparams͔ΒΛऔΓग़͠ɺHash จࣈྻͱͯ͠ѻ͏ɻ‣ ࣮ଶ͕ AC::Parameters Ͱ Hash ͷΑ͏ʹѻ͏ɻ৺ͷͰܕΛݟΔ‣ HTTP༝དྷͷσʔλɺrequest͔ΒऔΓग़͓ͯ͘͠ɻ‣ #user_agent ͱ͔ɺΫοΩʔͷͱ͔ೖྗΛ͖ͬΓ
‣ ొϖʔδͰϝʔϧΞυϨεΛೖྗͤ͞Δɻ‣ ೖྗ͞ΕͨϝʔϧΞυϨεΛอଘ͢Δྫ: Ϣʔβʔొ
‣ ࣮ࡏ֬ೝ༻ͷURLτʔΫϯҰॹʹอଘ͢Δɻ‣ ͜Ε after create ίʔϧόοΫͰΔ͜ͱଟ͍͠ɺͦΕ͚ͩͳΒ͞΄ͲࠔΒͳ͍͚Ͳɻ‣ τʔΫϯΛؚΉURLΛϝʔϧͰૹ৴͢Δɻ‣ ͜ΕΛίʔϧόοΫͰΔͱՒࠜʹͳΓ͕ͪɻྫ: AR͚ͩͰ·͔ͳ͍ͮΒ͍ʮΔ͜ͱʯ
‣ ίϯτϩʔϥͰऔΓग़ͨͨͪ͠Λೖྗʹ͢Δɻ‣ ୯Ұͷϝιουݺͼग़͠ͰॲཧҰࣜΛ࣮ߦ͢Δɻ‣ ໊લΛ͚ͭΔͷ૬มΘΒ͍ͣ͠‣ ಈ໊ࢺʹͨ͠Γɺpre/suffix͚ͭͨΓɺͦͷଞنΛಋೖͨ͠Γɻɻɻ‣ ؤுΕม͑ΒΕΔͷͰɺνʔϜͰͬ͘͠ΓདྷΔͭʹ͢ΔͱΑ͍ɻ͚ΔͨΊͷΛಋೖ͢Δ(ศ্ٓϑΥʔϜΦϒδΣΫτͱݺͼ·͢)
“• ಉ͡جຊϓϩάϥϜΛɺॏෳίʔυͳ͠ʹɺෳͷϓϨθϯςʔγϣϯʹରԠͤ͞Δ͜ͱ͕Ͱ͖Δ• ϢʔβʔΠϯλʔϑΣΠεςετ͕͠ʹ͍ͨ͘ΊɺͦΕΛ͢Δ͜ͱʹΑΓɺςετՄೳͳϩδοΫ෦ʹूதͰ͖Δ• εΫϦϓτ༻ͷ"1*αʔϏεͱͯ͠֎෦Խ͢ΔͨΊͷ"1*ΛָʹՃͰ͖ΔʢબՄೳͳϓϨθϯςʔγϣϯ෦Ͱݟ͔͚ΔʣϓϨθϯςʔγϣϯͱυϝΠϯͷ http://bliki-ja.github.io/PresentationDomainSeparation/
‣ ͜ͷ”͚ΔͨΊͷ”ͷೖྗPOROʹͳΔͷͰɺςετ͔Β؆୯ʹݺͼग़ͤΔɻ‣ PORO: Plain Old Ruby Object = ී௨ͷΦϒδΣΫτ‣ ؆୯ʹݺͼग़ͤΔͷͰɺଞͷςετͰͷσʔληοτΞοϓʹ͑ΔɻςετՄೳ
email = '[email protected]'form = UserRegistrationForm.new(email: email)form.calltoken = extract_token_from_sent_email(AM::Base.deliveries.last)expect(token).not_to be_nilexpect(UserRegistration.find_by(email: email, uuid: token)).to be_presentྫ1: ೖྗ͞ΕͨϝΞυΛอଘͯ֬͠ೝURLΛϝʔϧ͢Δͷͷςετ
͜ͷʮϑΥʔϜΦϒδΣΫτʯΛߋʹɺͨͱ͑͜Μͳ;͏ʹҭͯͨ͘ͳͬͨͱͯ͠:1. ϑΥʔϜΦϒδΣΫτೖྗϋϯυϦϯάʹͱͲΊɺ ӬଓԽͷͨΊʹαʔϏεΛ͏Ұઃ͚͍ͨɻ2. ϝʔϧૹ৴ΤϯςΟςΟӬଓԽΛPub/SubͰݕͯ͠ ૄ݁߹ʹ͍ͨ͠ɻ“ϩδοΫ෦ʹूதͰ͖Δ”
> ӬଓԽͷͨΊʹαʔϏεΛઃ͚͍ͨemail = '[email protected]'form = UserRegistrationForm.new(email: email)form.calltoken = extract_token_from_sent_email(AM::Base.deliveries.last)expect(token).not_to be_nilexpect(UserRegistration.find_by(email: email, uuid: token)).to be_present‣ ෦ʹ͏1ϨΠϠઃ͚ͯɺϓϨθϯςʔγϣϯͱͷΠϯλʔϑΣʔεมΘΒͣ҆ఆ͍ͯ͠Δɻ
> Pub/SubͰૄ݁߹ʙUserRegistrationForm.new(email: email).call+ OurJob.execute_all!token = extract_token_from_sent_email(AM::Base.deliveries.last)‣ ΠϯλʔϑΣʔε҆ఆͨ͠··ɺΞʔΩςΫνϟมߋʹඞཁͳमਖ਼͚ͩΛೖΕΕΑ͍ɻ
‣ ΠϯλʔϑΣʔε͕҆ఆ͢ΔͷͰɺϩδοΫ෦Λ มԽ/ચ࿅͢Δࣗ༝͕ಘΒΕΔɻ‣ (ಈ࡞͢Δ && !ΩϨΠ) ͳίʔυΛɺ (ಈ࡞͢Δ && ΩϨΠ) ͳίʔυʹҭͯΒΕΔɻ‣ ϦϑΝΫλϦϯά!“ϩδοΫ෦ʹूதͰ͖Δ”
ศ্ٓϑΥʔϜΦϒδΣΫτͱݺΜͩҙਤ
‣ A: ͲͬͪͰ͍͍‣ ࣗಈςετ͕͋ͬͯϦϑΝΫλϦϯά͘͢͠ͳ͍ͬͯΕokɻ‣ ʮೖྗΛͱΓ·ͱΊͯόϦσʔγϣϯ·ͰΛ͢Δʯͱɺ ʮͦͷvalidͳೖྗͰॲཧΛ͢Δʯʹׂ͍͍ͯ͠Μ͡Όͳ͍͔ͳɻ‣ ࠷ॳʹখ͘͞࡞Δͱ͖UIͱ͚ۙͮͨ΄͏͕͍͍Μ͡Όͳ͍͔ͳ‣ ʮϑΥʔϜʯͬͯͭ·ΓɺαʔϏεΛఏڙ͢Δଆ͕ར༻ऀʹظ͢Δ ߦಈͦͷͷͩΑͶɻ‣ ͦ͜ʹԊͬͨͷΛ࡞Δͷ͕ૉ͡Όͳ͍͔ͳɻαʔϏεϨΠϠ͡Όͳͯ͘ϑΥʔϜΦϒδΣΫτਪ͠ͳͷͳͥ?
‣ ʮೖྗʯͱʮϩδοΫ෦ʯΛ͚Α͏‣ ϓϩμΫτίʔυςετεοΩϦ͢Δͣ!‣ ࠷ॳখ͘͞φΠʔϒʹ࡞Ζ͏‣ ઃܭ͕ΜΓ͗ͯ͢ർΕͳ͍Α͏ʹ…‣ Ͳ͏͍͏நԽ͕ྑ͍ͷ͔ɺ࠷ॳΘ͔Βͳ͍͔ΒͶ‣ ͪΌΜͱʑϦϑΝΫλϦϯά͠Α͏‣ φΠʔϒͳ··ΰνϟοͱੵΈଓ͚ΔͱͦΕμϝͰ͢ͶͲͬͪͰΑ͘ͳ͍͜ͱ
·ͱΊ
‣ Ϗϡʔ / ίϯτϩʔϥ / AR::B ͷࡾ૬ߏͰ·͔ͳ͑ͳͦ͏ͳ߹ɺബ͍Λ͏Ұ࡞ͬͯΈΔͱΑ͍ɻ‣ ίϯτϩʔϥ͕ѻ͏WebͷೖྗͱɺϩδοΫʹඞཁͳ ೖྗͷڥքͱͳΔ͜ͱΛҙࣝ͢Δɻ‣ φΠʔϒ͔ͭςετ͕ॻ͖͍͢ϨΠϠ͔Β͡Ίͯɺ ෮͠ͳ͕ΒมԽ͍͚ͯ͠ΔΑ͏ʹ!·ͱΊ