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
まずはドメインに向き合って、それからCQRSで実装する
Search
memetics10
January 10, 2026
4.6k
14
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
まずはドメインに向き合って、それからCQRSで実装する
memetics10
January 10, 2026
Featured
See All Featured
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.6k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
540
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
2
6.3k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
203
77k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
Raft: Consensus for Rubyists
vanstee
142
7.8k
Un-Boring Meetings
codingconduct
0
460
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
640
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
460
Paper Plane (Part 1)
katiecoart
PRO
2
12k
Transcript
ͦΕ͔Β$234Ͱ࣮͢Δ +BOVBSZ ·ͣυϝΠϯʹ͖߹ͬͯ ,PTVLF"CF
"CPVU.F ,PTVLF"CF גࣜձࣾ%JHJUUMF$50 ❤🏋🚴 !NFNFUJDT
TRITON 2023.10.25 %JHJUUMFJOD Τϯλϝۀք͚ʹσδλϧάοζɺ "*ٕज़Λ׆༻ͨ͠ίϛϡχέʔγϣϯ αʔϏεͳͲɺΠϯλϥΫςΟϒͳମ ݧΛ࣮ݱ͢ΔαʔϏεΛग़͢Δ
εςʔΫϗϧμʔͷ૾Λ͑ΔͨΊʹɺΤϯδχ ΞϓϩμΫτσβΠϯʹίϛοτ͢Δɻਖ਼͍͠ ΞʔΩςΫνϟύλʔϯͰɺؒҧͬͨϓϩμΫτΛ ࡞Δ͜ͱආ͚͍ͨɻ &SJD&WBOT %PNBJO%SJWFO%FTJHO5BDLMJOH$PNQMFYJUZJOUIF)FBSUPG4PGUXBSF 'JSTUBOEGPSFNPTU ϓϩμΫτσβΠϯ ʹ࣠Λஔ͘ ιϑτΣΞͷ֩৺ɺυϝΠϯʹؔͨ͠Λ
ϢʔβʔͷͨΊʹղܾ͢ΔೳྗͰ͋Δɻ ͦΕҎ֎ͷಛ͍ͣΕɺͲΕ΄Ͳॏཁͩͱͯ͠ɺ ͜ͷجຊతͳతΛࢧ͑Δʹ͗͢ͳ͍ɻ
$234ΞʔΩςΫνϟύλʔϯͷҰछ͕ͩɺ ϓϩμΫτσβΠϯͷώϯτ͕͍ͬͯΔ ɾ.7$ ɾϨΠϠʔυΞʔΩςΫνϟ ɾΠϕϯτιʔγϯά ɾFUDʜ ɾϢʔβʔυϝΠϯͷੳ ɾ֓೦Ϟσϧ ɾ69ઃܭ ɾFUDʜ
ΞʔΩςΫνϟύλʔϯ ϓϩμΫτσβΠϯ #VU 8IZ$234 ιϑτΣΞͷ෦Λମܥతʹཧ͢Δํ๏ ϢʔβʔχʔζʹରԠ͢ΔΛ࡞͢Δϓϩηε
ϢϏΩλεݴޠͷಈࢺ͕$36%ʹऩଋ͢Δ͜ͱ͋·Γͳ͍ ΦϒδΣΫτͷߏؔੑ͋Δ͕ɺৼΔ͍ͷͳ͍ʮυϝΠϯϞσϧශ݂ʯ σʔλͷ$36%͕த৺ͷΞʔΩςΫνϟͰɺυϝΠϯۦಈઃܭ͕ෆՄೳ Ϣʔβʔମݧ͕$36%ʹҾ͖ͣΒΕΔͷɺ༨ܭʹѱ͍ (SFH:PVOH $234EPDVNFOUTCZ(SFH:PVOH "TUFSFPUZQJDBMFYBNQMFPGUIJTXPVMECFXIFODIBOHJOHUIFTFYPGBOFNQMPZFF ZPVNVTUBGUFSHPFEJUUIFJSIFBMUIJOTVSBODFJOGPSNBUJPO 5IJTJTGBSXPSTFUIBOUIFDSFBUJPOPGBOBOFNJDNPEFM UIJTJTUIFDSFBUJPOPGBHMPSJ
fi FE FYDFMTQSFBETIFFU %PNBJO%SJWFO%FTJHO
$36%ࢤͷ6*ʹɺϢʔβʔͷҙਤ͕Έࠐ·Ε͍ͯͳ͍ γεςϜ͕ϢʔβʔͷҙਤΛϩετͯ͠͠·͏ͱɺཱͭϨϙʔςΟϯάใΛఏڙͰ͖ͳ͍ ֓೦ϞσϧΛਂ͘ཧղ͠ͳ͍ͱ͑ͳ͍ 6TFS*OUFSGBDF ҙਤͷ໌֬Խ
$234 $234ΦϒδΣΫτΛίϚϯυͱΫΤϦʹ͢Δ୯७ͳΞʔΩς Ϋνϟύλʔϯ͕ͩɺͦͷԸܙΛेʹड͚ΔͨΊʹ·ͣɺϢʔβʔ ͷҙਤΛΈऔΓɺମݧʹؾΛΔ (SFH:PVOH $234 5BTL#BTFE6*T &WFOU4PVSDJOHBHI $234JTTJNQMZUIFDSFBUJPOPGUXPPCKFDUTXIFSFUIFSFXBTQSFWJPVTMZPOMZPOF5IF TFQBSBUJPOPDDVSTCBTFEVQPOXIFUIFSUIFNFUIPETBSFBDPNNBOEPSBRVFSZ
UIFTBNF EF fi OJUJPOUIBUJTVTFECZ.FZFSJO$PNNBOEBOE2VFSZ4FQBSBUJPO BDPNNBOEJTBOZ NFUIPEUIBUNVUBUFTTUBUFBOEBRVFSZJTBOZNFUIPEUIBUSFUVSOTBWBMVF
ݴޠతͳҙຯ͔Βߟ͑Δͱɺ γεςϜ໋͕ྩΛڋ൱Ͱ͖Δ͜ͱΛ͍ࣔͯ͠Δ $PNNBOE ڋ൱ΛͨͩͷΤϥʔͱͯ͠ѻΘͣɺϢʔβʔମݧͱͯ͠ઃܭʹ৫ΓࠐΜͰ͓͘ ϢʔβʔͷҙਤΛࣽ٧ΊΔͱಉ࣌ʹɺڋ൱͞ΕΔཧ༝ΛΑ͘ߟ͑Δ
ݴޠతͳҙຯ͔Βߟ͑Δͱɺ ࣄ࣮औΓফͤͳ͍͜ͱΛ͍ࣔͯ͠Δ ΤϰΝϯεຊͰมߋΛӬଓԽ͢Δํ๏͕ᐆດ͕ͩͬͨɺΠϕϯτͰิ͞Εͨ &WFOU ͢Ͱʹى͖ͨ͜ͱΛڋ൱͢ΔͷෆࣗવͰ͋ΓɺίϚϯυͱҙຯతͳରশੑ͕͋Δ
ٕज़తʹͲͪΒ୯७ͳߏମͱ͍͏Ͱಉ͡Ͱɺ໋໊ํ๏ʹҧ͍͕͋Δ ݴޠతͳҙຯʹ͠ɺ υϝΠϯϞσϧͱϢϏΩλεݴޠͷ୳ࡧʹ͏ type DeactivateInventoryItem struct { InventoryItemID string Comment
string } type InventoryItemDeactivated struct { InventoryItemID string Comment string } &%"ɺΠϕϯτʹ࣍ͷࢦؚ͕ࣔ·Εͳ͍ҙຯతͳཧ༝Ͱૄ݁߹ʹͳΔ $PNNBOE&WFOU
ΠϕϯτετʔϛϯάΛɺσβΠϯͷख๏ͱͯ͠׆༻͢Δ ҟͳΔόοΫάϥϯυΛ࣋ͭਓͷߟ͑Λൃࢄͤ͞ɺΧϥʔύζϧͱରΛ௨ͯ͠߹ҙͤ͞Δ ·ͣΛ͘୳ΓɺͦΕ͔Βղܾऩଋ͍ͤͯ͘͞ͰɺσβΠϯࢥߟʹΑ͘ࣅ͍ͯΔ Πϕϯτ ϙϦγʔ ू ίϚϯυ ίϚϯυ Πϕϯτ ू
%PO/PSNBO 5IF%FTJHOPG&WFSZEBZ5IJOHT ൴Βɺຊͷ͕Կ͔ΛݟఆΊΔ·ͰղܾΛ୳ͦ͏ͱ͠ͳ͍ɻ ͕ఆ·ͬͨͱ͖Ͱ͑͞ɺΛղܾ͠Α͏ͱ͠ͳ͍ɻ ൴Βཱͪࢭ·͍ͬͯൣғ͔ΒՄೳͳ͑Λ୳͢ɻͦ͏ͯ͠ॳΊͯɺ࠷ऴతʹ൴ΒͷఏҊΛऩଋ͍ͤͯ͘͞ɻ ͜ͷϓϩηεσβΠϯࢥߟͱݺΕ͍ͯΔɻ &WFOU4UPSNJOH
ಉҰूʹର͢Δಉ࣮࣌ߦͰෆม͕݅ഁΒΕͳ͍Α͏ʹ͢Δඞཁ͕͋Δ "HHSFHBUF ࡏݿ͕֬ อ͞Εͨ ࡏݿ ࡏݿΛ֬ อ͢Δ ෆม݅Λڧ੍͢Δൣғɺͭ·ΓҰ؏ੑͱಉ࣮࣌ߦੑͷ୯Ґ ॲཧࣦͪഊͷ૿ՃʹΑΔϢʔβʔମݧͷѱԽʹҙ͢Δ ࡏݿ͕ϚΠφεʹͳΒͳ͍͜ͱෆม݅ʹͰ͖Δ͔ʁ
Πϕϯτൃੜ࣌ؒܦաͰىಈ͢ΔϦΞΫςΟϒϩδοΫɺΠϕϯτͱίϚϯυͷؒʹ͋Δࢵ৭ͷᝦ 1PMJDZ ࡏݿ͕ϚΠ φεͷ߹ ೖՙͪΛ ͢Δ ೖՙ͕ͪ ͞Εͨ ೖՙͪ ूͷෆม݅Ͱͳ͍ɺൺֱతΏΔ͔ͳϏδωε্ͷҙࢥܾఆ
ࡏݿ͕֬อ ͞Εͨ ࡏݿ ࡏݿΛ֬อ ͢Δ ࡏݿ͕֬อ ͞Εͨ ࡏݿ ࡏݿΛ֬อ ͢Δ Ұ୴ࡏݿͷϚΠφεΛڐ༰ͯ͠ɺʮͦΕ͔ΒʯೖՙͪͷରԠΛ͢Δ
จ͞Εͨ จ͞Εͨ Βඞͣ จ จ͢Δ υϦϯΫΛ ࡞Δ υϦϯΫ υϦϯΫ͕ ࡞ΒΕͨ
υϦϯΫ͕ ͨ͠Β ඞͣ ٬ͷ໊લΛ ݺͿ ࢧ͍Λ͢ Δ ࢧ͍ ࢧ͍͕ ྃͨ͠ ࢧ͍Ͱ͖ ͳ͔ͬͨ ߹ υϦϯΫΛ ࣺͯΔ จ͢Δ ࢧ͍υ ϦϯΫ࡞ ࢧ͍υ ϦϯΫ࡞ ྃ "HHSFHBUF1PMJDZ ੍ΛकΓͳ͕ΒɺॊೈͰϊϯϒϩοΩϯάͳΠϯλϥΫγϣϯΛߟ͑Δ (SFHPS)PIQF 4UBSCVDLT%PFT/PU6TF5XP1IBTF$PNNJU XFDBOTFFUIBUUIFSFBMXPSMEJTPGUFOBTZODISPOPVT 0VSEBJMZMJWFTDPOTJTUTPGNBOZDPPSEJOBUFE CVUBTZODISPOPVTJOUFSBDUJPOT %#ϩοΫ͢Ε͍͍ɺͱٕज़ओಋͰߟ͑ͳ͍Α͏ʹ͢Δ
ڭՊॻͷύλʔϯͷֶशʹ࠷దԽ͞Ε͍ͯΔ͕ɺݱ࣮ʹى͖͍ͯΔͦΕͱશ͘ҟͳ͍ͬͯΔ ڭՊॻͷΛղ͚ͩ͘Ͱͳ͘ɺݱ࣮ͷΛ۷ΓԼ͛Δ ֶशͨ͠ख๏Λɺݱ࣮ͷʹͦͷ··ͯΊͯ͏·͍͔͘ͳ͍͜ͱ͕ଟ͍ 5BDLMJOH3FBM*TTVFT ݱ࣮ͷੈքͰɺ͖Ε͍Ͱ͖ͬͪΓͨ͠แʹแ·Εͯ͜ͳ͍ɻൃݟ͞Εͳ͚ΕͳΒͳ͍ɻ ਓɺຊͷʹͨͲΓண͘Α͏ʹ۷ΓԼ͛Δ͜ͱΛͤͣʹɺ͋·Γʹ҆қʹද໘্ͷΛݟͯ͠·͏ͷͩɻ %PO/PSNBO 5IF%FTJHOPG&WFSZEBZ5IJOHT
αϒεΫొ͍ͯ͠Δސ٬ʹ͚ͩɺ ίϛϡχςΟ ΞʔςΟετ࡞ ͷݶఆߘΛݟ͍ͤͨ 3FBM%PNBJO'BOEPN$PNNVOJUZ
ͷจ͕ ྃͨ͠ จ ͷจΛ ྃͤ͞Δ αϒεΫϦϓ γϣϯొ͢ Δ αϒεΫ ͷ߹
αϒεΫϦϓ γϣϯొ͞ Εͨ αϒεΫϦϓ γϣϯ ߘ͕ ެ։͞Εͨ ߘ ߘΛ ެ։͢Δ ސ٬ ίϛϡχςΟ ཧऀ ސ٬༻ͷ ߘϏϡʔ 'JSTU.PEFM
ձͷதͰݴ͍͍ͨ͜ͱΛ͏·͘ݴ༿ͰදݱͰ͖ͳ͍ ݶఆߘΛݟΕΔ͔ఆ͢ΔͨΊʹɺຖճܾࡁঢ়ଶΛνΣοΫ͠ͳ͍ͱ͍͚ͣɺίʔυ͕ࡶ 6*্Ͱʮ͕ࣗαϒεΫϦϓγϣϯ͍ͯ͠ΔίϛϡχςΟʯΛͲ͏දݱ͢Ε͍͍͔ෆ໌ྎ "XLXBSE$POWFSTBUJPO 6* BOE$PEF ͗ͪ͜ͳ͞ͱ͍͏ঢ়
νΣοΫΠϯ͢Δͱ͖ɺʮαϒεΫʯͱ͍͏ࢧ͍ܖΛ֬ೝͯ͠Β͍ͬͯΔΘ͚Ͱͳ͍ ՝ۚΛࡁ·ͤͨΒʮձһূʯΛड͚औ͍ͬͯΔ 'PDVTPO%PNBJOBOE6TFS ਓؒͷ׆ಈͱɺͦ͜Ͱى͖͍ͯΔίτʹ͢Δ
ͷจ͕ ྃͨ͠ αϒεΫ ͷ߹ จ ͷจΛ ྃͤ͞Δ αϒεΫϦ ϓγϣϯొ ͢Δ
αϒεΫϦϓ γϣϯొ͞ Εͨ αϒεΫϦϓ γϣϯ ߘ͕ ެ։͞Εͨ ߘ ߘΛ ެ։͢Δ ސ٬ ίϛϡχςΟ ཧऀ ސ٬༻ͷ ߘϏϡʔ αϒεΫϦϓ γϣϯొ͞ ΕͨΒ ձһূΛड ͚औΔ ձһূ͕ड͚ औΒΕͨ ձһূ ձһূ ձһূ͕ఀࢭ ͞Εͨ ձһূΛఀ ࢭ͢Δ αϒεΫϦ ϓγϣϯΛ ແޮԽ͢Δ αϒεΫϦϓ γϣϯ͕ແޮ Խ͞Εͨ αϒεΫϦϓ γϣϯ αϒεΫϦϓ γϣϯ͕ແޮ Խ͞ΕͨΒ ސ٬ αʔϏεͷࢧ͍ͱར༻ͷݖརΛ͠ɺ ձһূΛड͚औͬͨɺͱ͍͏ࣄ࣮ΛՃ 3FDPOTJEFS%PNBJO.PEFM
3FDPOTJEFS6TFS&YQFSJFODF ձһূΛϦονͳΧʔυσβΠϯͰϢʔβʔʹݟͤΔ͜ͱͰɺॴ༗ײؼଐײΛߴΊΔମݧʹ ඞཁʹԠͯ͡ɺαϒεΫͳ͠ͰձһূΛ༩͢Δ͜ͱՄೳʹͳͬͨ υϝΠϯϞσϧͷมԽ͕ϢʔβʔମݧΛมԽͤ͞Δ ظؒݶఆͷΧʔυσβΠϯͳͲɺ৽͍͠ՁΛߟ͑ΔͨΊͷʹͳΔ
υϝΠϯΤΩεύʔταϒεΫʹΑΔ҆ఆऩӹΛୈҰʹߟ͍͑ͯͨɻυϝΠϯΤΩεύʔτݸผʹಛԽͨࣝ͠Λ ͍࣋ͬͯΔ͕ɺશମ࠷దͷղܾࡦΛ͍࣋ͬͯΔΘ͚Ͱͳ͍ υϝΠϯʹ౿ΈࠐΜͰɺղܾࡦΛ͢Δ %FTJHO%PNBJO.PEFM &SJD&WBOT %PNBJO%SJWFO%FTJHO5BDLMJOH$PNQMFYJUZJOUIF)FBSUPG4PGUXBSF զʑͷϞσϧɺ͜ͷϏδωεʹ;͞Θ͘͠ͳ͍ํ๏Ͱɺ ϑΝγϦςΟͷ୲ͱϩʔϯͷ୲Λ݁ͼ͚͍ͭͯͨͷͰ͋Δɻ தུ
ϑΝγϦςΟϩʔϯͷγΣΞʹؔͯ͠ɺಛผͳΦϒδΣΫτ͏ͳ͘ͳͬͨɻ ͲͪΒɺΑΓײతʹΘ͔ΔʮγΣΞύΠʯʹׅΓग़͞Εͨͷͩɻ ٕज़ྗͱྗͰɺࣗͨͪͳΓͷʮγΣΞύΠʯΛൃݟ͢Δ
ίϚϯυɺΠϕϯτɺूɺϙϦγʔͱ͍ͬͨ֓೦Λ࣮͢Δ͕ɺ CQRS+ES Θͳ͍ 6EJ%BIBO IUUQTYDPN6EJ%BIBOTUBUVT %POU$234 /PUBTBUPQMFWFMBSDIJUFDUVSF /PUVOUJMZPVWFUBTLPSJFOUFEZPVS6* /PUVOUJMZPVWFTFQBSBUFQSJWBUFEBUB fl
PXTGSPNQVCMJD"OEJGUIFOFXQSPKFDUJTUSVMZ HSFFO fi FME EF fi OJUFMZEPOU$234 BTZPVQSPCBCMZXPOUCFBCMFUPBEESFTT "SDIJUFDUVSF%FDJTJPO
"SDIJUFDUVSF$IBSBDUFSJTUJDT $234 &4ɺύϑΥʔϚϯεͱεέʔϥϏϦςΟʹد༩͢Δ ίϚϯυͱΫΤϦΛݸผʹ࠷దԽͰ͖ΔͷͰɺϋΠτϥϑΟοΫ͔ͭڝ߹͕ى͖͍͢ྖҬʹ͘ (SFH:PVOH $234EPDVNFOUTCZ(SFH:PVOH 5IFCPUUMFOFDLJOUFSNTPGTDBMJOHJTUIFEBUBTUPSBHF8IFOVTJOHB3%#.4BT DVSSFOUMZVTFUIJTCFDPNFTFWFONPSFPGBQSPCMFNNPTU3%#.4BSFBUUIJTQPJOUOPU IPSJ[POUBMMZTDBMBCMFBOEWFSUJDBMMZTDBMJOHCFDPNFTQSPIJCJUJWFMZFYQFOTJWFWFSZRVJDLMZ
Πϕϯτόʔδϣχϯάूڥքมߋͷස͕ߴ͍ෆ҆ఆͳྖҬͰมߋίετΛճऩ͢Δͷ͕͍͠
݁Ռ߹ͷΫΤϦϢʔβʔମݧʹతͳӨڹ͕͋Δ ࠷৽Ͱͳ͍σʔλΛݟ͍ͯΔՄೳੑΛɺϢʔβʔମݧʹંΓࠐΜͰ͓͘ઃܭίετͷલ͍͕ඞཁ ໌Β͔ʹεέʔϥϏϦςΟ͕ඞཁͳΒɺϦʔυϨϓϦΧΛޙ͔Βܧ͗͗ͰೖΕΔΑΓྑͦ͞͏ &WFOUVBMMZ$POTJTUFOU2VFSZ
Collaborative Domain Independent Domain 1VCMJD%BUB Ձ֨ 1SJWBUF%BUB ໊ આ໌ ը૾
CRUD, Stereotype Architecture CQRS+ES Publish Data 6EJ%BIBO IUUQTYDPN6EJ%BIBOTUBUVT 1VCMJDEBUBXPVMEOPUCFIBOEMFEJOUIFTBNFWFSUJDBMTMJDFBTUIFQSJWBUFEBUB $234JTBNPSFBQQSPQSJBUFDIPJDFGPSQVCMJDEBUB BOEUIFSF JUDBONBLFTFOTFUPIBWFEJ ff FSFOUWFSUJDBMTMJDFTGPSUIFDPNNBOEBOERVFSZQBSUT #PVOEFE$POUFYU 5PQ-FWFM"SDIJUFDUVSF
3%#ͰʮΠϕϯτʯͱʮϦιʔεʯΛ۠ผ͠ͳ͕ΒɺςʔϒϧΛઃܭ͢Δ Πϕϯτͷ֓೦తԸܙΛड͚ͭͭɺ݁Ռ߹ͷΫΤϦ͕ඞਢͰͳ͘ͳΔ ඞཁͳUBCMFKPJO͕૿͑ͨΓɺΠϯϐʔμϯεϛεϚον͕ܹ͘͠ͳΓ͍͢՝͕͋Δ *NNVUBCMF%BUB.PEFM
package subscription // ूϧʔτ type Subscription struct { ID uuid.UUID
Status Status } // ूϧʔτͷίϚϯυϝιου͕ɺෆม݅Λҡ࣋͠ͳ͕ΒΠϕϯτΛ࡞͢Δ func (s Subscription) Deactivate(deactivateAt time.Time) (Deactivated, error) { // write some invariants here if s.Status == Deactivated { return Deactivated{}, fmt.Errorf("subscription is already deactivated: %w", errors.ErrPreconditionFailed) } return Deactivated{SubscriptionID: s.ID, DeactivateAt: deactivateAt}, nil } // Πϕϯτ type Deactivated struct { SubscriptionID uuid.UUID DeactivatedAt time.Time } func (SubscriptionDeactivated) IsSubscriptionEvent() {} type Event interface { IsSubscriptionEvent() } // ϦϙδτϦ: Πϕϯτͷอଘͱूͷϩʔυ͕Մೳ type Repository interface { Store(context.Context, Event) error Load(context.Context, uuid.UUID) (Subscription, error) } *NQMFNFOUJOH"HHSFHBUF
package command // ίϚϯυ: ૢ࡞ͷ໊લͱͦΕ࣮ߦ͢ΔͨΊʹඞཁͳೖྗσʔλΛ࣋ͭ type DeactivateSubscriptionCommand struct { SubscriptionID
uuid.UUID } // ίϚϯυϓϩηοαʔ: ूʹίϚϯυॲཧΛҕৡ͢Δ func (p DeactivateSubscriptionCommandProcessor) Exec(ctx context.Context, command DeactivateSubscriptionCommand) (subscription.Deactivated, error) { aSubscription, err := p.SubscriptionRepo.Load(ctx, command.SubscriptionID) if err != nil { return subscription.Deactivated{}, fmt.Errorf("subscription.Repository.Load: %w", err) } event, err := aSubscription.Deactivate(time.Now()) if err != nil { return subscription.Deactivated{}, fmt.Errorf("subscription.Subscription.Deactivate: %w", err) } if err := p.SubscriptionRepo.Store(ctx, event); err != nil { return subscription.Deactivated{}, fmt.Errorf("subscription.Repository.Store: %w", err) } if err := p.EventPublisher.Publish(ctx, event); err != nil { return subscription.Deactivated{}, fmt.Errorf("EventPublisher.Publish: %w", err) } return event, nil } *NQMFNFOUJOH$PNNBOE
package redis type SubscriptionDeactivatedEventHandler struct { AsynqClient *asynq.Client } func
(h SubscriptionDeactivatedEventHandler) HandleSubscriptionDeactivated(ctx context.Context, event subscription.Deactivated) error { // ϏδωεϧʔϧΓग़͓ͯ͘͠ if policy.CanDeactivateMembershipcard(event) { payload, err := json.Marshal(task.DeactivateMembershipcardPayload{SubscriptionID: event.SubscriptionID}) if err != nil { return fmt.Errorf("marshal payload: %w", err) } // Ωϡʔʹ٧ΊͯผϓϩηεʹॲཧΛͤΔ _, err = h.AsynqClient.EnqueueContext(ctx, asynq.NewTask(task.DeactivateMembershipcard, payload)) if err != nil { return fmt.Errorf("enqueue process deactivate membershipcard task: %w", err) } } return nil } ˞࣮ߦͰ͖ͳ͍߹ͷϦτϥΠՄೳੑɺෳճ࣮ߦ͞Εͨ߹ͷႈੑɺଞͷΠϕϯτͱͷॱংੑɺΛߟྀ͓ͯ͘͠ඞཁ͋Γ *NQMFNFOUJOH1PMJDZ
package query // ΫΤϦαʔϏε type SubscriptionService interface { QueryPage(ctx context.Context,
filter SubscriptionFilter, sorter SubscriptionSorter, limit int, cursor *string) (Page[Subscription], error) QueryByIDs(context.Context, []string) ([]Subscription, error) QueryByID(context.Context, string) (Subscription, error) } // ΫΤϦϞσϧ type Subscription struct { ID string CustomerID string ProductID string NextRenewAt time.Time LastRenewedAt time.Time } // ϑΟϧλʔ&ιʔτ type SubscriptionFilter struct { CustomerID string } type SubscriptionSorter struct { Key SubscriptionSortKey Direction SortDirection } 2VFSZ4FSWJDF.PEFM
ϞσϧΛோΊͯΈΔͱɺ$234Ͱ࣮͢ΔͱΑͦ͞͏ͳՕॴͱɺͦ͏Ͱͳ͍Օॴ͕͋Δ ɾ͕࣌ؒ࣠ؔ͠ͳ͍ ɾຊདྷతʹޠኮ͕$36%ɺίϚϯυɾΠϕϯτʹແཧʹͯΊ͍ͯΔ ɾ๛ͳϙϦγʔ͕͋Δ ɾ࣌ؒ࣠ͰυϝΠϯ͕มԽ͍ͯ͘͠ ɾ$36%Ͱͳ͍ޠኮͰΓཱ͍ͬͯΔ #VU$36%ʜʁ
$36%ΛϢϏΩλεݴޠʹ͍ͯ͠Δ෦ͷ$234࣮ɺΓແବ ͱ͍͑ผͷΞʔΩςΫνϟύλʔϯͱڞଘͤ͞ΔͷɺҙࢥܾఆͷසֶशίετΛ૿ͯ͠͠·͏ ίϚϯυʹҙਤ͕ͳ͘ɺूͰڧ੍͢Δෆม͕݅ͳ͘ɺΠϕϯτ࣮࣭ूͷεφοϓγϣοτʹʜ package product func (p Product) Update(name Name,
description Description, updateAt time.Time) (ProductUpdated, error) { return ProductUpdated{ ProductID: p.ID, Name: name.value, Description: description.value, UpdatedAt: updateAt, }, nil } #VU$36%ʜʁ
7BVHIO7FSOPO JNQMFNFOUJOHEPNBJOESJWFOEFTJHO ͋·ΓΞʔΩςΫνϟʹؾΛͱΒΕ͗ͯ͢͠·͏ͱɺ %%%Λͬͯҙਂ͘ϞσϧΛ࡞Δ͜ͱ͕ ͓Ζ͔ͦʹͳͬͯ͠·͍͕ͪͩɻ தུ υϝΠϯϞσϧͷ΄͏͕ࣄۀՁΛଟ͘ੜΈग़͢͠ɺ ͦͷӨڹଓ͖͢Δɻ %FTJHO'PS8IPNʁ
෦࣭Λॏཁࢹͭͭ͠ɺ ᘳओٛʹؕΒͳ͍Α͏ʹ͢Δ υϝΠϯͱϢʔβʔͷՁʹ ͳΔͷ͔ʁͱ͍͏͍ʹཱͪΔ
εΩϧɺܦݧɺࢥߟͷҟͳΔਓʑͱίϥϘϨʔγϣϯͯ͠ɺٕज़ͱྗͰυϝΠϯΛਐԽ͍ͤͯ͘͞ ۀΛͦͷ··ιϑτΣΞʹ͢Δ͚ͩͰɺςΫϊϩδʔʹΑΔޮԽҎ্ͷΠϯύΫτى͖ͳ͍ʜ ࣄۀͱϓϩμΫτ͕ޭͨ͠Βɺ$234 &4͕ޮՌతʹ͑ΔྖҬͬͱ૿͍͑ͯͣ͘ʂ $PODMVTJPO ·ͣυϝΠϯʹ͖߹ͬͯɺͦΕ͔Β$234Ͱ࣮͢Δ
8FBSFIJSJOH IUUQTXXXXBOUFEMZDPNDPNQBOJFTDPNQBOZ@ 5IBOLZPVGPSMJTUFOJOH %.!NFNFUJDT ✉ LBCF!EJHJUUMFDPKQ