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
イベントソーシングとドメインモデリング
Search
Kosuke Abe
December 22, 2024
290
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
イベントソーシングとドメインモデリング
Kosuke Abe
December 22, 2024
Featured
See All Featured
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.7k
Everyday Curiosity
cassininazir
0
350
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
460
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.6k
Why Our Code Smells
bkeepers
PRO
340
58k
Design in an AI World
tapps
1
350
Marketing to machines
jonoalderson
1
5.9k
Odyssey Design
rkendrick25
PRO
2
870
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.5k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
brightonSEO & MeasureFest 2025 - Winning Strategies for Black Friday CRO & PPC - Christian Goodrich
cargoodrich
3
870
Transcript
ΠϕϯτιʔγϯάͱυϝΠϯϞσϦϯά ,PTVLF"CF $234 &4ΧϯϑΝϨϯε !NFNFUJDT
Πϕϯτιʔγϯά༏Ε͍ͯΔ͕ϕετϓϥΫςΟεͰͳ͍ εέʔϥϏϦςΟσʔλͱͯ͠ͷՁඇৗʹߴ͍ҰํͰɺ ࢄγεςϜతͳඇಉظॲཧɺεφοϓγϣοτɺ Πϕϯτόʔδϣχϯάɺूͷू߹ͷόϦσʔγϣϯͳͲɺ ෳͷٕज़తϋʔυϧ͕͋Δɻ l"SFUIFTFDPTUTXPSUIUIF30*XIFO UIFCVTJOFTTEFSJWFTBDPNQFUJUJWFBEWBOUBHFGSPNUIFEBUB z(SFH:PVOH l&WFOU4PVSDJOHJTBQBUUFSOUIBU DBO
CFVTFEXJUIJOB#PVOEFE$POUFYU MJLFBO40"TFSWJDF CVUJTPGUFOUPPIFBWZXFJHIUUPCFKVTUJ fi FEz6EJ%BIBO
ΠϕϯτυϝΠϯϞσϦϯάͷཁ ʮϞϊʯͷ$36%Ͱͳ͘ʮίτʯΛੳ͢Δ͜ͱͰɺ;Δ ·͍๛͔ͳυϝΠϯϞσϧ͕खʹೖΔ l5IJTNFBOTUIBUUIFSFBSFOPPUIFSWFSCTXJUIJOUIFEPNBJO8IFO IPXFWFSPOFUBMLTXJUIEPNBJOFYQFSUTJOBOF ff PSUUPSF fi OFBO6CJRVJUPVT -BOHVBHF
JUJTFYUSFNFMZSBSFUIBUPOFFOETVQXJUIBMBOHVBHFUIBUJT GPDVTFEPOUIFTFGPVSWFSCTz(SFH:PVOH lΠϕϯτιʔγϯά෦ઃܭ্ͷςʔϚͰ͋ͬͯɺσʔλϞσϧ্ͷ֓೦Ͱ͋ Γ·ͤΜɻ தུ ཤྺ͔Β࠶ݱ͞ΕΔ࠷৽σʔλͷܗ͚ͩΛʹ͢ΕΑ͍Θ͚ Ͱ͢ɻͦΕͷΈ͕ۀϢʔβʔͷؔ৺͝ͱ͔ͩΒͰ͢ɻzʰσʔλϞσϦϯάͰυϝ ΠϯΛۦಈ͢Δʱਿຊܒ
Πϕϯτιʔγϯά30*ʹݟ߹Θͳ͍ͱͯ͠ɺ ΠϕϯτΛத৺ͱͨ͠υϝΠϯϞσϦϯάͱ࣮͍ͨ͠ Πϕϯτιʔγϯά෦ઃܭ͕ͩɺ Πϕϯτͷ֓೦υϝΠϯϞσϧͷҰ෦ͱͯ͠֎෦ઃܭʹͳΔ
type ArchiveArticleCommandService struct { Repository article.Repository } type ArchiveArticleCommand struct
{ ArticleID uuid.UUID } func (s ArchiveArticleService) Handle(ctx context.Context, command ArchiveArticleCommand) (article.Archived, error) { current := time.Now() anArticle, err := s.Repository.Find(ctx, command.AccountID) if err != nil { return account.Archived{}, errors.New(...) } event, err := anArticle.Archive(current) if err != nil { return account.Archived{}, errors.New(...) } if err := s.Repository.PersistEvent(ctx, event); err != nil { return account.Archived{}, errors.New(...) } return event }
type ArchiveArticleCommandService struct { Repository article.Repository } type ArchiveArticleCommand struct
{ ArticleID uuid.UUID } func (s ArchiveArticleService) Handle(ctx context.Context, command ArchiveArticleCommand) (article.Archived, error) { current := time.Now() anArticle, err := s.Repository.Find(ctx, command.AccountID) if err != nil { return account.Archived{}, errors.New(...) } event, err := anArticle.Archive(current) if err != nil { return account.Archived{}, errors.New(...) } if err := s.Repository.PersistEvent(ctx, event); err != nil { return account.Archived{}, errors.New(...) } return event } ϦϙδτϦ͔ΒهࣄूΛऔಘ
type ArchiveArticleCommandService struct { Repository article.Repository } type ArchiveArticleCommand struct
{ ArticleID uuid.UUID } func (s ArchiveArticleService) Handle(ctx context.Context, command ArchiveArticleCommand) (article.Archived, error) { current := time.Now() anArticle, err := s.Repository.Find(ctx, command.AccountID) if err != nil { return account.Archived{}, errors.New(...) } event, err := anArticle.Archive(current) if err != nil { return account.Archived{}, errors.New(...) } if err := s.Repository.PersistEvent(ctx, event); err != nil { return account.Archived{}, errors.New(...) } return event } هࣄूʹʮΞʔΧΠϒͨ͠ʯ ΠϕϯτΛ࡞ͤ͞Δ
type ArchiveArticleCommandService struct { Repository article.Repository } type ArchiveArticleCommand struct
{ ArticleID uuid.UUID } func (s ArchiveArticleService) Handle(ctx context.Context, command ArchiveArticleCommand) (article.Archived, error) { current := time.Now() anArticle, err := s.Repository.Find(ctx, command.AccountID) if err != nil { return account.Archived{}, errors.New(...) } event, err := anArticle.Archive(current) if err != nil { return account.Archived{}, errors.New(...) } if err := s.Repository.PersistEvent(ctx, event); err != nil { return account.Archived{}, errors.New(...) } return event } ʮΞʔΧΠϒͨ͠ʯΠϕϯτΛ ϦϙδτϦʹͯ͠ӬଓԽ
type ArticleRepository struct { Conn sqlx.DB } func (r ArticleRepository)
PersistEvent(ctx context.Context, event article.Event) error { switch e := event.(type) { case article.Archived: if _, err := r.Conn.ExecContext(ctx, `INSERT INTO article_archivements (article_id, archived_at) VALUE (?, ?)`, e.ArticleID, e.ArchivedAt); err != nil { return errors.New(...) } case ... default: return errors.New(...) } } func (r ArticleRepository) Find(ctx context.Context, id uuid.UUID) (*article.Article, error) { var data articleData if err := r.Conn.GetContext(ctx, data, `SELECT articles.id, .... FROM articles WHERE articles.id = ?`); err != nil { return nil, errors.New(...) } return r.convertToAggregate(data), nil } શͯΛΠϕϯτͱͯ͠ӬଓԽ͢ΔͷͰͳ͘ɺ ϦιʔεͱΠϕϯτͷ྆ํΛ3%#ͷςʔϒϧͰදݱɻ ΠϕϯτͷӬଓԽͱूͷ࠶ߏங͚ͩͰͳ͘ɺ ΫΤϦϞσϧͷߏஙʹ͑ΔΑ͏ʹ ςʔϒϧΛઃܭ͢Δɻ ΠϕϯτछผʹԠͯ͡ߋ৽ܥͷ42-Λൃߦ ϦιʔεͱΠϕϯτ͔ΒूΛ࠶ߏங
͜ͷ࣮ͷϝϦοτͱσϝϦοτ 👍 ɾϦιʔεͷߋ৽ΛҰఆڐ༰͢ΔͨΊɺશͳΠϕϯτཤྺΒͳ͍ 👎 ɾΠϕϯτத৺ͷυϝΠϯϞσϧΛ࣮Ͱ͖Δ ɾΠϕϯτιʔγϯάͷ࣮ݱʹඞཁͳίετΛΘͣʹࡁΉ ɾΠϯϐʔμϯεϛεϚον͕େ͖͘ͳΔ͜ͱ͕͋Δ