Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Goでやや大きいプロダクトのアーキテクチャを検討したり実装したりしたおはなし
Search
yami20
July 17, 2020
Technology
830
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Goでやや大きいプロダクトのアーキテクチャを検討したり実装したりしたおはなし
yami20
July 17, 2020
Other Decks in Technology
See All in Technology
Deploying a Full-Stack Bun-Native Framework on Cloudflare Workers
7nohe
0
130
生成AIのテナント制御とシャドーMCP対策 | AIを"止めずに"、情報を守る
yukun
0
140
こんなアーキテクチャ図は嫌だ BEYOND THE TIME: 半年後の自分へ贈る15のメッセージ / 15 of Anti-pattern in AWS Architecture Diagrams
naospon
3
300
TinyGo 開発サイクルを高速化する:Go で作るエミュレータ入門
zozotech
PRO
1
600
OpenTelemetryのメトリクスをCloudWatchに送ってPromQLで見てみた
ota1022
0
120
Snowflakeで実現する全社横断の顧客の声(VOC)分析・活用基盤@Snowflake World Tour Tokyo 2026
yuto16
0
160
Amazon Quick on DesktopがIAM Identity Centerで動かない理由
yukiogawa
0
150
【視聴者参加型!】AWSセキュリティアンチパターンクイズ
syoshie
1
490
プロダクト思考 × 基盤思考を AIで実現する Compound Engineering
tkc66buzz
1
310
日経電子版を支えていく Kasane Design System/fec_fukuoka
nikkei_engineer_recruiting
0
660
コーディングエージェントでM5Stack系の開発を少し試した時の話 / M5 Japan Tour 2026 Autumn 東京
you
PRO
0
140
The Agent Builder Loop from Daily Work to OSS
minorun365
PRO
3
120
Featured
See All Featured
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.3k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
520
Done Done
chrislema
186
16k
Music & Morning Musume
bryan
47
7.4k
Are puppies a ranking factor?
jonoalderson
2
3.9k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
202
76k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
230
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
ラッコキーワード サービス紹介資料
rakko
1
4.8M
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
660
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
270
Transcript
GoͰେ͖͍ϓϩμΫτͷ ΞʔΩςΫνϟΛݕ౼ͨ͠Γ࣮ͨ͠Γͨ͠ ͓ͳ͠ Remote.go#1 2020.07.17 @yami20
ͩΕʁ • @yami20 (ΠϯλʔωοτҾ͖͜ΓͳͷͰಛʹใग़ͯ͜ͳ͍Ͱ͢) • Engineer@Finatext • อݥࣄۀͰαʔόʔαΠυ։ൃ • Go1.6?1.7?͋ͨΓͰͪΐͬͱ͞ΘͬͯΕ͍ͯͨ
• ڈͷΕ͔Β·ͨ৮Γ࢝Ίͨͱ͜Ζ • ͜ͷձͷλΠτϧʹʮ্ڃऀ͚ʯͱ͔ॻ͔ΕͯͯŜƄŞŲƄſͯ͠·͢
͖ΐ͏͓ͳ͢͠Δ͜ͱ • ͦͦ͜͜େ͖͍ɾෳࡶͳϓϩμΫτΛGoͰͭ͘Γ·ͨ͠ɻ • ࣮ΞʔΩςΫνϟͷબఆtipsΛɺͦͷҙਤΛ৫Γަͥͳ͕Β͓ ͯ͠ΈΑ͏ͱࢥ͍·͢ɻ
ͦͷ͜͜Ζʁ • ʮ͖Ε͍ͳͷ͜͏͍͏࣮ͩʯͱ͍͏ใͨ͘͞Μ͋Δɻ • ͖Ε͍ͳ࣮Λ͍ٻΊଓ͚Δ͜ͱ͕࣮ʹ͓͍ͯ࠷దղͰͳ͍ɻ • ʮ͋Δ࣮ʹΑͬͯͲͷ༷ͳ՝͕ղܾ͞ΕΔ͔ʯͱ͍͏༗ػతͳͭͳ͕ Γɺԡ͑͞Δ͖ϙΠϯτ/ࣺͯͯΑ͍ϙΠϯτΛڞ༗͢Δ͜ͱͰɺΑΓ Α͍࣮Λࢦ͢ਓʑͷࢀߟʹͳΕ͍͍ͳ͊ɻ
͓ͳ͠͠ͳ͍͜ͱ ͘͢͝৽͍͠ใɺΠέΠέͳ࣮ग़͖ͯ·ͤΜɻ ޠΓਚ͘͞ΕͨثͨͪΛखʹɺଥͳ࣮Λࢦ͓͢ͳ͠Ͱ͢ɻ
ຊ
ཁ݅ɾنɾಛੑ ʙอݥϓϥοτϑΥʔϜγεςϜʙ •(͜ͷลࢀߟఔʹॻ͍͚ͨͩͳͷͰඈ͠·͢) • ཁ݅ • APIαʔόʔ(SPAͷbackend) • ͪͳΈʹରʹͳΔfrontendͷͳ͠ https://speakerdeck.com/slont/bokufalsekangaetasaikiyoufalsevueakitekutiya
• ෳͷอݥձ͕ࣾΛઃܭɾొ͠ɺސ٬ͷਃࠐΛड͚͚ͨΓɺܖ৹ࠪͨ͠Γཧͨ͠Γɺͦͷଞਵ͢Δػೳ͕ʹΐʹΐɻ • ن • ΞυςΫήʔϜʹൺΔͱτϥϑΟοΫ֨ஈʹ͓ͱͳ͍͠ɻ1ਓ͕1ʹԿेճՃೖͨ͠Γ͠ͳ͍͠ɺ࿈ଧͯ͢͠ఢ͍ͳ͍ɻ • PFͰ͋Δ͜ͱΛ౿·͑ͯҰൠతͳECͱ͔ͷنײΛΠϝʔδ͍͚ͯͨͩ͠Εɻ • ಛੑ • σʔλͷϥΠϑαΠΫϧ͕͍ɻ୯Ґ͕جຊɺਓੜ୯ҐͷऔҾ͋Δ • σʔλͷߏ͕ෳࡶ. ଐੑϦϨʔγϣϯͱʹ͔͘ଟ͍. • γεςϜͷण໋͕͍ɻσʔλͷϥΠϑαΠΫϧ͕͍ͷ͋Δ͠ɺPFͳͷͰ͓͍ͦΕͱด͡ΒΕͳ͍ͱ͍͏ͷ͋Δɻ • PFͰ͋ΔͨΊɺॳظʹग़Δཁ͕݅ͯ͢ͱݶΒͳ͍ • ࢥ͍ΑΒͳ͍֦ு͕ඞཁʹͳΔՄೳੑ͕͋Δ
࠾༻ͨ͠ߏ • ϞϊϦε • શʹ୯ҰγεςϜͱ͍͏Θ͚Ͱͳ͍Ͱ͕͢ɻ • ໌Β͔ʹੑ࣭ͷҟͳΔ෦͕ͨ͠ɺAPIेຊͷίϯϙʔωϯτ3ͭͱ͍͏ঢ়ଶɻ • ϨΠϠʔυΞʔΩςΫνϟ(෩) •
ݫີͳͦΕͰͳ͍ • DIP(ґଘੑͷٯస)ΈࠐΉ
ϞϊϦεͱ͍͏બ
ϞϊϦεͱϚΠΫϩαʔϏε • ϞϊϦεʹΛࡴ͞Εͨܦݧ͋Δɻ • ϑϩϯτ͔Βཧը໘·Ͱ͕ͯ͢ಉࠝ͞Εɺ100ਓҎ্ͷ։ൃऀ͕ҰͭͷϦϙδτϦʹ commit͠ʮdeployฒͼ·͢ʯͱΛ͔͚߹͍ɺσϓϩΠࣦഊ͢Δͱଞ෦ॺʹౖΒΕΔσΟ ετϐΞ • ϚΠΫϩαʔϏεʹଜΛম͔Εͨܦݧ͋Δɻ •
1~3ςʔϒϧ૬ͷσʔλຖʹઐ༻ͷAPI͕ཚཱͯ͠૬ޓʹԿࢀর͍͋͠ɺ͍ͭͲ ͜ͰԿͷॲཧ͕ى͖͍ͯΔ͔Θ͔Βͳ͍σΟετϐΞ • ݁ہɺ͓࡞๏ʹࠩͷ͋ΔଟͷγεςϜΛͯ͢Ѳ͠ͳ͚ΕԿΘ͔Βͳ͍ɻ
ϞϊϦεͱϚΠΫϩαʔϏε • ϞϊϦε • ϝϯςෆՄೳͳ΄Ͳίʔυɾؔऀ͕ଟ͘ͳΔͱͭΒ͍ • ಉҰϦϙδτϦ͔ͩΒͱແࠩผʹࢀরΛΏΔ͢ͱΘ͚Θ͔ΒΜ͘ͳΔ • ϚΠΫϩαʔϏε •
ෆదͳׂʹΑͬͯຊདྷඞཁͷͳ͍ॲཧ͕૿Ճ͢ΔͱͱͯͭΒ͍ • Ұൠతʹ࣮ྔ૿͑Δ͠ɺΠϯϑϥߏ໘Ͱͷݕ౼ࣄ߲ɾઃఆ૿͑Δ
ϞϊϦεͱ͍͏બ • ࠷దͳϚΠΫϩαʔϏεͷཻΛࣄલʹݟग़͢͜ͱඇৗʹқ͕ߴ͍ɻ • ༷௨Γʹ࣮͍ͯͨ͠ͷʹʮ࣮Aͷσʔλ͚ͩͩͱΓͳͯ͘ɺৗʹBͱCҰॹʹཁΔΜͩ...ʯͱ͔ݴΘΕ͕ͪ • Goͬͯهड़ྔࣗମগͳ͘ͳ͍Ͱ͢ΑͶ? (ڞײΛٻΊΔѹྗ) • γϯϓϧͰಡΈॻ͖͍͢͠ɺʮָΛͤͯ͘͞ΕΔʯΈ߇͑Ίɻ
• ϚΠΫϩαʔϏεͰͷهड़૿Ճͱ߹ΘͤΔͱͪΐͬͱϔϏʔɻ • αʔϏεͷ্ཱͪ͛࣌ͰϞϊϦε๊͕͑Δ͕ੜ͡ΔϦεΫখ͍͞ • ʮϞϊϦεͷ··ʯҭͯͳͯ͘͢ΉΑ͏ʹదͳઃܭɾ੍Λ͠ɺ͕࣌དྷͨΒׂ͢ΕΑ͔Ζ͏ͳ ͷͩ • αʔϏεΛҭ͍ͯͯ͘தͰదͳׂཻ͕ݟ͑ͯ͘Δͱ͍͏ϝϦοτ͋Δɻ
ͱ͜ΖͰ • ϞϊϦε(স)ͬͯݴΘΕΔ͘Β͍ͷ֮ޛͰ࣮͍ͯͨ͠ΜͰ͕͢ɺ ͘͜͜Β͍?ͰϞδϡϥϞϊϦεͱ͍͏֓೦͕ఏএ͞Ε͍ͯͨͷ Ͱ͢Ͷɻ • ͦͷͱ͓Γʹ͍ͬͯΔͱ·Ͱݴ͑·ͤΜ͕ɺΞϓϩʔνͱͯ͠ Θ͔ΓΈ͕;͔͍
ϨΠϠʔυΞʔΩςΫνϟ(෩)ͱ͍͏બ
ϨΠϠʔυΞʔΩςΫνϟ(෩) • ࣮ΞʔΩςΫνϟʹۜͷؙͳ͘ɺνʔϜͱϓϩδΣΫτͷঢ়گ ʹΑͬͯ࠷దղมΘΔɻ • ֎෦ଓ͕ͳ͘ɺ͔ͭ20APIʹຬͨͳ͍Α͏ͳγεςϜΛগਓͰ࡞ ΔͷͰ͋ΕMVCͰશવྑ͍ͱࢥ͏ɻ • αʔϏε͕େنͰෳࡶɺ͔ͭ৫ͷख़͕ߴ͚ΕΫϦʔϯΞʔ ΩςΫνϟͰ࡞ΓࠐΈͨ͘ͳΔͱࢥ͏ɻ
ϨΠϠʔυΞʔΩςΫνϟ(෩) • લఏ • ߏΛϞϊϦεͱ͢Δ͜ͱʹਵͯ͠ɺதظతʹʮϢʔεέʔεʹ Ԡͯ͡αʔϏεΛ͍ͨ͠ʯͱߟ͍͑ͯΔɻ • Ϣʔεέʔε͕໌֬ʹͳΔΑ͏ͳ࣮ΞʔΩςΫνϟ/੍Λઃ͚͍ͨ • อݥͱ͍͏౷తͳϏδωεʹج͍ͮͯ࡞ΔαʔϏεͰ͋ΓɺϏδωε
ϩδοΫ͕ෳࡶɾॏཁͱͳΓಘΔɻ => DDDͱੑͷߴ͍ΞʔΩςΫνϟ͕ྑ͍ͱߟ͑ͨɻ
ϨΠϠʔυΞʔΩςΫνϟ(෩) • ͳͥΫϦʔϯΞʔΩςΫνϟ(ҎԼCA)Λબͳ͔ͬͨͷ͔? • CA͔ͨ͠ʹΑ͘Ͱ͖͍ͯΔͱ͓͏ • ͔͠͠ͳ͕ΒɺΞʔΩςΫνϟࣗମͷֶशίετͷߴ͕͞൱Ίͳ͍ • ͚͕ݫີɾৄࡉͰ͋Δ͕Ώ͑ʹɺʮ͏·͘Θ͚ͳ͚Ε͍͚ͳ͍ʯڧ੍͍Λײ͡Δ ʢݸਓͷײͰ͢)
• ݫີʹΘ͚ΒΕΔ͜ͱڧΈ͕ͩɺڧΈΛڗड͢Δʹ࠷ॳ͔Βߴ͍ݟ͕ٻΊΒΕΔɻ গਓɾ্ཱͪ͛ஈ֊ͷϓϩδΣΫτʹ͓͍ͯͷίεύ͍͔΄Ͳ͔?
ϨΠϠʔυΞʔΩςΫνϟ(෩)ͱ͍͏બ • DDD͖ͷΞʔΩςΫνϟͷதͰൺֱతૉ(ݸਓͷײͰ͢)ͳϨΠϠʔυ ΞʔΩςΫνϟͰυϝΠϯΛ͖Ε͍ʹอͪɺϢʔεέʔεΛΘ͔Γ͘͢දݱ ͢Δ͜ͱͰ͖Δɻ • ७ਮͳϨΠϠʔυΞʔΩςΫνϟinfraͷґଘΛ࣋ͭͨΊςετͮ͠Β͍ • DIPΛՃ͑ΕΓ͍ͨ͜ͱेʹͰ͖Δɺͣɻ
ґଘੑͷٯస(DIP) ```go:application/policy.go package application type Policy struct { // DIP.
infraʹґଘͤͣ͞ʹdomainͷinterfaceʹґଘͤ͞Δ policyRepo domain.PolicyRepository } func (p *Policy) Get(id string) (*model.Policy, error) { // ... res, err := p.policyRepo.Get(id) if err != nil { return nil, err } return res, nil } ``` ```go:domain/repository.go package domain // application͔Βݟ͑ΔॴʹinterfaceΛஔ͘ type PolicyRepository interface { Get(id string) (*model.Policy, error) } ```
ϨΠϠʔυΞʔΩςΫνϟ෩ʹຬͨ͢ͱ... ```go:infra/db/policy.go package infra // infra/db ʹ interface Λຬͨ͢۩ମతͳ࣮Λஔ͘ type
PolicyRepository struct { sess *dbr.Session } func (p *PolicyRepository) Get(id string) (*model.Policy, error) { // SQLͱ͔ // p.sess. ... } ```
ΫϦʔϯΞʔΩςΫνϟ෩ʹຬͨ͢ͱ... ```go:infra/db/policy.go // infra type DBSess struct { sess *dbr.Session
} func NewDBSess() *DBSess { // DBଓ } func (d *DBSess) Query(stmt string, args ...interface{}) () {} ``` ```go:interfaces/db.go // interfaces type DBSess interface { Query(stmt string, args ...interface{}) (Rows, error) } type Rows interface { Scan(...interface{}) error Next() bool Close() error } type PolicyRepository struct { sess DBSess } func (p *PolicyRepository) Get(id string) (*model.Policy, error) { // SQLͱ͔ // p.handler.... } ```
CAͪΐͬͱΉ͔͍ͣ͠ ཆ৩ͷ՝/ٖࣅίʔυͰൺֱ͢ΔͷͪͱͣΔ͍Ͱ͕͢...ͱ͖ͬͭʹ ͍͘͜ͱ൱Ίͳ͍...ɻ ͖Ε͍ͳநԽͰ͋Δ͜ͱΘ͔Δɻ ͔͠͠interfacesͱinfra͕ผΕ͍ͯΔԸܙͬͯԿ͚ͩͬ? ͦΕʹΑͬͯͤʹͳΔہ໘ࣗͨͪʹͲΕ͚ͩ๚ΕΔΜ͚ͩͬ?
݁ہ࡞ͬͨߏ (αϯϓϧ. ΈͮΒ͍) ϨΠϠʔυΞʔΩςΫνϟDIPͷ ใੈͷதʹͨ͘͞Μ͋Δ͠৽ ͍͜͠ͱΛ͍ͯ͠ΔΘ͚Ͱͳ͍Ͱ ͕͢...
ઃܭͷझࢫ • ࣮ફDDDʹ͍͏ʮ؇͔ͳϨΠϠʔԽΞʔΩςΫνϟʯ͕ϕʔε • ʮ؇͔ʯͱɺԼͷ͚ͩͰͳ͘Լํͷ͍ͣΕͬͯΑ͍ͱ͍͏ҙຯɻ • ໋໊ɾσΟϨΫτϦͷΓํΘΓͱ;Μ͍͖ɻ • ڭՊॻతʹ interfaces/handler
ͱ͔͕ͩɺinterfaces͕όϦΤʔγϣϯʹΉҹ͕͋·Γ ͳ͘ɺtopϨϕϧͷσΟϨΫτϦ͕1ͭ2ͭ૿͑ͨͱͯࠔΔ͜ͱͳ͍ͷͰtopʹhandlerͰ ͖ͬͨɻ·͊ͲͬͪͰ͍͍͔ͳɻ • application͡Όͳͯ͘usecase͚ͬͯͭΔ͜ͱ͕ଟ͍ؾ͢Δɻ ݸਓతʹusecaseͬͯଧͭͱࠨख͕ർΕΔ͔ΒڭՊॻΛ໔ࡑූʹapplicationʹͨ͠ɻ
ઃܭͷझࢫ(Ά͑Ή) • DDD/ΞʔΩςΫνϟΛݫີʹकΖ͏ͱ͗͢͠Δͱɺࣗͨͪʹͱͬͯ ඞཁͰແ͍ෳࡶ͞Λ࣋ͪࠐΜͰ͠·ͬͨΓɺӨڹͷͳ͍ࣄฑʹ͍ͭͯ ʮͲ͜ʹॻ͖͔͘ʯʮͲ͏ॻ͖͔͘ʯͰաʹΜͰ͠·͍͕ͪɻ • ͕ࣗͨͪकΓ͍ͨͷΛकΔ͖Ͱ͋ͬͯɺڭՊॻతͳ໋໊ɾߏΛ ݫक͢Δ͜ͱ͕తͰͳ͍ɻ • कΔ͖͜ͱΛ໌֬ʹɻ
·Δ͖͜ͱ(࣮ͷ੍) 1. domainapp,infra,handlerΛࢀর͠ͳ͍ 1. valuemodel,serviceΛࢀর͠ͳ͍ 2. modelserviceΛࢀর͠ͳ͍ 2. appinfra,handlerΛࢀর͠ͳ͍
੍Λ·ΔͨΊʹ 1. framework, httpʹؔ͢ΔॲཧhandlerͰ݁ͤ͞Δ 2. ϓϩάϥϜͷ֎ͷग़དྷࣄΛҙࣝ͢Δ࣮infraͰ݁ͤ͞Δ 1. ࣮ߦڥ,֎෦API,DB,... 3. appԼ(domain)ʹఆٛͨ͠interfaceʹґଘͤ͞Δ(DIP)
4. ͦΕҎ֎ͷࡉ͔͍͜ͱΑ͠ͳʹɻࠔΔਓ͕͍ͳ͚ΕΑ͍ɻ
੍ʹΑͬͯಘΔͷᶃ • domainʹ֎෦APIDBΛҙࣝ͢Δهड़͕શ͘ͳ͘ͳΔɻ • ७ਮͳϏδωεϩδοΫ͚͕ͩଘࡏ͢ΔͷͰͱ͖ͯΕ͍(খฒײ) • γϯϓϧͳunit testΛ؆୯ɾཏతʹॻ͚Δɻ • DBͷσʔλΛͲ͏༻ҙͨ͠ΒΑ͍͔?localCIͰڥͷࠩແ͍͔?ͲΜ
ͳϦΫΤετ͕དྷΔ͔?ͳͲͷٕज़త/ڥతͳ੍,ςετͷ͔͠͞Βղ์ ͞Ε͍ͯΔͣɻ • mockෆཁͳͷͰɺʮςετͷΓํΛؒҧ͏ʯݒ೦ͳ͍
੍ʹΑͬͯಘΔͷᶄ • applicationrepositoryͷinterfaceͷΈʹґଘ͠infraʹґଘ͍ͯ͠ͳ͍ɻ • infraΛࠩ͠ସ͑Δࣄ͕Ͱ͖Δɻ • mockΛࠩ͠ࠐΜͰͷunit test͕Մೳ • ͜ͷ߹ɺྫ͑ʮσʔλ͕ਖ਼͘͠อଘ͞ΕΔ͔ʯͷςετͰͳ͘ɺʮσʔλΛਖ਼͘͠ΈཱͯͯอଘΛݺΔ͔ʯͷςετʹͳΔ
• ࣮ࡍʹʮDBʹॻ͖ࠐ·ΕΔ͔·Ͱ֬ೝ͍ͨ͠ʯͱ͍͏Θ͔Δ͕ʮapplication୯ମͷͷςετʯͱͯ͜͠ΕͰΑ͍ͣɻ infra࣮͚͕ͩbugͬͨ߹ʹɺapp͕bug͍ͬͯͳ͍͜ͱ͕อূ͞ΕΔɻ • localͰ͑ͳ͍APIΛμϛʔʹࠩ͠ସ͑ͯಈ͔ͨ͠Γ͢Δ͜ͱՄೳ
੍ʹΑͬͯಘΔͷᶅ • infra/handlerʹϏδωεϩδοΫ͕͍ͳ͍ͷͰɺٕज़తͳؔ৺ (http,sql,...)ʹϑΥʔΧεͰ͖Δɻ • ͨͱ͑handlerͯ͢ҎԼͷΑ͏ͳըҰతͰബ͍࣮ʹͳΔ • HTTP RequestͷParse •
applicationݺग़ • Responseฦ٫
αʔϏεͷΓग़͕͠Ͱ͖ͦ͏͔? • app/domain͕͓ޓ͍ʹઐ༻ͱͳ͍ͬͯΔ(ଞͷdomainΛΘͣɺଞͷapp͔ΒΘ Εͳ͍)ͷɺΘ͔ͣͳൣғͰ͔͠ڞ༗͍ͯ͠ͳ͍࣮͕͍͔ͭ͘ੜͨ͡ɻ • ͜ͷ༷ͳՕॴ࣮తʹಠཱੑ͕͔͍ͨɻ • ςετॻ͚͍ͯΔͷͰΓग़͠༰қɻ • Ұ࿈ͷinfra/handler/app/domainΛ·ΔͬͱΓग़ͯ͠ϚΠΫϩαʔϏεʹͯ͠
͠·ͬͯΑͦ͞͏ɻ • ͦ͏Ͱͳ͍Օॴ҆қʹΓग़ͦ͏ͱߟ͑ͣɺ·ͣϦϑΝΫλϢʔεέʔεͷ ཧΛ৻ॏʹਐΊΔͷ͕Α͍Α͏ʹࢥ͏ɻ
Α·
Α·: repositoryϑΝΠϧΘ͚ͳ͍ͷ? • repositoryͬͯinterfaceཏྻ͢Δ͚ͩͰத͕΄΅ͳ͍ͷͰϑΝΠϧ ཚཱͤͯͪ͞ΐͬͱڏ͍͔͠ͳ...ͱ͓ͬͯ·ͱΊ͍ͯΔɻ ָͩ͠ɻ • domain/repository/ Ͱ͖ͬͨ΄͏͕ਖ਼͍͠ͱࢥ͏
Α·: handlerͷςετ • applicationhandlerͷinterfaceԽ͍ͬͯͳ͍ • ͬͨ΄͏͕handler,routingͷUT͍͢͠...͔ͳ? • (ബ͍࣮ͳΒ) handlerͷςετUTΑΓe2eΛؤுͬͨ΄͏͕Α͍ͱࢥ͍ͬͯΔɻ •
handler, ࣮ࡍͷreq/resͰࢼͨ͘͠ͳΔͷ͕ਓͰ͋Γ·ͤΜ͔ • ʮinfraͷҟৗʹର͢ΔhandlerͷڍಈͷςετΛৗʹಈ͔͍ͨ͠ʯͱ͔ͳΒඞཁͦ͏ɻ • mockࠩ͠ࠐΜͰαʔόʔ্͛ͯe2eͰҰಈ࡞֬ೝ͢Εݸਓతʹຬ
Α·: handlerͷςετ • ͪͳΈʹe2eͱ͍ͬͯͦΜͳʹϋΠΧϥͳͷͰͳ͍ɻ • postmanͰಈ࡞֬ೝͯ͠ઃఆΛอଘ͠ɺnewmanͰ͑ΔΑ͏ʹ͍ͯ͠Δɻ • ։ൃதʹʮͪΐͬͱcurlͯ͠ΈΔʯΘΓʹ࡞ͬͯͨΊ͓͚ͯಛʹ࣌ؒΛ͔ͭ Θͳ͔ͯ͘ͳΓͷཏੑʹͳΔͱࢥ͏ɻ
Α·: gomockͱDDD • gomock • https://github.com/golang/mock • InterfaceΛॆ͢Δmock࣮Λࣗಈੜͯ͘͠ΕΔπʔϧ • ʮInterfaceΛॻ͔ͳ͚ΕͳΒͳ͍ʯDDD࣮ͱ૬ੑ͕Α͍
• repositoryΛࢦఆͯ͋͛͠Εmock͕Ψοͱ࡞ΒΕΔ • ʮͲͷΑ͏ʹrepository͕ݺΕͯ΄͍͔͠ʯΛࢦఆͯ͠ςετͰ͖Δ
Α·: gomockͱDDD func TestGetProduct(t *testing.T) { ctrl := gomock.NewController(t) defer
ctrl.Finish() // ੜ͞Εͨmock package m := mock_repo.NewMockProductRepository(ctrl) /* * Get("hoge")͕call͞ΕΔ͜ͱΛςετ͠ɺ * ݺΕͨ߹ID:"hoge"ͷmodelΛฦͯ͘͠ΕΔ * / id := "hoge" m.EXPECT().Get(id).Return(&model.Product{ID: id}, nil) // mockRepoͷIFΛຬ͍ͨͯ͠ΔͷͰinfraͱͯ͑͠Δ app := application.NewProduct(m) res, err := app.GetProduct(id) ... }
Α·: testͱtime.Now() • goʹݶͬͨ/େͨ͠Ͱͳ͍Ͱ͕͢... • ͍Ζ͍Ζͳͱ͜Ζʹ time.Now() ͕͋ΔͨΊʹ҆ఆͨ͠ςετ͕ॻ͚ͣ ʹఘΊͨܦݧ͋Γ·ͤΜ͔ •
ςετ͍͢͠ΞʔΩςΫνϟͰؤுͬͯॻ͍ͯɺͦ͜Ͱͭ·͍ͣͯ ҙຯ͕͋Γ·ͤΜɻ • ࣌ؒউखʹॻ͖ΘΓଓ͚ΔglobalมͳͷͰॳظஈ֊͔Βੵۃతʹ ͍ग़͓ͯ͘͠ͷ͕ྑ͍ͱࢥ͍ͬͯ·͢ɻ
Α·: testͱtime.Now() package clock import "time" // Clock ࣌ؒͷinjection༻IF type
Clock interface { Now() time.Time } // RealClock ࣮࣌ؒΛฦ͢. αʔόʔ্Ͱappʹ͜ΕΛ͢. type RealClock struct {} func (r *RealClock) Now() time.Time { return time.Now() } func NewRealClock(loc *time.Location) *RealClock { return &RealClock{} } // MockClock ݻఆ࣌ؒΛฦ͢μϛʔ࣌ܭ.ςετͰappʹ͜ΕΛ͢. type MockClock struct { now *time.Time } func NewMockClock(t *time.Time) *MockClock { return &MockClock{now: t} } func (m *MockClock) Now() time.Time { return time.Now() } timeΛ͍ग़͢Ұͭͷྫ. ͕࣌ؒඞཁͳapplicationʹ࣌ܭ(Now ΛऔΕΔϞϊ)Λ͢Α͏ʹ͓ͯ͘͠ɻ ࣌ܭ͢ͷΊΜͲ͍ͱ͍͏ͷ͋Δ͕࣌ؒͷґ ଘΛ໌ࣔతʹ͢ΔҙຯͰଥͩͱࢥ͍ͬͯΔɻ ʘ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʗ
Αͨͳ͠
infraͷࠩ͠ସ͑,ϚϧνΫϥυͱ͍͏ເ • ʮinfraҎԼʹٕज़తؔ৺Λด͡ࠐΊΔͱσʔλϕʔεج൫ΛҠߦ͠Α͏ͬͯͳͬͨ࣌ʹָʯ • ࣮ࡍͱͯͦ͠Μͳͷ͕ඞཁʹͳΔ͜ͱͳ͍Ζʁͬͨ͜ͱ͋Δ͓ͭΓΎʙ? • ͬͨɻ • ࣾͷٕज़ϙʔτϑΥϦΦଟ༷ԽݱߦͷΠϯϑϥʹ͕ੜͨ͡߹ʹඋ͑ͯɺ৽͍ٕ͠ज़ͷݕূͯ͠Έͨ ͍ΑͶͱ͍͏͕͋ͬͨɻ
• PJͷλΠϛϯάܦݧతͳ߹͋ͬͯɺGCP/CloudDatastoreΛར༻ͯ͠MVP࣮Λߦͬͨɻ • ͦͷޙॾʑͷࣄΛצҊͯ͠AWS/Auroraʹࡌͤସ͑ͨɻ • ্࣮ͷӨڹൣғ͔֬ʹinfraҎԼʹݶఆ͞Εɺॻ͖͑ࣗମ2͔͔Βͳ͍͘Β͍ͰࡁΜͩɻ • (࣮͠ͳ͍Ͱࣄલͷݕ౼Ͱશ෦ચ͍ग़ͤΑɺͱݴΘΕΔͱ͕ࣖ௧͍ͱ͜ΖͰ͋Δ...·͊ૉৼΓͨ·ʹͶ?)