Pull to refresh

Comments 7

К сожалению на практике это будет выглядеть так:
module.NewServer(
    ":8080",
    module.WithWhitelistedIP("10.0.0.0/8"),
    module.Timeout(10 * time.Second),
    module.TLS(&TLSConfig{})
)

Кажется, такой вариант все же более читаемый с меньшим количеством неймспейсов в коде. И фокус сразу на параметрах:
module.NewServer(&module.ServerOptions{
    Bind: ":8080",
    Whitelist: module.IPRange("10.0.0.0/8"),
    Timeout: 10 * time.Seconds,
    TLS: &TLSConfig{}
})

И в модуле тоже значительно меньше писанины, не нужно будет объявлять функцию на каждый параметр.
Именно так оно порой и выглядит.

Возможно я делаю что-то неправильно, но обычно я совмещаю подходы со структурой конфигурации и функциональными параметрами. Часто конфиги лежат в каком нибудь yaml или json файле и их действительно удобно получать в структуру. А что-то вроде сквозных логгеров со своими настройками или конфигурацией, требующей предварительной обработки, довольно комфортно передаются функционально. Мне кажется, что это выгладит не так уж и монструозно:

log := logger.New()
cfg, err := parseConfigFromSomewhere()
// handle error

module.NewServer(
	cfg,
	module.SetLogger(log),
	module.TLS(&TLSConfig{}),
)
А в чем профит отдельного типа Option, если можно как-то так?

log := logger.New()
cfg, err := parseConfigFromSomewhere()
// handle error

module.NewServer(
	cfg.
		SetLogger(log).
		SetTLS(&TLSConfig{}),
)
Если я вас правильно понял, то в вашем варианте получается, что сам конфиг выглядит примерно так:
Config
type Config struct {
	Bind   string
	logger *logger.Logger
	tls    *tls.Config
}

func (c *Config) SetLogger(log *logger.Logger) *Config {
	c.logger = log
	return c
}

func (c *Config) SetTLS(t *tls.Config) *Config {
	c.tls = t
	return c
}

А сервер так:
Server
type Server struct {
	cfg    Config
	logger *log.Logger
	http   *http.Server
}

func NewServer(cfg *Config) *Server {
	srv := &http.Server{
		Addr:         cfg.Bind,
		TLSConfig:    cfg.tls,
	}

	return &Server{
		cfg:    *cfg,
		logger: cfg.logger,
		http:   srv,
	}
}

С cfg.tls все получилось хорошо, а вот с logger уже не все так просто. Его нужно либо использовать через вызов s.cfg.logger либо выносить из конфига в Server и держать сразу в двух местах. И оба варианта мне не очень нравятся. Также не очень понятно как в NewServer создавать значения по умолчанию без перебора конфига на nil значения. В остальном ваш метод выглядит приятно, спасибо за подсказку.
Статья чисто для ГОшников?) Свои термины выдумали, техники… остальной Мир живёт себе с полиморфными конструкторами и в ус не дует
Согласно этому сайту бенчмарков производительность ГОшки и Явы почти не отличается — так зачем платить больше страдать..?
image
(примечание переводчика — блог с оригинальной статьей Дейва Чейни более не существует, не найдя перепечаток я заменил ссылку на статью ссылкой на видео с его доклада)

Блог на месте. dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
Проблемы доступности ссылки из России известно из-за кого… Поэтому VPN

Спасибо за перевод. Статья полезная.
Подключился через VPN и действительно. Поправлю в статье, но ссылку на видео, пожалуй, тоже оставлю. Спасибо!
Sign up to leave a comment.

Articles