Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
フレームワークを作らない方法/How NOT to build frameworks
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
MOROHASHI Kyosuke
June 21, 2019
Programming
1.3k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
フレームワークを作らない方法/How NOT to build frameworks
銀座Rails#10での発表資料です
MOROHASHI Kyosuke
June 21, 2019
More Decks by MOROHASHI Kyosuke
See All by MOROHASHI Kyosuke
Railsの気持ちを考えながらコントローラとビューを整頓する/tidying-rails-controllers-and-views-as-rails-think
moro
5
520
dynamic!
moro
11
22k
Identifying User Idenity
moro
23
30k
Simplicity on Rails -- RDB, REST and Ruby
moro
18
21k
ちょうどよい Rails E2E テスト/enough-good-rails-e2e-test
moro
6
2.7k
全体がいい感じになるために、私たちRailsをホームにするWeb技術者ができること/let-our-whole-system-grow
moro
2
2k
フォームオブジェクトとの向き合い方/Grow Form Objects up
moro
1
2.2k
チームによるいきいきとしたソフトウェア開発/an-alive-team-grows-software
moro
3
3.5k
Web-E2E-Testing-from-Ruby
moro
5
660
Other Decks in Programming
See All in Programming
アルゴリズムは何を圧縮しているのか ─ Haskell から育った「圧縮代数」というメンタルモデル
naoya
16
3.9k
【SRE NEXT 2026 Lunch Session】一人目専任SREの立ち上げを加速する ― AIと進めたオンボーディングで2分を0.04秒にした話
pkshadeck
PRO
0
3.5k
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
150
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
470
仕様書を書く前にハーネスを作る - Agent Native開発は「探索を速く、判定を固く」
gotalab555
4
1.6k
FDEが実現するAI駆動経営の現在地
gonta
2
270
AIが無かった頃の素敵な出会いの話
codmoninc
1
390
Japan Community Day at Kubecon + CloudNativeCon Japan 2026: Learning Container Privilege Control by Building My Own Low-Level Container Runtime
ternbusty
1
140
<title><a id="</title>君はこのHTMLをパースできるか"></a></title> #雑LT_study
pizzacat83
0
140
ここ半年くらいでAIに作らせたR用ツール
eitsupi
0
370
これって Effect でできたのでは? / TSKaigi Mashup Kansai #2
susisu
0
150
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
160
Featured
See All Featured
Code Reviewing Like a Champion
maltzj
528
40k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.5k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.8k
A Modern Web Designer's Workflow
chriscoyier
698
190k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.7k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
240
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
460
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
66
57k
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
160
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
330
Transcript
ϑϨʔϜϫʔΫΛ ࡞Βͳ͍ํ๏ )PX/05UPCVJMEGSBNFXPSLT 2019-06-21 ۜ࠲Rails#10 ॾڮګհ @moro
‣ ࣸਅ
Kyosuke MOROHASHI @moro
!5 SMS? What's SMSってなにをやってる会社なの?
https://twitter.com/sunaot/status/1002392476492038144
“ 情報インフラを構築することで、⾼齢社会を 取り巻く⼈びと、⾼齢社会で働く⽅や事業者の⽅、 ⾼齢者ご⾃⾝やそのご家族などがイキイキと ⽣活できる社会の実現を⽬指しています。 — https://www.bm-sms.co.jp/philosophy/
!8 &
吳䒭⠓爡ؒأ ٥ ؒي ٥ ؒأ 匌❨鿪庥⼒蓎Ⱅ㕦⡝♶⹛欵蓎Ⱅ㕦ةٙ٦ https://www.bm-sms.co.jp ؒٝآص،䱰欽؟؎ ز https://careers.bm-sms.co.jp/engineer/
join us!
͜Ε·Ͱͷ͋Β͢͡
‣ ͳͥϑϨʔϜϫʔΫʹ͠ͳ͍΄͏͕Α͍͔ ‣ ϑϨʔϜϫʔΫΛ࡞Βͳ͍ํ๏ ‣ ςϯϓϨʔτϝιουΛආ͚ͯ;ͭ͏ʹϝιουʹநग़͢Δ ‣ ςϯϓϨʔτϝιουΑΓετϥςδʔͰ֦ுͤ͞Δ ‣ lͪΐͬͱҧ͏ॲཧzΛදݱ͢ΔͨΊʹϒϩοΫΛड͚͚Δ
‣ ·ͱΊ੍ޚߏΛ͍खʹҕͶΔ
ͳͥ ϑϨʔϜϫʔΫʹ͠ͳ͍ ΄͏͕Α͍͔
ϥΠϒϥϦͱ ϑϨʔϜϫʔΫ
“ ͔͠͠ɺϥΠϒϥϦͰݺͼग़͠ଆ͕ϓϩάϥϜશ ମͷ੍ޚߏΛࢦఆͰ͖ͳ͍͕ɺϑϨʔϜϫʔΫͰ ՄೳͰ͋Δɻ͜ͷ੍ޚͷస͕ιϑτΣΞϑ ϨʔϜϫʔΫͷಛͰ͋Δɻ https://ja.wikipedia.org/wiki/ιϑτΣΞϑϨʔϜϫʔΫ
‣ ʮར༻ऀ͕ݺͼग़͢ʯͷ͕ϥΠϒϥϦ ‣ ʮར༻ऀ ͷίʔυ Λݺͼग़͢ʯͷ͕ϑϨʔϜϫʔΫ ϑϨʔϜϫʔΫ੍ޚߏΛࢦఆ͢Δ
‣ ͖ͬΓͱനࠇ͚ͭΒΕΔΘ͚Ͱͳ͍ɻ ‣ ར༻ऀͨΔΞϓϦ։ൃऀ͕ݺͼग़͢"DUJWF3FDPSE Ϟσϧʹఆٛͨ͠ίʔϧόοΫ"DUJWF3FDPSE͕ݺͼग़ͧ͢ʜ ‣ ར༻ऀ͕ॻ͘ίʔυͷ੍ޚߏΛͲΕ΄Ͳࢦఆ ͢Δ͔͠ͳ͍͔ɻ ˞۠ผ߹͍
‣ ϑϨʔϜϫʔΫɺͦͷ্Ͱͷ׆ಈΛ੍͢Δɻ ‣ ͍ΘΏΔʮϨʔϧ͔Β߱Γ͍ͨʯ ‣ ඞͣ͠ѱ͍Θ͚Ͱͳ͍ʮ੍͕ࣗ༝ΛͨΒ͢ʯ ‣ ʮͦͷ্Ͱͷ׆ಈʯ༧ଌͰ͖ͳ͍ɻ ‣ ͍͍ͨͯநԽ͕࿙ΕΔɻ
‣ ࡞ऀͷؾ࣋ͪΛߟ͑Α͏ͱͯ͠࡞ऀߟ͑ͯͳ͍͜ͱɻ ͳͥϑϨʔϜϫʔΫʹ͠ͳ͍΄͏͕ྑ͍͔
‣ ಡΈղ͘ͷʹϝλϓϩάϥϛϯάͷ͕ࣝඞཁʹͳΔ͜ͱଟ͍ɻ ‣ ϝλϓϩάϥϛϯάֶशۂઢ ίʔυࣗମ͕͘͠ͳΓ͕ͪ https://www.martinfowler.com/articles/rubyAtThoughtWorks.html
‣ ଟ͘ͷ"1*ͱͦͷ͍ํΛֶश͢Δඞཁ͋Γɻ ‣ ࡞ऀͷؾ࣋ͪΛߟ͑ͯΞϓϦέʔγϣϯίʔυ Λॻ͘ɻ ϑϨʔϜϫʔΫࣗମֶशίετ͕͔͔Δ
‣ 3VCZͰ8FCΞϓϦ։ൃ͢Δͱ͖ͷυఆ൪ͱͯ͠ ϝΠϯετϦʔϜʹ͍Δɻ ‣ ৭Μͳ༻్ͷʮݸผࣄʯΛίϯτϦϏϡʔτ͞Ε ଓ͚͖ͯͨɻ ‣ ʮϨʔϧͷ߱ΓํʯͳΜͯͷ·ͰؚΊͯେͳ ϊϋ͕ੵ͞Ε͍ͯΔɻ
3BJMTϛϥΫϧ
‣ ࣗࣗΛؚΉ ະདྷͷϝϯςφʹର੍͠͠ͳ͍ɻ ‣ ະདྷʹͲ͏͍͏ιϑτΣΞʹ͍͔ͨ͠Θ͔Βͳ͍ɻ ‣ େମʹ͓͍ͯߟྀෆ͠நԽ࿙ΕΔɻ ‣ ϥΠϒϥϦʹ͓ͯ͘͠ͱɺݺͿݺͳ͍ɺ ͏ݺͳ͘͢Δɺͷར༻ऀ͕ܾΊΒΕΔɻ
ʮ;ͩΜʯϑϨʔϜϫʔΫʹ͢ΔͷΛආ͚Δ
ͱ͍͑ɺ ศརϝιουΛॻ͖ͨ͘ͳΔ͜ͱ ͨ͘͞Μ͋ΔΘ͚Ͱ
‣ ͳͥϑϨʔϜϫʔΫʹ͠ͳ͍΄͏͕Α͍͔ ‣ ϑϨʔϜϫʔΫΛ࡞Βͳ͍ํ๏ ‣ ςϯϓϨʔτϝιουΛආ͚ͯ;ͭ͏ʹϝιουʹநग़͢Δ ‣ ςϯϓϨʔτϝιουΑΓετϥςδʔͰ֦ுͤ͞Δ ‣ lͪΐͬͱҧ͏ॲཧzΛදݱ͢ΔͨΊʹϒϩοΫΛड͚͚Δ
‣ ·ͱΊ੍ޚߏΛ͍खʹҕͶΔ
ϑϨʔϜϫʔΫΛ ࡞Βͳ͍ํ๏
ݴ͍͑Δͱ ੍ޚߏΛ ͍खʹҕͶΔํ๏
ςϯϓϨʔτϝιουΛආ͚ͯ ;ͭ͏ʹϝιουʹநग़͢Δ
‣ ΦʔόʔϥΠυ͞ΕͯΔϝιουΛΈଆ͕ݺͿɻ ݺΕΔଆ͔Βߏ͕ݟ͑ͳ͍ɻ ‣ 34QFDͷMFUTVCKFDUಉࠜͰ͋Δͱݴ͑Δɻ ‣ ۩ςετέʔε͔ΒΕͨʮϑΝΠϧͷ্ͷํʯʹ ߏ͕Ͱ͖ΔͷͰɺݟ͑ͳ͍͠ɺม͑ͮΒ͍ɻ ςϯϓϨʔτϝιουύλʔϯͷ
‣ ܧঝͯ͠͠·͏ͷͰɺϑϨʔϜϫʔΫͷ෦ߏΛ ࡽͯ͠͠·͏ɻ ‣ ͞ΘΓͨ͘ͳΔΑͶ ‣ ͦͯ͠όʔδϣϯΞοϓͰ͖ͳ͘ͳΔ ‣ 3BJMTΞϓϦ͋Δ͋Δɻ ςϯϓϨʔτϝιουύλʔϯͷ
‣ 3BJMTࣗମ͕ϥΠϒϥϦఏڙΫϥεΛܧঝͯ͠͏ ϑϨʔϜϫʔΫͳͷͰɺࣗͰͦ͏ॻ͖ͨ͘ͳΔɻ ‣ ʜΑͶ ‣ 999#BTF͍ͬͯ͏நΫϥεΛఆٛͨ͜͠ͱ͋Δਓ ‣ 3BJMT͔ͩΒͰ͖Δ͜ͱɻ
3BJMTϛϥΫϧ
ϝιουʹநग़͠ɺࣗͰݺͼग़͢
‣ Ұ࿈ͷΦϒδΣΫτάϥϑΛ࡞Δϝιο υʹநग़͠ɺ࡞Γ͍ͨଆ͕ݺͼग़͢ɻ ‣ ࠩΛҾͰ༩͑ͭͭɺ ‣ ΊͬͪΌී௨ͷ͜ͱΛݴͬͯ·͢ ϝιουʹநग़͠ɺࣗͰݺͼग़͢
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) }
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) }
‣ BVUIPSVTFS͕Ͳ͏࡞ΒΕͲ͏ΘΕΔ͔ɺॱΛͬ ͯಡΊΔɻ ‣ ϔϧύʔϝιου͕େ͖͘ͳΔଟ͘ͳΓ͗͢Δ ଞͷϑΝΠϧ͔Β͍͍ͨ߹ɺී௨ʹ ίʔυΛׂ͢ΔͱΑ͍ɻ ‣ কདྷɺςετίʔυΛॻ͘ਓ͕ɺ͍ํΛࣗͰ ܾΊΒΕΔɻ
ҧ͏ॲཧΛڬΈࠐΉͨΊʹ ετϥςδʔύλʔϯΛ͏
‣ ڞ௨ͷલॲཧΛͯ͠ɺຊॲཧͯ͠ɺڞ௨ͷޙॲཧ͕ ͋Δ߹ͳͲɻ ‣ ͞Βʹຊॲཧͷྫ֎ॲཧඞཁͳ߹ͳΜ͔ʹͳΓ͕ͪɻ ‣ ͜ͷຊॲཧ͚ͩΛม͍͑ͨɻ ‣ ςϯϓϨʔτϝιου͍ͨ͘ͳΓ͕ͪɻ ϝιουͷҰ෦͚ͩม͍͑ͨ߹͕͋Δ
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
ετϥςδʔύλʔϯΛ͏
‣ Ұ෦͚ͩม͍͑ͨॲཧΛɺετϥς δʔΦϒδΣΫτͷೖͰදݱ͢Δɻ ετϥςδʔύλʔϯΛ͏
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
class SnsNotification def notify(article) #=> [TwitterNotification.new, FacebookNotofication.new...] SnsNotification.targets.each
do |sns| sns.notify(article)
‣ ݺͼग़͢γʔέϯε͕ࣗ໌ʹͳΔɻ ‣ ݺΕΔݸʑͷετϥςδʔଆΠϯλʔϑΣʔε ͕͖ͬΓ͢Δɻ ‣ ৼΔ͍ʹӨڹΛ༩͑Δύϥϝʔλ͕໌֬ʹͳΔͷͰɺςετ͍͢͠ ‣ ݺͼग़͠ݩείʔϓʹΞΫηεͰ͖ͳ͍ ‣
CJOEJOH@PG@DBMMFSͷ͜ͱΕΑ͏
lͪΐͬͱҧ͏ॲཧzΛ ϒϩοΫͱͯ͠ड͚औΔ
“ EPFOE·ͨ\^Ͱғ·Εͨίʔυͷஅย ϒ ϩοΫͱݺΕΔ ΛޙΖʹ͚ͯϝιουΛݺͼग़ ͢ͱɺͦͷϝιουͷ෦͔ΒϒϩοΫΛධՁͰ͖ ·͢ɻ ϒϩοΫ͖ϝιουΛࣗͰఆٛ͢ΔʹZJFME ࣜΛ͍·͢ɻ
‣ ॲཧΛΦϒδΣΫτͱͯ͠நԽͨ͠ͷɻ ‣ 3VCZͷಛਓؾϙΠϯτͷͭ ‣ ͍ΘΏΔʮߴ֊ؔʯ ‣ DBMMͰॲཧΛݺͼग़͢ɻ ϒϩοΫ
‣ ;ͭ͏ͷ܁Γฦ͠ ‣ .PEFMBMMFBDIEPFOE ‣ ॲཧͷڥք ‣ .PEFMUBOTBDUJPOEPFOE ‣ %4-
‣ 3BJMTBQQMJDBUJPOSPVUFTESBXEPFOE ‣ 34QFDͷMFU 3BJMTΞϓϦʹ͓͚ΔϒϩοΫ
‣ ϥΠϒϥϦ੍͕ޚߏΛࢦఆ͍ͯ͠Δ ‣ ݺͼग़͠ଆͷ۩ମతͳॲཧࣗମΛϒϩοΫͱͯ͠ड͚ɺ ϥΠϒϥϦϑϨʔϜϫʔΫͰ४උ্ͨ͠Ͱݺͼग़͢ɻ ‣ ͰɺऔΒΕͨؾ͕͠ͳ͍ ‣ FBDIUSBOTBDUJPOී௨ʹಡΊΔ ϒϩοΫΛΑ͘ݟͯΈΔͱ
model.transaction do model1.save! model2.save! end ྫ
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Ͱॻ͍ͯΈΔ
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
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
class Model def transaction(&strategy) do_begin strategy.call # or
yield do_commit rescue do_rollback ϒϩοΫΛड͚͚Δ model.transaction do model1.save! model2.save!
‣ DBMMΛڞ௨ΠϯλʔϑΣʔεͱͨ͠ετϥςδʔͱ ݴ͑Δɻ ‣ ͍ΘΏΔDBMMBCMFPCKFDU ‣ ϒϩοΫΛ͏ͱɺΞϓϦέʔγϣϯίʔυͷಡΈ खͷίϯςΩετ͕ܧଓ͢Δɻ ‣ CJOEJOHQSZΛೖΕΔͱ͜Ζ͕ࣗ໌
ϒϩοΫͱετϥςδʔ
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
‣ ϒϩοΫΛड͚͚Δͱɺʮͪΐͬͱҧ͏ॲཧ Λࠩ͠ࠐ·͍ͤͨʯͱ͖ʹͷ੍ޚߏΛݺͼग़ ͠ଆʹҕͶ͍ͯΔΑ͏ʹݟͤΒΕΔɻ ‣ ͦ͏͍͏ؾ࣋ͪͰ͑Δͷ͕େࣄɻ ‣ 3VCZͬΆ͍ίʔυʹͳΔɻ
‣ ͳͥϑϨʔϜϫʔΫʹ͠ͳ͍΄͏͕Α͍͔ ‣ ϑϨʔϜϫʔΫΛ࡞Βͳ͍ํ๏ ‣ ςϯϓϨʔτϝιουΛආ͚ͯ;ͭ͏ʹϝιουʹநग़͢Δ ‣ ςϯϓϨʔτϝιουΑΓετϥςδʔͰ֦ுͤ͞Δ ‣ lͪΐͬͱҧ͏ॲཧzΛදݱ͢ΔͨΊʹϒϩοΫΛड͚͚Δ
‣ ·ͱΊ੍ޚߏΛ͍खʹҕͶΔ
·ͱΊ ੍ޚߏΛ ͍खʹҕͶΔ
‣ ศརϥΠϒϥϦ͕ศརͳͷؒҧ͍ͳ͍ɻ ‣ ੍ޚߏΛͯ͠͠ͳͯ͘ɺศརϝιουΛఏڙ͢Δͷ͕ेศར ‣ ʮͪΐͬͱҧ͏ॲཧʯετϥςδʔͰදݱ͢Δɻ ‣ ܧঝͤͯ͞ݺͼग़͢ॲཧ͚ͩΛॻ͔ͤͳ͍ ‣ ϒϩοΫ͍͍Ϡπɻੵۃతʹ׆༻͠·͠ΐ͏ɻ
‣ 3VCZ͍͍ΑͶ ϥΠϒϥϦίʔυͱΞϓϦίʔυΛૄʹอͭ
‣ ϔϧύʔϝιουΛɺετϥςδʔύλʔϯΛɺϒϩοΫΛ ͑Α͍Θ͚Ͱͳ͍ɻ ‣ 'PP'SBNFXPSLOBOUPLB@QSPD DPOUFYU \^Έ͍ͨͳ ‣ ͍ͭɺͲ͏ݺΕΔͷ
‣ ʮࠓ͜ͷศརϥΠϒϥϦΛॻ͍ͯΔࣗɺͦΕ͕ Ͳ͏ΘΕΔ͔·ͩΒͳ͍ʯͱ͍͏ؾ࣋ͪʹ͖߹͏ɻ )PXʹ͍ͭͯ͠·͕ͨ͠
‣ ·ͩݟ͵ΞϓϦέʔγϣϯίʔυʹɺඞཁҎ্ͷ ੍Λ՝͞ͳ͍Α͏ʹ͢Δɻ ‣ ΞϓϦέʔγϣϯͰԿΛ͍͔ͨ͠ɺͦͷͱ͖ʹͳΒͳ͍ͱΘ͔Βͳ͍ɻ ‣ ͦͷ࣌ɺͦͷਓୡ͕ɺ͖߹͑Δ༨Λ͢ɻ ‣ ۩ମతͳʹ͖߹͍ͬͯΔਓΛϦεϖΫτɻະདྷͷ͔ࣗ ੍ޚߏΛ͍खʹҕͶΔ