Go에서 깨끗한 인터페이스를 작성하기 위한 모범 사례



인터페이스를 사용하면 특정 동작과 관련하여 서로 다른 유형을 동일한 유형으로 취급할 수 있습니다. 그들은 Go 프로그래머 도구 벨트의 중심이며 새로운 Go 개발자가 부적절하게 사용하는 경우가 많습니다… 읽기 어렵고 버그가 많은 코드로 이어집니다.


인터페이스는 명명된 메서드 서명 모음이며 Go에서 일종의 다형성을 달성하는 방법입니다.

인터페이스 요약



깨끗한 Go를 작성하는 방법의 예로 표준 라이브러리를 살펴보겠습니다. 오류 인터페이스는 간단합니다.

type error interface {
    Error() string
}


정의에 따라 오류 인터페이스는 Error() 메서드가 정의된 모든 유형을 캡슐화하고 매개변수를 허용하지 않으며 문자열을 반환합니다. 예를 들어 네트워크 문제를 나타내는 구조체를 정의해 보겠습니다.

type networkProblem struct {
    message string
    code int
}


그런 다음 Error() 메서드를 정의합니다.

func (np networkProblem) Error() string {
    return fmt.Sprintf("network error! message: %s, code: %v", np.message, np.code)
}


이제 오류가 허용되는 모든 곳에서 networkProblem 구조체의 인스턴스를 사용할 수 있습니다.

func handleErr(err error) {
    fmt.Println(err.Error())
}

np := networkProblem{
    message: "we received a problem",
    code: 404,
}

handleErr(np)

// prints "network error! message: we received a problem, code: 404"


인터페이스를 작게 유지



이 기사에서 얻을 수 있는 조언이 하나뿐이라면 다음과 같이 하십시오. 인터페이스를 작게 유지하십시오! 인터페이스는 일부 엔터티를 정확하게 나타내는 데 필요한 최소한의 동작을 정의하기 위한 것입니다.

다음은 최소한의 동작을 정의하는 좋은 예로 남아 있는 더 큰 인터페이스의 예입니다.

type File interface {
    io.Closer
    io.Reader
    io.Seeker
    Readdir(count int) ([]os.FileInfo, error)
    Stat() (os.FileInfo, error)
}


http.파일 – https://golang.org/pkg/net/http/#pkg-overview

인터페이스의 동작을 만족하는 모든 유형은 HTTP 패키지에서 파일로 간주할 수 있습니다. 이것은 HTTP 패키지가 디스크의 파일, 네트워크 버퍼 또는 간단한 []바이트를 처리하는지 알 필요가 없기 때문에 편리합니다.

인터페이스는 만족하는 유형에 대한 지식이 없어야 합니다.



인터페이스는 다른 유형이 해당 인터페이스의 구성원으로 분류하는 데 필요한 것을 정의해야 합니다. 그들은 디자인 타임에 인터페이스를 만족시키는 어떤 유형도 인식하지 않아야 합니다.

예를 들어 자동차를 정의하는 데 필요한 구성 요소를 설명하는 인터페이스를 구축한다고 가정해 보겠습니다.

type car interface {
    GetColor() string
    GetSpeed() int
    IsFiretruck() bool
}


GetColor() 및 GetSpeed()는 완벽하게 이해되며 자동차 범위에 국한된 메서드입니다. IsFiretruck()은 안티 패턴입니다. 우리는 모든 차량이 소방차인지 여부를 표시하도록 강제하고 있습니다. 이 패턴이 어느 정도 의미가 있으려면 가능한 하위 유형의 전체 목록이 필요합니다. IsPickup(), IsSedan(), IsTank()… 어디서 끝나요??

대신 개발자는 자동차 인터페이스의 인스턴스가 제공될 때 기본 유형을 파생시키기 위해 type assertion의 기본 기능에 의존해야 합니다. 또는 하위 인터페이스가 필요한 경우 다음과 같이 정의할 수 있습니다.

type firetruck interface {
    car
    HoseLength() int
}


자동차에서 필수 메소드를 상속하고 필수 메소드를 하나 더 추가합니다.

인터페이스는 클래스가 아닙니다



인터페이스는 클래스가 아니며 더 얇습니다.

인터페이스에는 데이터 생성 또는 소멸을 요구하는 생성자 또는 분해자가 없습니다.

인터페이스는 본질적으로 계층적이지 않지만 다른 인터페이스의 상위 집합이 되는 인터페이스를 만드는 구문 설탕이 있습니다.

인터페이스는 함수 서명을 정의하지만 기본 동작은 정의하지 않습니다. 즉, 인터페이스를 만들면 구조체 메서드와 관련하여 코드가 건조되지 않는 경우가 많습니다. 다섯 가지 유형이 오류 인터페이스를 충족하는 경우 모두 자체 버전의 Error() 함수가 필요합니다.

읽어 주셔서 감사합니다



질문이나 의견이 있으면 트위터로 연락주세요.

Dev.to의 레인:

게시물 Best Practices For Writing Clean Interfaces in GoQvault에 처음 나타났습니다.

좋은 웹페이지 즐겨찾기