Backend
Functional Options 패턴을 활용한 Go 설정 관리
Go에서 필수 인자와 선택 옵션을 분리해 생성자 API를 안정적으로 유지하는 방법을 정리합니다.
Functional Options 패턴을 활용한 Go 설정 관리
왜 쓰는가
설정 필드가 늘어날수록 생성자 시그니처는 빠르게 깨집니다. Functional Options는 아래 두 가지를 분리해 문제를 줄입니다.
- 필수값: 생성자 인자로 강제
- 선택값:
With...옵션으로 오버라이드
기본 형태
type Config struct {
batchSize int
timeout time.Duration
}
type Option func(*Config)
func WithBatchSize(v int) Option {
return func(c *Config) {
if v > 0 {
c.batchSize = v
}
}
}
func WithTimeout(v time.Duration) Option {
return func(c *Config) {
if v > 0 {
c.timeout = v
}
}
}
func NewWorker(client Client, handler Handler, opts ...Option) *Worker {
cfg := Config{batchSize: 10, timeout: 5 * time.Second}
for _, opt := range opts {
opt(&cfg)
}
return &Worker{client: client, handler: handler, cfg: cfg}
}
실무 규칙
- 필수 의존성(
client,handler)은 절대 옵션으로 내리지 않기 - 옵션 함수에서 유효성 검증 수행
- 기본값은 생성자 내부에서 한 번만 정의
자주 하는 실수
- 옵션끼리 충돌 규칙이 없음 (예: timeout 0 허용)
- 생성자 외부에서 기본값을 중복 관리
- 모든 값을 옵션으로 처리해 필수값 계약 붕괴
요약
Functional Options는 "유연한 설정" 패턴이 아니라 "생성자 안정성" 패턴입니다. 필수/선택 경계를 명확히 유지하면 API가 오래 버팁니다.