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
Goでやや大きいプロダクトのアーキテクチャを検討したり実装したりしたおはなし
Search
yami20
July 17, 2020
Technology
820
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
社内 AI エージェント Synapse と セマンティックレイヤーの育て方
hiroakis
3
1.8k
FDE という解 ― 暗黙知と明示知をつなぐ、伴走型エンジニアリング ―
otanet
0
150
小さくはじめるSLI/SLO ~育てながら組織に定着させる実践知~ / Starting Small with SLI/SLOs: Building Adoption Through Continuous Growth
nari_ex
7
1.9k
AI駆動開発を通して感じた、 AI時代のデザイナーの役割変化
whisaiyo
3
2k
非定型業務をAI slackbotで自動化する ~ 社内要望を自動壁打ちするbotを作った ~/automating-ad-hoc-work-with-ai-slackbot
shibayu36
0
640
【NRUG vol.18】なぜ多くのオブザーバビリティ導入は失敗するのか
nrug_member
0
120
2026TECHFRESH畢業分享會 - Lightning Talk - 資料也要 CI/CD? 用 Airbyte 自動化資料同步
line_developers_tw
PRO
0
920
2026TECHFRESH畢業分享會 - Lightning Talk - 打造精準高效的 MCP 設計模式與測試實務
line_developers_tw
PRO
0
930
自宅LLMの話
jacopen
1
510
MCP Appsを作ってみよう
iwamot
PRO
4
600
AWSシリコン最前線 〜AI時代のチップ選択を読み解く〜
htokoyo
2
550
非エンジニアがClaudeと挑んだ「1ヶ月間プロダクト30本ノック」
askokc
0
430
Featured
See All Featured
Tell your own story through comics
letsgokoyo
1
950
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.5k
Un-Boring Meetings
codingconduct
0
310
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
360
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
130
Building AI with AI
inesmontani
PRO
1
1.1k
The Pragmatic Product Professional
lauravandoore
37
7.3k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
160
Documentation Writing (for coders)
carmenintech
77
5.4k
Crafting Experiences
bethany
1
180
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͔͔Βͳ͍͘Β͍ͰࡁΜͩɻ • (࣮͠ͳ͍Ͱࣄલͷݕ౼Ͱશ෦ચ͍ग़ͤΑɺͱݴΘΕΔͱ͕ࣖ௧͍ͱ͜ΖͰ͋Δ...·͊ૉৼΓͨ·ʹͶ?)