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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
全員がプロダクトへ向き合う組織を持続成長させるために——組織づくりのフライホイールと4象限 / The Flywheel Model and Four Quadrants for Organizational Design
hiro_torii
4
960
Code4Lib JAPANカンファレンス2026 開会挨拶 / Code4Lib JAPAN Conference 2026: Opening Remarks
ykiyota
0
330
目の前の楽しいが人生を変える - コミュニティの螺旋の歩き方と楽しむコツ / change your life
soudai
PRO
4
380
Amazon Quick on DesktopがIAM Identity Centerで動かない理由
yukiogawa
0
150
AI活用の現在地、 ちゃんと見えてますか?/XPfest-2026
visional_engineering_and_design
0
180
スクラムで身についていた動き方を、XPで捉え直してみた
codmoninc
PRO
1
350
Gitは怖い?共有ワークスペースから始めるSnowflakeチーム開発
coco_se
0
110
When Does a Local Qwen Start to Break
morshoto
0
200
DEFCON_CHV_CTF_Write-up.pdf
bata_24
0
130
なぜSRE・セキュリティは評価されないのか?守りの組織を事業成長エンジンに変えた実践
cscengineer
PRO
3
2.4k
enechainの内製セルフサービスプラットフォーム
hiyosi
0
150
日経電子版を支えていく Kasane Design System/fec_fukuoka
nikkei_engineer_recruiting
0
670
Featured
See All Featured
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
820
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
330
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
500
The Spectacular Lies of Maps
axbom
PRO
1
990
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
660
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
780
Ethics towards AI in product and experience design
skipperchong
2
370
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
330
Writing Fast Ruby
sferik
630
63k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.3k
4 Signs Your Business is Dying
shpigford
187
23k
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͔͔Βͳ͍͘Β͍ͰࡁΜͩɻ • (࣮͠ͳ͍Ͱࣄલͷݕ౼Ͱશ෦ચ͍ग़ͤΑɺͱݴΘΕΔͱ͕ࣖ௧͍ͱ͜ΖͰ͋Δ...·͊ૉৼΓͨ·ʹͶ?)