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
「エンジニア進化論」2028年の開発完全自動化、エンジニアはどう進化するか
cyberagentdevelopers
PRO
6
5k
Agent Skills設計で柔軟性と硬さのバランスが難しい話
nassy20
0
130
【NRUG vol.18】KubernetesにおけるNew Relicデータ取得量削減の考え方
nrug_member
0
110
Oracle AI Database@Azure:サービス概要のご紹介
oracle4engineer
PRO
6
2k
自宅LLMの話
jacopen
1
510
【セミナー資料】Claude Code をセキュアに使うための考え方と設定の勘どころ / Claude Code Webinar 20260616
masahirokawahara
1
120
LLMにもCAP定理があるという話
harukasakihara
0
330
Claude Code×Terraform IaC テンプレート駆動開発
itouhi
1
510
AIソロプレナー時代に2ヶ月で20人増員した事業創造会社の開発組織の話
miyatakoji
0
640
あなたの AI ワークスペースに、 専門コーダーを連れてくる - Amazon Quick Desktop 最新情報
kawaji_scratch
1
130
Bedrock AgentCore RuntimeでAuth0 Changelog調査AIをアップグレードした話
t5u8a5a
1
110
2026 TECHFRESH 畢業分享會 - AI-Native 重塑軟體工程與虛擬講師
line_developers_tw
PRO
0
940
Featured
See All Featured
The agentic SEO stack - context over prompts
schlessera
0
820
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Typedesign – Prime Four
hannesfritz
42
3.1k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Context Engineering - Making Every Token Count
addyosmani
9
960
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
360
Tell your own story through comics
letsgokoyo
1
950
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
230
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
[SF Ruby Conf 2025] Rails X
palkan
2
1.1k
Speed Design
sergeychernyshev
33
1.8k
Rails Girls Zürich Keynote
gr2m
96
14k
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͔͔Βͳ͍͘Β͍ͰࡁΜͩɻ • (࣮͠ͳ͍Ͱࣄલͷݕ౼Ͱશ෦ચ͍ग़ͤΑɺͱݴΘΕΔͱ͕ࣖ௧͍ͱ͜ΖͰ͋Δ...·͊ૉৼΓͨ·ʹͶ?)