Go의 구조 정의에 따라 Functional Options Pattern 코드를 자동으로 생성하는 CLI 도구를 제작했습니다.

24707 단어 Go자동 생성tech
Go에서 선택적 매개변수를 구현할 때 Functional Options Pattern을 자주 사용하려고 합니다.이 디자인 모델은 매우 편리하지만 구조에서 선택할 수 있는 매개 변수를 준비하려면 선택할 수 있는 매개 변수에 사용할 함수를 설치해야 하기 때문에 기술해야 하는 코드가 많아지기 쉽다.
이 문제를 해결하기 위해 Functional Options Pattern을 구현하는 코드를 자동으로 생성하는 CLI 도구'foggo'를 제작했다.
https://github.com/s14t284/foggo

이른바 Functional options Pattern


Go는 간단한 언어 규범에서 선택할 수 있는 파라미터를 제공하지 않았다.
옵션 매개 변수는 기본 매개 변수 또는 옵션 매개 변수라고도 하는데 파이톤은 가변 길이 매개 변수*args 또는*kargs를 가리킨다.
일반적인 함수라면 문제없지만 구조체 초기화에 사용되는 함수와 프로그램 라이브러리를 제공할 때 생략할 수 있는 인자를 원할 때가 있습니다.
이 생략 가능한 매개변수를 구현하기 위해 Functional Options Pattern(FOP)이 사용됩니다.
FOP는 우버의 Go Style Guide와 go-patterns에도 소개됐다.
https://github.com/uber-go/guide/blob/master/style.md#functional-options
https://github.com/tmrts/go-patterns/blob/master/idiom/functional-options.md
다음은 go-patterns가 제시한 FOP의 예입니다.
FOP는 옵션 매개변수에 값을 대입하는 함수를 정의하는 고급 함수와 가변 길이 매개변수로 고급 함수를 초기화하는 함수를 정의하는 옵션 구조를 정의합니다.
사용자는 매개 변수에서 초기화에 사용할 함수를 선택할 수 있는 함수로 지정합니다.
// Options
package file

type Options struct {
	UID         int
	GID         int
	Flags       int
	Contents    string
	Permissions os.FileMode
}

type Option func(*Options)

func UID(userID int) Option {
	return func(args *Options) {
		args.UID = userID
	}
}

func GID(groupID int) Option {
	return func(args *Options) {
		args.GID = groupID
	}
}

// Contents, Permissions については省略

// Constructor
func New(filepath string, setters ...Option) error {
	// Default Options
	args := &Options{
		UID:         os.Getuid(),
		GID:         os.Getgid(),
		Contents:    "",
		Permissions: 0666,
		Flags:       os.O_CREATE | os.O_EXCL | os.O_WRONLY,
	}

	for _, setter := range setters {
		setter(args)
	}

	f, err := os.OpenFile(filepath, args.Flags, args.Permissions)
	if err != nil {
		return err
	} else {
		defer f.Close()
	}

	if _, err := f.WriteString(args.Contents); err != nil {
		return err
	}

	return f.Chown(args.UID, args.GID)
}

// Usage
// emptyFile, err := file.New("/tmp/empty.txt")
// fillerFile, err := file.New("/tmp/file.txt", file.UID(1000), file.Contents("Lorem Ipsum Dolor Amet"))
또한 상기 FOP의 실현 방법에서 함수로 선택할 수 있는 매개 변수를 정의했기 때문에 모듈을 사용하여 테스트할 수 없는 문제가 존재한다.
다음 기사에서도 이 문제를 해결할 FOP 모델을 제시했다.
(질문은 다음 기사를 참조하십시오.)
https://ww24.jp/2019/07/go-option-pattern
https://zenn.dev/sanpo_shiho/articles/c06f6b156029a5
이 글은 선택할 수 있는 매개 변수를'선택할 수 있는 매개 변수와 apply 함수를 가진 구조'로 정의하는 방법을 소개했다.
package file

type Options struct {
	UID         int
	GID         int
	Flags       int
	Contents    string
	Permissions os.FileMode
}

type Option interface {
	apply(*Options)
}

type UIDOption struct {
	UID int
}

func (o UIDOption) apply(s *Options) {
	s.UID = o.UID
}

type GIDOption struct {
	GID int
}

func (o GIDOption) apply(s *Options) {
	s.GID = o.GID
}

// (Contents, Permissions については省略)

func New(filepath string, setters ...Option) error {
	// 重複箇所については省略
	...

	for _, setter := range setters {
		setter.apply(args)
	}

	...

	return f.Chown(args.UID, args.GID)
}

Function Options Pattern 설치 관련 질문


FOP는 옵션의 수량에만'대입 매개 변수의 고급 함수'와'옵션용 구조체 +apply 함수'를 설치해야 하기 때문에 옵션이 많으면 그에 상응하는 설치도 팽창한다.
또한 선택할 수 있는 매개 변수는 고급 함수나 구조체의 매개 변수를 함수 매개 변수에 대입하는 함수apply로 정의되어 있어 처음 보면 이해하기 어렵다.
이해하기 전에 도입을 망설일 수도 있습니다.
이러한 이중화, 가져오기 전의 장애를 제거하기 위해 FOP를 자동으로 생성하는 CLI 도구를 만들었습니다.

