sequence

This paper mainly appreciates the practice of Go-bank-Transfer for Clean Architecture

The project structure

├ ─ ─ adapter │ ├ ─ ─ API │ │ ├ ─ ─ action │ │ ├ ─ ─ logging │ │ ├ ─ ─ middleware │ │ └ ─ ─ the response │ ├ ─ ─ logger │ ├ ─ ─ presenter │ ├── Repository │ ├─ Heavy ├─ Infrastructure │ ├─ Database │ ├─ router │ ├─ Validation ├─ usecaseCopy the code

There are four layers: Adapter, Domain, Infrastructure, and usecase

domain

account

type AccountID string

func (a AccountID) String() string {
	return string(a)
}

type (
	AccountRepository interface {
		Create(context.Context, Account) (Account, error)
		UpdateBalance(context.Context, AccountID, Money) error
		FindAll(context.Context) ([]Account, error)
		FindByID(context.Context, AccountID) (Account, error)
		FindBalance(context.Context, AccountID) (Account, error)
	}

	Account struct {
		id        AccountID
		name      string
		cpf       string
		balance   Money
		createdAt time.Time
	}
)

func NewAccount(ID AccountID, name, CPF string, balance Money, createdAt time.Time) Account {
	return Account{
		id:        ID,
		name:      name,
		cpf:       CPF,
		balance:   balance,
		createdAt: createdAt,
	}
}

func (a *Account) Deposit(amount Money) {
	a.balance += amount
}

func (a *Account) Withdraw(amount Money) error {
	if a.balance < amount {
		return ErrInsufficientBalance
	}

	a.balance -= amount

	return nil
}

func (a Account) ID() AccountID {
	return a.id
}

func (a Account) Name() string {
	return a.name
}

func (a Account) CPF() string {
	return a.cpf
}

func (a Account) Balance() Money {
	return a.balance
}

func (a Account) CreatedAt() time.Time {
	return a.createdAt
}

func NewAccountBalance(balance Money) Account {
	return Account{balance: balance}
}
Copy the code

Account defines the AccountRepository interface and account type. It also provides the Withdraw and Deposit methods

transfer

type TransferID string

func (t TransferID) String() string {
	return string(t)
}

type (
	TransferRepository interface {
		Create(context.Context, Transfer) (Transfer, error)
		FindAll(context.Context) ([]Transfer, error)
		WithTransaction(context.Context, func(context.Context) error) error
	}

	Transfer struct {
		id                   TransferID
		accountOriginID      AccountID
		accountDestinationID AccountID
		amount               Money
		createdAt            time.Time
	}
)

func NewTransfer(
	ID TransferID,
	accountOriginID AccountID,
	accountDestinationID AccountID,
	amount Money,
	createdAt time.Time,
) Transfer {
	return Transfer{
		id:                   ID,
		accountOriginID:      accountOriginID,
		accountDestinationID: accountDestinationID,
		amount:               amount,
		createdAt:            createdAt,
	}
}

func (t Transfer) ID() TransferID {
	return t.id
}

func (t Transfer) AccountOriginID() AccountID {
	return t.accountOriginID
}

func (t Transfer) AccountDestinationID() AccountID {
	return t.accountDestinationID
}

func (t Transfer) Amount() Money {
	return t.amount
}

func (t Transfer) CreatedAt() time.Time {
	return t.createdAt
}
Copy the code

Transfer defines the TransferRepository interface and transfer type

usecase

➜ usecase git:(master) ├─ create_account.go ├─ create_account_test. Go ├─ create_account_test Create_transfer_test. Go ├── Find_account_balance. Go ├─ find_account_balance_Test. Go ├─ Find_account_balance_test ├── ├─ ├─ ├─ ├.goCopy the code

This layer defines CreateAccountUseCase and CreateAccountPresenter, CreateTransferUseCase and CreateTransferPresenter, and FindAccountBalanceUseCas E and FindAccountBalancePresenter, FindAllAccountUseCase and FindAllAccountPresenter, FindAllTransferUseCase and FindAllTransferPresen Ter interface

adapter

➜ adapter git:(master) tree. ├─ API │ ├─ action │ ├─ go │ ├─ create_account_test Go │ ├─ Heavy Metal Guitar School. Go │ ├─ Heavy metal Guitar School. Go │ ├─ Heavy metal Guitar School │ │ ├ ─ ─ find_all_account. Go │ │ ├ ─ ─ find_all_account_test. Go │ │ ├ ─ ─ find_all_transfer. Go │ │ ├ ─ ─ Go │ ├─ ├─ ├─ ├─ go │ ├─ go │ ├─ go │ ├─ go │ ├─ go │ ├─ go │ ├─ go │ ├─ go │ ├─ go │ ├─ Info. Go │ ├ ─ ─ middleware │ │ └ ─ ─ logger. Go │ └ ─ ─ the response │ ├ ─ ─ error. Go │ └ ─ ─ success. Go ├ ─ ─ logger │ └ ─ ─ logger. Go ├ ─ ─ Go │ ├─ Create_Transfer. Go │ ├─ Create_transfer. Go │ ├─ Create_transfer_test Go │ ├─ Heavy Metal Guitar School ─ Heavy metal Guitar School. Go │ Heavy metal Guitar School ─ Heavy metal Guitar School │ ├ ─ ─ find_all_transfer. Go │ └ ─ ─ find_all_transfer_test. Go ├ ─ ─ the repository │ ├ ─ ─ account_mongodb. Go │ ├ ─ ─ Account_postgres. Go │ ├ ─ ─ no. Go │ ├ ─ ─ SQL. Go │ ├ ─ ─ transfer_mongodb. Go │ └ ─ ─ transfer_postgres. Go └ ─ ─ the validator └ ─ ─ validator.goCopy the code

The Adapter layer implements the interface defined by the Domain and usecase layer

summary

Go-bank-transfer project defines model and Repository interface in domain layer, usecase layer defines USecase and Presenter interface, and at the same time calls domain layer to realize business choreography. Adapter implements the interfaces defined by the two layers above.

doc

  • go-bank-transfer