Pro Yearly is on sale from $80 to $50! »

フレームワークを作らない方法/How NOT to build frameworks

フレームワークを作らない方法/How NOT to build frameworks

銀座Rails#10での発表資料です

70e13d9877054026fda46d5a5b53a236?s=128

MOROHASHI Kyosuke

June 21, 2019
Tweet

Transcript

  1. ϑϨʔϜϫʔΫΛ ࡞Βͳ͍ํ๏ )PX/05UPCVJMEGSBNFXPSLT 
 2019-06-21 ۜ࠲Rails#10 ॾڮګհ @moro  

  2. ‣ ࣸਅ  

  3.   Kyosuke MOROHASHI @moro

  4.  

  5. !5 SMS? What's SMSってなにをやってる会社なの?

  6.   https://twitter.com/sunaot/status/1002392476492038144

  7. “ 情報インフラを構築することで、⾼齢社会を
 取り巻く⼈びと、⾼齢社会で働く⽅や事業者の⽅、 ⾼齢者ご⾃⾝やそのご家族などがイキイキと
 ⽣活できる社会の実現を⽬指しています。 — https://www.bm-sms.co.jp/philosophy/

  8. !8 &

  9. 吳䒭⠓爡ؒأ ٥ ؒي ٥ ؒأ 匌❨鿪庥⼒蓎Ⱅ㕦⡝⿼♶⹛欵蓎Ⱅ㕦ةٙ٦ https://www.bm-sms.co.jp ؒٝآص،䱰欽؟؎ ز https://careers.bm-sms.co.jp/engineer/

    join us!
  10. ͜Ε·Ͱͷ͋Β͢͡

  11.  

  12.  

  13. ‣ ͳͥϑϨʔϜϫʔΫʹ͠ͳ͍΄͏͕Α͍͔ ‣ ϑϨʔϜϫʔΫΛ࡞Βͳ͍ํ๏ ‣ ςϯϓϨʔτϝιουΛආ͚ͯ;ͭ͏ʹϝιουʹநग़͢Δ ‣ ςϯϓϨʔτϝιουΑΓ΋ετϥςδʔͰ֦ுͤ͞Δ ‣ lͪΐͬͱҧ͏ॲཧzΛදݱ͢ΔͨΊʹϒϩοΫΛड͚෇͚Δ

    ‣ ·ͱΊ੍ޚߏ଄Λ࢖͍खʹҕͶΔ
  14. ͳͥ
 ϑϨʔϜϫʔΫʹ͠ͳ͍ ΄͏͕Α͍͔

  15. ϥΠϒϥϦͱ ϑϨʔϜϫʔΫ  

  16. “ ͔͠͠ɺϥΠϒϥϦͰ͸ݺͼग़͠ଆ͕ϓϩάϥϜશ ମͷ੍ޚߏ଄ΛࢦఆͰ͖ͳ͍͕ɺϑϨʔϜϫʔΫͰ ͸ՄೳͰ͋Δɻ͜ͷ੍ޚͷ൓స͕ιϑτ΢ΣΞϑ ϨʔϜϫʔΫͷಛ௃Ͱ͋Δɻ https://ja.wikipedia.org/wiki/ιϑτ΢ΣΞϑϨʔϜϫʔΫ

  17. ‣ ʮར༻ऀ͕ݺͼग़͢ʯͷ͕ϥΠϒϥϦ ‣ ʮར༻ऀ ͷίʔυ Λݺͼग़͢ʯͷ͕ϑϨʔϜϫʔΫ ϑϨʔϜϫʔΫ͸੍ޚߏ଄Λࢦఆ͢Δ  

  18. ‣ ͸͖ͬΓͱനࠇ͚ͭΒΕΔΘ͚Ͱ͸ͳ͍ɻ ‣ ར༻ऀͨΔΞϓϦ։ൃऀ͕ݺͼग़͢"DUJWF3FDPSE
 Ϟσϧʹఆٛͨ͠ίʔϧόοΫ͸"DUJWF3FDPSE͕ݺͼग़ͧ͢ʜ  ‣ ར༻ऀ͕ॻ͘ίʔυͷ੍ޚߏ଄ΛͲΕ΄Ͳࢦఆ
 ͢Δ͔͠ͳ͍͔ɻ ˞۠ผ͸౓߹͍

     
  19. ‣ ϑϨʔϜϫʔΫ͸ɺͦͷ্Ͱͷ׆ಈΛ੍໿͢Δɻ ‣ ͍ΘΏΔʮϨʔϧ͔Β߱Γ͍ͨʯ໰୊ ‣ ඞͣ͠΋ѱ͍Θ͚Ͱ͸ͳ͍ʮ੍໿͕ࣗ༝Λ΋ͨΒ͢ʯ ‣ ʮͦͷ্Ͱͷ׆ಈʯ͸༧ଌͰ͖ͳ͍ɻ ‣ ͍͍ͨͯந৅Խ͕࿙ΕΔɻ

    ‣ ࡞ऀͷؾ࣋ͪΛߟ͑Α͏ͱͯ͠΋࡞ऀ΋ߟ͑ͯͳ͍͜ͱ΋ɻ ͳͥϑϨʔϜϫʔΫʹ͠ͳ͍΄͏͕ྑ͍͔  
  20. ‣ ಡΈղ͘ͷʹϝλϓϩάϥϛϯάͷ஌͕ࣝඞཁʹͳΔ͜ͱଟ͍ɻ ‣ ϝλϓϩάϥϛϯάֶशۂઢ ίʔυࣗମ͕೉͘͠ͳΓ͕ͪ   https://www.martinfowler.com/articles/rubyAtThoughtWorks.html

  21. ‣ ଟ͘ͷ"1*ͱͦͷ࢖͍ํΛֶश͢Δඞཁ͋Γɻ ‣ ࡞ऀͷؾ࣋ͪΛߟ͑ͯΞϓϦέʔγϣϯίʔυ Λॻ͘ɻ ϑϨʔϜϫʔΫࣗମ΋ֶशίετ͕͔͔Δ  

  22. ‣ 3VCZͰ8FCΞϓϦ։ൃ͢Δͱ͖ͷυఆ൪ͱͯ͠
  ೥ϝΠϯετϦʔϜʹ͍Δɻ ‣ ৭Μͳ༻్ͷʮݸผࣄ৘ʯΛίϯτϦϏϡʔτ͞Ε ଓ͚͖ͯͨɻ ‣ ʮϨʔϧͷ߱ΓํʯͳΜͯͷ·ͰؚΊͯ๲େͳ
 ϊ΢ϋ΢͕஝ੵ͞Ε͍ͯΔɻ

    3BJMT͸ϛϥΫϧ  
  23. ‣ ࣗ෼ࣗ਎ΛؚΉ ະདྷͷϝϯςφʹର੍͠໿͠ͳ͍ɻ ‣ ະདྷʹͲ͏͍͏ιϑτ΢ΣΞʹ͍͔ͨ͠͸Θ͔Βͳ͍ɻ ‣ େମʹ͓͍ͯߟྀ͸ෆ଍͠ந৅Խ͸࿙ΕΔɻ ‣ ϥΠϒϥϦʹ͓ͯ͘͠ͱɺݺͿ΋ݺ͹ͳ͍΋ɺ
 ΋͏ݺ͹ͳ͘͢Δɺͷ΋ར༻ऀ͕ܾΊΒΕΔɻ

    ʮ;ͩΜ͸ʯϑϨʔϜϫʔΫʹ͢ΔͷΛආ͚Δ  
  24. ͱ͸͍͑ɺ ศརϝιουΛॻ͖ͨ͘ͳΔ͜ͱ͸ ͨ͘͞Μ͋ΔΘ͚Ͱ  

  25. ‣ ͳͥϑϨʔϜϫʔΫʹ͠ͳ͍΄͏͕Α͍͔ ‣ ϑϨʔϜϫʔΫΛ࡞Βͳ͍ํ๏ ‣ ςϯϓϨʔτϝιουΛආ͚ͯ;ͭ͏ʹϝιουʹநग़͢Δ ‣ ςϯϓϨʔτϝιουΑΓ΋ετϥςδʔͰ֦ுͤ͞Δ ‣ lͪΐͬͱҧ͏ॲཧzΛදݱ͢ΔͨΊʹϒϩοΫΛड͚෇͚Δ

    ‣ ·ͱΊ੍ޚߏ଄Λ࢖͍खʹҕͶΔ
  26. ϑϨʔϜϫʔΫΛ ࡞Βͳ͍ํ๏

  27. ݴ͍׵͑Δͱ ੍ޚߏ଄Λ
 ࢖͍खʹҕͶΔํ๏

  28. ςϯϓϨʔτϝιουΛආ͚ͯ ;ͭ͏ʹϝιουʹநग़͢Δ  

  29. ‣ ΦʔόʔϥΠυ͞ΕͯΔϝιουΛ࢓૊Έଆ͕ݺͿɻ ݺ͹ΕΔଆ͔Βߏ଄͕ݟ͑ͳ͍ɻ ‣ 34QFDͷMFUTVCKFDU໰୊΋ಉࠜͰ͋Δͱ΋ݴ͑Δɻ ‣ ۩৅ςετέʔε͔Β཭ΕͨʮϑΝΠϧͷ্ͷํʯʹ
 ߏ଄͕Ͱ͖ΔͷͰɺݟ͑ͳ͍͠ɺม͑ͮΒ͍ɻ ςϯϓϨʔτϝιουύλʔϯͷ໰୊ 

    
  30. ‣ ܧঝͯ͠͠·͏ͷͰɺϑϨʔϜϫʔΫͷ಺෦ߏ଄Λ ࡽͯ͠͠·͏ɻ ‣ ͞ΘΓͨ͘ͳΔΑͶ ‣ ͦͯ͠όʔδϣϯΞοϓͰ͖ͳ͘ͳΔ ‣ 3BJMTΞϓϦ͋Δ͋Δɻ ςϯϓϨʔτϝιουύλʔϯͷ໰୊

     
  31. ‣ 3BJMTࣗମ͕ϥΠϒϥϦఏڙΫϥεΛܧঝͯ͠࢖͏
 ϑϨʔϜϫʔΫͳͷͰɺࣗ෼Ͱ΋ͦ͏ॻ͖ͨ͘ͳΔɻ ‣ ʜΑͶ  ‣ 999#BTF͍ͬͯ͏ந৅ΫϥεΛఆٛͨ͜͠ͱ͋Δਓ ‣ 3BJMT͔ͩΒͰ͖Δ͜ͱɻ

      3BJMT͸ϛϥΫϧ
  32. ϝιουʹநग़͠ɺࣗ෼Ͱݺͼग़͢  

  33. ‣ Ұ࿈ͷΦϒδΣΫτάϥϑΛ࡞Δϝιο υʹநग़͠ɺ࡞Γ͍ͨଆ͕ݺͼग़͢ɻ ‣ ࠩ෼ΛҾ਺Ͱ༩͑ͭͭɺ ‣ ΊͬͪΌී௨ͷ͜ͱΛݴͬͯ·͢ ϝιουʹநग़͠ɺࣗ෼Ͱݺͼग़͢  

  34.   let!(:article) { create(:article, author: author } # ...͜ͷؒ

    30ߦ... context ';ͭ͏ͷϢʔβʔͷهࣄ͸Ұཡදࣔର৅' do let(:author) { create(:author) } it { expect(Article.indexable).to include(article) } context 'ୀձͨ͠Ϣʔβʔͷهࣄ͸Ұཡදࣔର৅֎' do let(:author) { create(:author, retired_at: Time.now) } it { expect(Article.indexable).not_to include(article) }
  35.   def article_by(user) create(:article, author: author) end context ';ͭ͏ͷϢʔβʔ'

    do let(:article) { article_by(create(:user)) } it { expect(Article.indexable).to include(article) } context 'ୀձͨ͠Ϣʔβʔ' do let(:article) { article_by(:author, retired_at: Time.now) } it { expect(Article.indexable).not_to include(article) }
  36. ‣ BVUIPSVTFS͕Ͳ͏࡞ΒΕͲ͏࢖ΘΕΔ͔ɺॱΛ௥ͬ ͯಡΊΔɻ ‣ ϔϧύʔϝιου͕େ͖͘ͳΔଟ͘ͳΓ͗͢Δ
 ଞͷϑΝΠϧ͔Β΋࢖͍͍ͨ৔߹͸ɺී௨ʹ
 ίʔυΛ෼ׂ͢ΔͱΑ͍ɻ ‣ কདྷɺςετίʔυΛॻ͘ਓ͕ɺ࢖͍ํΛࣗ෼Ͱ
 ܾΊΒΕΔɻ

     
  37. ҧ͏ॲཧΛڬΈࠐΉͨΊʹ ετϥςδʔύλʔϯΛ࢖͏  

  38. ‣ ڞ௨ͷલॲཧΛͯ͠ɺຊॲཧͯ͠ɺڞ௨ͷޙॲཧ͕
 ͋Δ৔߹ͳͲɻ ‣ ͞Βʹຊॲཧͷྫ֎ॲཧ΋ඞཁͳ৔߹ͳΜ͔͸৑௕ʹͳΓ͕ͪɻ ‣ ͜ͷຊॲཧ͚ͩΛม͍͑ͨɻ ‣ ςϯϓϨʔτϝιου࢖͍ͨ͘ͳΓ͕ͪɻ ϝιουͷҰ෦͚ͩม͍͑ͨ৔߹͕͋Δ

     
  39.   class TwitterNotification < BaseNotification private def before_request authorize(@article.author)

    def request @user = article.author.access_token ... def after_request nil class BaseNotification def notify(article) @article = article before_request request after_request private def request raise NotImplementedError
  40. ετϥςδʔύλʔϯΛ࢖͏  

  41. ‣ Ұ෦͚ͩม͍͑ͨॲཧΛɺετϥς δʔΦϒδΣΫτͷ஫ೖͰදݱ͢Δɻ ετϥςδʔύλʔϯΛ࢖͏  

  42.   class TwitterNotification < BaseNotification private def before_request authorize(@article.author)

    def request @user = article.author.access_token ... def after_request nil class BaseNotification def notify(article) @article = article before_request request after_request private def request raise NotImplementedError
  43.   class SnsNotification def notify(article) #=> [TwitterNotification.new, FacebookNotofication.new...] SnsNotification.targets.each

    do |sns| sns.notify(article)
  44. ‣ ݺͼग़͢γʔέϯε͕ࣗ໌ʹͳΔɻ ‣ ݺ͹ΕΔݸʑͷετϥςδʔଆ΋ΠϯλʔϑΣʔε ͕͸͖ͬΓ͢Δɻ ‣ ৼΔ෣͍ʹӨڹΛ༩͑Δύϥϝʔλ͕໌֬ʹͳΔͷͰɺςετ΋͠΍͍͢ ‣ ݺͼग़͠ݩείʔϓʹΞΫηεͰ͖ͳ͍ ‣

    CJOEJOH@PG@DBMMFSͷ͜ͱ͸๨ΕΑ͏  
  45. lͪΐͬͱҧ͏ॲཧzΛ
 ϒϩοΫͱͯ͠ड͚औΔ  

  46. “ EPFOE·ͨ͸\^Ͱғ·Εͨίʔυͷஅย ϒ ϩοΫͱݺ͹ΕΔ ΛޙΖʹ෇͚ͯϝιουΛݺͼग़ ͢ͱɺͦͷϝιουͷ಺෦͔ΒϒϩοΫΛධՁͰ͖ ·͢ɻ
 ϒϩοΫ෇͖ϝιουΛࣗ෼Ͱఆٛ͢Δʹ͸ZJFME ࣜΛ࢖͍·͢ɻ

  47. ‣ ॲཧΛΦϒδΣΫτͱͯ͠ந৅Խͨ͠΋ͷɻ ‣ 3VCZͷಛ௃ਓؾϙΠϯτͷͭ ‣ ͍ΘΏΔʮߴ֊ؔ਺ʯ ‣ DBMMͰॲཧΛݺͼग़͢ɻ ϒϩοΫ 

    
  48. ‣ ;ͭ͏ͷ܁Γฦ͠ ‣ .PEFMBMMFBDIEPFOE ‣ ॲཧͷڥք ‣ .PEFMUBOTBDUJPOEPFOE ‣ %4-

    ‣ 3BJMTBQQMJDBUJPOSPVUFTESBXEPFOE ‣ 34QFDͷMFU 3BJMTΞϓϦʹ͓͚ΔϒϩοΫ  
  49. ‣ ϥΠϒϥϦ੍͕ޚߏ଄Λࢦఆ͍ͯ͠Δ ‣ ݺͼग़͠ଆͷ۩ମతͳॲཧࣗମΛϒϩοΫͱͯ͠ड͚ɺ
 ϥΠϒϥϦϑϨʔϜϫʔΫͰ४උ্ͨ͠Ͱݺͼग़͢ɻ ‣ Ͱ΋ɺऔΒΕͨؾ͕͠ͳ͍ ‣ FBDI΍USBOTBDUJPO͸ී௨ʹಡΊΔ ϒϩοΫΛΑ͘ݟͯΈΔͱ

     
  50.   model.transaction do model1.save! model2.save! end ྫ

  51.   module Transactionable def transaction do_begin do_something do_commit rescue

    do_rollback class Model include Transactionable private def do_something model1.save! model2.save! NJYJOͰॻ͍ͯΈΔ
  52.   class MyModel < AbstractModel private def do_something model1.save!

    model2.save! ςϯϓϨʔτϝιουͰॻ͍ͯΈΔ class AbstractModel def transaction do_begin do_something do_commit rescue do_rollback private def do_something raise NotImplementedError
  53.   class SaveStrategy def initialize(*models) def do_something @models.each(&:save!) ...

    s = SaveStrategy.new( model1, model2 ) model.transaction(s) ετϥςδʔͰॻ͍ͯΈΔ class Model def transaction(strategy) do_begin strategy.do_something do_commit rescue do_rollback
  54.   class Model def transaction(&strategy) do_begin strategy.call # or

    yield do_commit rescue do_rollback ϒϩοΫΛड͚෇͚Δ model.transaction do model1.save! model2.save!
  55. ‣ DBMMΛڞ௨ΠϯλʔϑΣʔεͱͨ͠ετϥςδʔͱ ΋ݴ͑Δɻ ‣ ͍ΘΏΔDBMMBCMFPCKFDU ‣ ϒϩοΫΛ࢖͏ͱɺΞϓϦέʔγϣϯίʔυͷಡΈ खͷίϯςΩετ͕ܧଓ͢Δɻ ‣ CJOEJOHQSZΛೖΕΔͱ͜Ζ͕ࣗ໌

    ϒϩοΫͱετϥςδʔ  
  56.   class MyModel < AbstractModel private def do_something model1.save!

    model2.save! ྫEP@TPNFUIJOH͕ݺ͹Εͯͳͦ͞͏ͳͱ͖Ͳ͏͢Δ class AbstractModel def transaction do_begin do_something do_commit rescue do_rollback private def do_something raise NotImplementedError
  57. ‣ ϒϩοΫΛड͚෇͚Δͱɺʮͪΐͬͱҧ͏ॲཧ Λࠩ͠ࠐ·͍ͤͨʯͱ͖ʹͷ੍ޚߏ଄Λݺͼग़ ͠ଆʹҕͶ͍ͯΔΑ͏ʹݟͤΒΕΔɻ ‣ ͦ͏͍͏ؾ࣋ͪͰ࢖͑Δͷ͕େࣄɻ ‣ 3VCZͬΆ͍ίʔυʹ΋ͳΔɻ  

  58. ‣ ͳͥϑϨʔϜϫʔΫʹ͠ͳ͍΄͏͕Α͍͔ ‣ ϑϨʔϜϫʔΫΛ࡞Βͳ͍ํ๏ ‣ ςϯϓϨʔτϝιουΛආ͚ͯ;ͭ͏ʹϝιουʹநग़͢Δ ‣ ςϯϓϨʔτϝιουΑΓ΋ετϥςδʔͰ֦ுͤ͞Δ ‣ lͪΐͬͱҧ͏ॲཧzΛදݱ͢ΔͨΊʹϒϩοΫΛड͚෇͚Δ

    ‣ ·ͱΊ੍ޚߏ଄Λ࢖͍खʹҕͶΔ
  59. ·ͱΊ
 ੍ޚߏ଄Λ
 ࢖͍खʹҕͶΔ

  60. ‣ ศརϥΠϒϥϦ͕ศརͳͷ͸ؒҧ͍ͳ͍ɻ ‣ ੍ޚߏ଄Λͯ͠͠ͳͯ͘΋ɺศརϝιουΛఏڙ͢Δͷ͕े෼ศར ‣ ʮͪΐͬͱҧ͏ॲཧʯ͸ετϥςδʔͰදݱ͢Δɻ ‣ ܧঝͤͯ͞ݺͼग़͢ॲཧ͚ͩΛॻ͔ͤͳ͍ ‣ ϒϩοΫ͍͍Ϡπɻੵۃతʹ׆༻͠·͠ΐ͏ɻ

    ‣ 3VCZ͍͍ΑͶ ϥΠϒϥϦίʔυͱΞϓϦίʔυΛૄʹอͭ  
  61. ‣ ϔϧύʔϝιουΛɺετϥςδʔύλʔϯΛɺϒϩοΫΛ ࢖͑͹Α͍Θ͚Ͱ͸ͳ͍ɻ ‣ 'PP'SBNFXPSLOBOUPLB@QSPD DPOUFYU \^Έ͍ͨͳ ‣ ͍ͭɺͲ͏ݺ͹ΕΔͷ 

    ‣ ʮࠓ͜ͷศརϥΠϒϥϦΛॻ͍ͯΔࣗ෼͸ɺͦΕ͕
 Ͳ͏࢖ΘΕΔ͔·ͩ஌Βͳ͍ʯͱ͍͏ؾ࣋ͪʹ޲͖߹͏ɻ )PXʹ͍ͭͯ࿩͠·͕ͨ͠  
  62. ‣ ·ͩݟ͵ΞϓϦέʔγϣϯίʔυʹɺඞཁҎ্ͷ
 ੍໿Λ՝͞ͳ͍Α͏ʹ͢Δɻ ‣ ΞϓϦέʔγϣϯͰԿΛ͍͔ͨ͠͸ɺͦͷͱ͖ʹͳΒͳ͍ͱΘ͔Βͳ͍ɻ ‣ ͦͷ࣌ɺͦͷਓୡ͕ɺ޲͖߹͑Δ༨஍Λ࢒͢ɻ ‣ ۩ମతͳ໰୊ʹ޲͖߹͍ͬͯΔਓΛϦεϖΫτɻະདྷͷࣗ෼͔΋ ੍ޚߏ଄Λ࢖͍खʹҕͶΔ