foggo의 소개


foggo Go의 구조 정의에 따라 FOP가 자동으로 생성됩니다.go install 다음과 같이 가져옵니다.
# foggo では自動生成したコードの整形に goimports を利用するため、先にインストールしてください
$ go install golang.org/x/tools/cmd/goimports@latest
$ go install github.com/s14t284/foggo@latest
foggo는 fop과 afop 두 개의 하위 명령을 제공합니다.
fop은 FOP의 소개를 통해 최초로 접촉한 모드의 코드를 자동으로 생성할 수 있다.
afop은 함수apply를 구현하는 FOP 코드를 자동으로 생성할 수 있습니다.여기 기사.에서 실현 함수의 FOP를 Applicable Function Optional Pattern으로 명명하여 afop이라고 약칭한다.

사용법


foggo에서는 명령선을 통해 FOP를 자동으로 생성하는 것과 apply를 통해 두 가지를 자동으로 생성하는 것을 지원한다.
여기에는 go:generate에 따라 FOP가 자동으로 생성되는 방법이 소개되어 있습니다.
우선 선택할 수 있는 매개 변수의 구조를 다음과 같이 준비해야 한다.
구조를 자동으로 생성하려는 함수를 정의한 파일에 기술하십시오go:generate.
file/options.go
package file

//go:generate foggo fop --struct Options
type Options struct {
	UID         int
	GID         int
	// オプションを作成したくないパラメータには `foggo:"-"` タグを付与してください
	Flags       int `foggo:"-"`
	Contents    string
	Permissions os.FileMode
}
그런 다음 go:generate foggo fop --struct {構造体名} 명령을 실행합니다.
$ go generate ./...
를 실행하면 go generate 아래 코드가 자동으로 생성됩니다.
file/options_gen.go
// Code generated by foggo; DO NOT EDIT.

package file

import "os"

type OptionsOption func(*Options)

func NewOptions(options ...OptionsOption) *Options {
	s := &Options{}

	for _, option := range options {
		option(s)
	}

	return s
}

func WithUID(UID int) OptionsOption {
	return func(args *Options) {
		args.UID = UID
	}
}

func WithGID(GID int) OptionsOption {
	return func(args *Options) {
		args.GID = GID
	}
}

func WithPermissions(Permissions os.FileMode) OptionsOption {
	return func(args *Options) {
		args.Permissions = Permissions
	}
}
그리고 필요에 따라 자동으로 생성된 초기화 함수와 옵션을 사용하십시오.
goo-patterns FOP의 실시 예시를 재현하려면 옵션 초기화에 사용되는 함수를 제외하고 파일 열기/쓰기 함수를 위한 옵션을 사용해야 한다.
package file

func NewFile(filepath string, options *Options) error {
	flags := os.O_CREATE | os.O_EXCL | os.O_WRONLY
	f, err := os.OpenFile(filepath, flags, options.Permissions)
	if err != nil {
		return err
	} else {
		defer f.Close()
	}
	if _, err := f.WriteString(options.Contents); err != nil {
		return err
	}

	return f.Chown(options.UID, options.GID)
}

// 以下のように必要に応じてオプションを絞って構造体を初期化する関数を用意すると良い
func NewFileWithContentAndPermissions(filepath, content string, permissions os.FileMode) error {
	options := NewOptions(
		WithUID(os.Getuid()),
		WithGID(os.Getgid()),
		WithContents(content),
		WithPermissions(permissions),
	)
	return NewFile(filepath, options)
}

file/options_gen.go명령의 집행례를 확인하십시오README.

주의점


코드가 자동으로 생성되는 상황에 따라 다음과 같은 문제가 있습니다.
  • 가변 길이의 매개 변수만 있는 함수를 자동으로 생성하기 위해 선택할 수 있는 매개 변수 이외의 매개 변수가 필요한 경우 함수를 따로 설치해야 한다.
  • 기본값을 초기화하는 함수에서 정의할 수 없기 때문에 기본값이 무엇인지 알기 어렵다
  • 그럼에도 FOP를 실현하기 위해 기술해야 할 코드가 줄어든 것은 의미가 있다.
    해결책이 있다면 의견을 얻었으면 좋겠어요.

    끝맺다


    FOP를 자동으로 생성하는 CLI 도구 foggo에 대한 설명입니다!
    foggo를 사용하여 FOP를 실현하는 간단한 조작에서 한 사람이 해방되면 좋겠다.
    개선 방안이 있다면 반드시 이슈를 홍보해 주십시오.

    참고 자료


  • 전문가들의 Go 언어.(이 책을 통해 FOP와 코드의 자동 생성을 알 수 있음)

  • gonstructor(자동 생성 구조기의 CLI. 이 CLI 도구로foggo의 구상을 얻었다)
  • 좋은 웹페이지 즐겨찾기