go-kit/go-kit.github.io

New FAQ entries

peterbourgon opened this issue · 2 comments

  • Introduction — Understanding Go kit key concepts
    • Transport, Endpoint, Service
    • Middlewares in general
    • Endpoint Middleware, Service Middleware
  • Dependency Injection — How do I wire up my Component Graph?
  • Configuration — How should Go kit services be configured?
  • Persistence — How should Go kit services manage persistence?
    • Repository pattern
    • e.g. In-Memory & PostgreSQL
  • Caching — How should Go kit services interface with cache systems?
  • Logging — How should Go kit services manage logs?
  • Metrics — How should Go kit services be instrumented?
  • Service Discovery — How should Go kit services interact with service discovery systems?
  • Templating — What if Go kit services want to render web pages?
  • How do I decide where to place a bit of functionality?

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         { /* ... */ }

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