Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Tactical DDD patterns in Go

Robert Laszczak
September 19, 2018
84

Tactical DDD patterns in Go

Robert Laszczak

September 19, 2018
Tweet

Transcript

  1. roblaszczak 32 package backlog type ItemID struct{ id.ID } type

    Item struct { id ItemID name string // ... }
  2. roblaszczak 33 package backlog type ItemID struct{ id.ID } type

    Item struct { id ItemID name string // ... }
  3. roblaszczak 34 func NewItem(id ItemID, name string) (*Item, error) {

    if id.Empty() { return nil, ErrItemEmptyID } i := &Item{id: id} if err := i.SetName(name); err != nil { return nil, err } return i, nil }
  4. roblaszczak 35 func NewItem(id ItemID, name string) (*Item, error) {

    if id.Empty() { return nil, ErrItemEmptyID } i := &Item{id: id} if err := i.SetName(name); err != nil { return nil, err } return i, nil }
  5. roblaszczak 36 func (i *Item) SetName(name string) error { if

    name == "" { return ErrItemEmptyName } i.name = name return nil }
  6. roblaszczak 37 func (i *Item) SetName(name string) error { if

    name == "" { return ErrItemEmptyName } i.name = name return nil }
  7. roblaszczak 39 func (i *Item) setName(name string) error { if

    name == "" { return ErrItemEmptyName } i.name = name return nil }
  8. roblaszczak 46 for _, tt := range tests { t.Run(tt.name,

    func(t *testing.T) { s := createTestSprint(t) initialSprintID := tt.i.CommitedSprintID() initialStatus := tt.i.Status() err := tt.i.CommitToSprint(s) assert.Equal(t, tt.wantErr, err) // ... }) }
  9. roblaszczak 47 if tt.wantErr == nil { assert.Equal(t, s.ID(), tt.i.CommitedSprintID())

    assert.Equal( t, tt.i.Status(), backlog.ItemStatusCommited ) } else { assert.Equal(t,initialSprintID,tt.i.CommitedSprintID()) assert.Equal(t, tt.item.Status(), initialStatus) }
  10. roblaszczak 48 if tt.wantErr == nil { assert.Equal(t, s.ID(), tt.i.CommitedSprintID())

    assert.NotEqual(t, s.ID(), initialSprintID) assert.Equal( t, tt.i.Status(), backlog.ItemStatusCommited ) } else { assert.Equal(t,initialSprintID,tt.i.CommitedSprintID()) assert.Equal(t, tt.item.Status(), initialStatus) }
  11. roblaszczak 49 if tt.wantErr == nil { assert.Equal(t, s.ID(), tt.i.CommitedSprintID())

    assert.NotEqual(t, s.ID(), initialSprintID) assert.Equal( t, tt.i.Status(), backlog.ItemStatusCommited ) } else { assert.Equal(t,initialSprintID,tt.i.CommitedSprintID()) assert.Equal(t, tt.item.Status(), initialStatus) }
  12. roblaszczak 50 if tt.wantErr == nil { assert.Equal(t, s.ID(), tt.i.CommitedSprintID())

    assert.NotEqual(t, s.ID(), initialSprintID) assert.Equal( t, tt.i.Status(), backlog.ItemStatusCommited ) } else { assert.Equal(t,initialSprintID,tt.i.CommitedSprintID()) assert.Equal(t, tt.item.Status(), initialStatus) }
  13. roblaszczak 51 func (i *Item) CommitToSprint(s *sprint.Sprint) error { if

    !i.IsScheduledForRelease() { return ErrMustBeScheduledToCommit } if i.IsCommittedToSprint() { i.UncommitFromSprint() } i.setStatus(ItemStatusCommited) i.setSprintID(s.ID()) return nil }
  14. roblaszczak 52 func (i *Item) CommitToSprint(s *sprint.Sprint) error { if

    !i.IsScheduledForRelease() { return ErrMustBeScheduledToCommit } if i.IsCommittedToSprint() { i.UncommitFromSprint() } i.setStatus(ItemStatusCommited) i.setSprintID(s.ID()) return nil }
  15. roblaszczak 53 func (i *Item) CommitToSprint(s *sprint.Sprint) error { if

    !i.IsScheduledForRelease() { return ErrMustBeScheduledToCommit } if i.IsCommittedToSprint() { i.UncommitFromSprint() } i.setStatus(ItemStatusCommited) i.setSprintID(s.ID()) return nil }
  16. roblaszczak 54 func (i *Item) CommitToSprint(s *sprint.Sprint) error { if

    !i.IsScheduledForRelease() { return ErrMustBeScheduledToCommit } if i.IsCommittedToSprint() { i.UncommitFromSprint() } i.setStatus(ItemStatusCommited) i.setSprintID(s.ID()) return nil }
  17. roblaszczak 56 func (i *Item) CommitToSprint(s *sprint.Sprint) error { if

    !i.IsScheduledForRelease() { return ErrMustBeScheduledToCommit } if i.IsCommittedToSprint() { i.UncommitFromSprint() } i.setStatus(ItemStatusCommited) i.setSprintID(s.ID()) return nil }
  18. roblaszczak 57 func (i *Item) CommitToSprint(s *sprint.Sprint) error { if

    !i.IsScheduledForRelease() { return ErrMustBeScheduledToCommit } if i.IsCommittedToSprint() { i.UncommitFromSprint() } i.setStatus(ItemStatusCommited) i.setSprintID(s.ID()) return nil }
  19. roblaszczak 63 func NewPrice(cents int, currency string) (Price, error) {

    if cents <= 0 { return Price{}, ErrCentsTooLow } if len(currency) != 3 { return Price{}, ErrInvalidCurrency } return Price{cents, currency}, nil }
  20. roblaszczak 64 func NewPrice(cents int, currency string) (Price, error) {

    if cents <= 0 { return Price{}, ErrCentsTooLow } if len(currency) != 3 { return Price{}, ErrInvalidCurrency } return Price{cents, currency}, nil }
  21. roblaszczak 65 func NewPrice(cents int, currency string) (Price, error) {

    if cents <= 0 { return Price{}, ErrCentsTooLow } if len(currency) != 3 { return Price{}, ErrInvalidCurrency } return Price{cents, currency}, nil }
  22. roblaszczak 68 func (p Price) Add(toAdd Price) (Price, error) {

    if p.currency != toAdd.currency { return Price{}, ErrCurrencyDoesntMatch } return NewPrice(p.cents+toAdd.cents, p.currency) }
  23. roblaszczak 75 package backlog // …. var ( ErrItemNotFound =

    errors.New("item not found") ErrItemAlreadyExists = errors.New("item already exists") )
  24. roblaszczak 76 type BacklogItemRepository struct { items map[string]backlog.Item } func

    (r *BacklogItemRepository) Add(i *backlog.Item) error { if _, ok := r.items[i.ID().String()]; ok { return backlog.ErrItemAlreadyExists } r.items[i.ID().String()] = *i return nil }
  25. roblaszczak 77 type BacklogItemRepository struct { items map[string]backlog.Item } func

    (r *BacklogItemRepository) Add(i *backlog.Item) error { if _, ok := r.items[i.ID().String()]; ok { return backlog.ErrItemAlreadyExists } r.items[i.ID().String()] = *i return nil }
  26. roblaszczak 78 type BacklogItemRepository struct { items map[string]backlog.Item } func

    (r *BacklogItemRepository) Add(i *backlog.Item) error { if _, ok := r.items[i.ID().String()]; ok { return backlog.ErrItemAlreadyExists } r.items[i.ID().String()] = *i return nil }
  27. roblaszczak 85 func (c CommitBacklogItemToSprintHandler) Handle(cmd CommitBacklogItemToSprint) error { sprint,

    err := c.sprintRepository.ByID(cmd.SprintID) if err != nil { return err } item, err := c.backlogItemRepository.ByID(cmd.BacklogItemID) if err != nil { return err } // ...
  28. roblaszczak 86 func (c CommitBacklogItemToSprintHandler) Handle(cmd CommitBacklogItemToSprint) error { sprint,

    err := c.sprintRepository.ByID(cmd.SprintID) if err != nil { return err } item, err := c.backlogItemRepository.ByID(cmd.BacklogItemID) if err != nil { return err } // ...
  29. roblaszczak 87 func (c CommitBacklogItemToSprintHandler) Handle(cmd CommitBacklogItemToSprint) error { //

    ... if err := item.CommitToSprint(sprint); err != nil { return err } return c.backlogItemRepository.Update(item) }
  30. roblaszczak 88 func (c CommitBacklogItemToSprintHandler) Handle(cmd CommitBacklogItemToSprint) error { //

    … if item.IsCommitedToBacklog() { return err } // … return c.backlogItemRepository.Update(item) }
  31. roblaszczak 89 func (c CommitBacklogItemToSprintHandler) Handle(cmd CommitBacklogItemToSprint) error { //

    … if item.IsCommitedToBacklog() { return err } // … return c.backlogItemRepository.Update(item) }
  32. roblaszczak 93 . ├── app │ └── command ├── domain

    │ ├── backlog │ └── sprint ├── infrastructure │ └── memory └── interfaces └── rest
  33. roblaszczak 98 type Item struct { id ItemID `json:"id"` name

    string `json:"name"` status ItemStatus `json:"status"` releaseSchedule time.Time `json:"release_schedule"` commitedSprintID sprint.ID `json:"commited_sprint_id"` }
  34. roblaszczak 101 type BacklogItemView struct { ID string `json:"id"` Name

    string `json:"name"` } func NewBacklogItemView(item *backlog.Item) BacklogItemView { return BacklogItemView{item.ID().String(), item.Name()} }
  35. roblaszczak 105 type ItemUnmarshalData struct { ID ItemID Name string

    Status ItemStatus ReleaseSchedule time.Time CommitedSprintID sprint.ID } func UnmarshalItem(ud ItemUnmarshalData) *Item { return &Item{ ud.ID, ud.Name, ud.Status, ud.ReleaseSchedule, ud.CommitedSprintID, } }
  36. roblaszczak 106 type ItemUnmarshalData struct { ID ItemID Name string

    Status ItemStatus ReleaseSchedule time.Time CommitedSprintID sprint.ID } func UnmarshalItem(ud ItemUnmarshalData) *Item { return &Item{ ud.ID, ud.Name, ud.Status, ud.ReleaseSchedule, ud.CommitedSprintID, } }