go-kit / go-kit.github.io

The gokit.io website.
MIT License
21 stars 28 forks source link

New FAQ entries #14

Closed peterbourgon closed 4 years ago

peterbourgon commented 7 years ago
andreaslacza commented 4 years ago

Lets say you want to create a CRUD app like gokit example service profilesvc

In Go kit, services are typically modeled as interfaces, and implementations of those interfaces contain the business logic.

type Service interface {
PostProfile(p Profile) error
GetProfile(id string) (Profile, error)
DeleteProfile(id string) error
}

Persistence — How should I work with databases and data stores? Even better: consider defining an interface to model your persistence operations. The interface will deal in business domain objects, and have an implementation that wraps the database handle.

type Store interface {
    Insert(p Profile) error
    Select(id string) (Profile, error)
    Delete(id string) error
}

type databaseStore struct{ db *sql.DB }

func (s *databaseStore) Insert(p Profile) error            { /* ... */ }
func (s *databaseStore) Select(id string) (Profile, error) { /* ... */ }
func (s *databaseStore) Delete(id string) error            { /* ... */ }

type Service interface {
    PostProfile(p Profile) error
    GetProfile(id string) (Profile, error)
    DeleteProfile(id string) error
}

type MyService struct {
    store  Store
    value  string
    logger *log.Logger
}

func NewService(store Store, value string, logger log.Logger) *MyService {
    return &MyService{
        store:  store,
        value:  value,
        logger: logger,
    }
}

func (s *MyService) PostProfile(p Profile) error           { /* ... */ }
func (s *MyService) GetProfile(id string) (Profile, error) { /* ... */ }
func (s *MyService) DeleteProfile(id string) error         { /* ... */ }

both interfaces share the same methods.

why not?

type Service interface {
    PostProfile(p Profile) error
    GetProfile(id string) (Profile, error)
    DeleteProfile(id string) error
}

type databaseStore struct{ db *sql.DB }

func (s *databaseStore) PostProfile(p Profile) error           { /* ... */ }
func (s *databaseStore) GetProfile(id string) (Profile, error) { /* ... */ }
func (s *databaseStore) DeleteProfile(id string) error         { /* ... */ }

type MyService struct {
    databaseStore  Service
    value          string
    logger         log.Logger
}

func NewService(databaseStore Service, value string, logger log.Logger) *MyService {
    return &MyService{
        databaseStore:  databaseStore,
        value:          value,
        logger:         logger,
    }
}

func (s *MyService) PostProfile(p Profile) error           { /* ... */ }
func (s *MyService) GetProfile(id string) (Profile, error) { /* ... */ }
func (s *MyService) DeleteProfile(id string) error         { /* ... */ }
peterbourgon commented 4 years ago

Because although they may have a similar method set, a Repository layer is, importantly, conceptually distinct from a Service layer.