인터페이스와 최소 특권 원칙

인터페이스는 확장되고 읽을 수 있는 코드를 작성하는 데 있어 매우 강력한 추상적인 개념이지만, 언제, 어떻게 사용하는지 개발하는 것은 항상 쉽지 않다.시간과 실천은 대체할 수 없지만 최소한의 특권 원칙은 정보 안전 문제(예를 들어 IAM(신분과 액세스 관리)에 가장 많이 사용되는 개념이다. 인터페이스가 코드에서 맡은 역할을 생각하는 데 유용한 구조를 제공할 수 있다.

최저 특권 원칙
구체적인 형식이 아닌 인터페이스를 매개 변수로 함수를 작성할 때, 인터페이스가 공개된 행위에만 접근할 수 있습니다.매개 변수로 사용되는 실제 대상이나 구조에는 다른 데이터나 기능이 있을 수 있지만, 이러한 속성은 함수에 숨겨져 있다.
함수 파라미터를 제한하는 가시적인 행위는 클라우드 기반 응용 프로그램 구성원이 접근할 수 있는 서비스와 자원을 제한하는 것과 유사하다.제품의 경우 최종 사용자가 데이터를 볼 수 있기를 원하지만 데이터를 업데이트하거나 다른 항목을 추가할 수 없습니다.같은 응용 프로그램에 대해 서버 기능이 없을 수도 있습니다. 데이터를 볼 뿐만 아니라 변경도 필요합니다.그러면 콘텐츠를 지울까요?이것은 관리 권한을 가진 개발자를 위한 작업일 수 있습니다.
IAM을 관리할 때 세 멤버에 대한 종합적인 액세스 요구 사항을 충족하는 관리 수준의 액세스 권한을 제공할 수 있습니다.이 솔루션을 사용하면 개발자가 적절히 작업을 수행할 수 있지만 엔드 유저와 서버 기능이 없는 데이터가 불법으로 업데이트되거나 삭제될 위험이 있습니다.이런'최소 공분모'의 IAM 방법은 최소 특권 원칙에 어긋난다.
최소 특권 원칙에 따르면 자원이나 서비스를 제공하는 사용자는 예상한 합법적인 임무를 수행하는 데 필요한 최소 권한만 가져야 한다.
함수나 방법의 경우, 우리는 이 원칙을 다시 쓸 수 있습니다. 함수의 매개 변수 형식은 함수가 예상한 합법적인 작업을 수행할 수 있도록 충분한 유형 행위만 표시해야 합니다.

코드의 최소 특권 원칙을 설명하다
이 아이디어를 설명하기 위해 GCP(곡가운 플랫폼)의 자원과 역할을 바탕으로 Go에서 인터페이스와 구조를 만들 것입니다.
이미지나 zip 파일 등 다양한 유형의 데이터를 저장하는 Bucket이라는 논리적 그룹으로 나눌 수 있는 블로그 저장소 서비스인 Google Cloud Storage를 에뮬레이션하는 애플리케이션을 구축합니다.
클라우드 메모리 통 역할을 하는 것은 Go struct(대상 언어를 향한 클래스와 유사)입니다.이 구조에는 속성 Blobs 이 있습니다. 키와 데이터 형식을 값으로 하는 문자열입니다.
// interface{} in Go is an interface that defines no behavior
// and is similar to the `any` type in other languages
type CloudStorageBucket struct {
    Blobs map[string]interface{}
}
다음에, 우리는 CloudStorageBucket를 만드는 데 사용할 새로운 실례를 정의하고,blob를 보기, 만들기, 삭제하는 데 사용할 조수 방법을 정의할 것입니다.
func NewCloudStorageBucket() *CloudStorageBucket {
    return &CloudStorageBucket{
        Blobs: make(map[string]interface{}),
    }
}

// the variable 'ok' is a boolean value that will return true if 
// the key you're trying to access exists for the given map
func (cs CloudStorageBucket) ViewBlob(key string) (interface{}, error) {
    if blob, ok := cs.Blobs[key]; ok {
        return blob, nil
    }

    return nil, fmt.Errorf("no blob found with key %s", key)
}

func (cs CloudStorageBucket) CreateBlob(key string, contents interface{}) error {
    if _, ok := cs.Blobs[key]; !ok {
        cs.Blobs[key] = contents
        return nil
    }

    return fmt.Errorf("blob with key %s already exists", key)
}

func (cs CloudStorageBucket) DeleteBlob(key string) (interface{}, error) {
    if blob, ok := cs.Blobs[key]; ok {
        delete(cs.Blobs, key)
        return blob, nil
    }

    return nil, fmt.Errorf("no blob found with key %s", key)
}
이로써 클라우드 메모리통의 기본적인 실현이 완성되었다.

메모리 통 권한을 인터페이스로 정의하기
클라우드 메모리 통의 접근 권한으로 주의를 돌리고, 이 서비스 사용자가 사용할 수 있는 행동을 보기, 만들기, 삭제하는 세 가지 인터페이스를 만들 것입니다.
type CloudStorageViewer interface {
    ViewBlob(cs *CloudStorageBucket, key string) (interface{}, error)
}

type CloudStorageCreator interface {
    CreateBlob(cs *CloudStorageBucket, key string, contents interface{}) error
}

type CloudStorageDeleter interface {
    DeleteBlob(cs *CloudStorageBucket, key string) (interface{}, error)
}
모든 인터페이스는 하나의 방법만 정의한다. 왜냐하면 그것은 단지 하나의 행위를 공개하는 데에만 관심을 가지기 때문이다.더 복잡한 용례가 나타날 때 그것들도 함께 조합할 수 있다.
// creating an admin interface by composing together three 
// single method interfaces
type CloudStorageAdmin interface {
    CloudStorageViewer
    CloudStorageCreator
    CloudStorageDeleter
}

스토리지 통 사용자 생성
이를 실현하기 위해 우리는 세 가지 서로 다른 유형의 사용자에서 이러한 인터페이스를 실현할 것이다. 단말기 사용자는 클라우드 저장소의 데이터만 볼 수 있어야 하고, 서버가 없는 클라우드 기능은 기존의 블로그를 보고 새로운 블로그를 만들 수 있어야 하며, 관리 권한을 가지고 모든 세 가지 조작을 수행할 수 있는 개발자도 있어야 한다.
// Go does not have explicit interface implementation. Any struct 
// with a method signature identical to the one defined on an 
// interface is treated as an implicit implementation. In that 
// respect it is a bit like duck typing in languages like Ruby.

type EndUser struct {}

func (EndUser) ViewBlob(cs *CloudStorageBucket, key string) (interface{}, error) {
    return cs.ViewBlob(key)
}


type CloudFunction struct {}

func (CloudFunction) ViewBlob(cs *CloudStorageBucket, key string) (interface{}, error) {
    return cs.ViewBlob(key)
}

func (CloudFunction) CreateBlob(cs *CloudStorageBucket, key string, contents interface{}) error {
    return cs.CreateBlob(key, contents)
}


type Developer struct {}

func (Developer) ViewBlob(cs *CloudStorageBucket, key string) (interface{}, error) {
    return cs.ViewBlob(key)
}

func (Developer) CreateBlob(cs *CloudStorageBucket, key string, contents interface{}) error {
    return cs.CreateBlob(key, contents)
}

func (Developer) DeleteBlob(cs *CloudStorageBucket, key string) (interface{}, error) {
    return cs.DeleteBlob(key)
}

최소 특권 원칙의 기능 디자인에서의 응용
이 세 가지 유형의 사용자를 정의하고 실현하는 인터페이스가 있으면 이 인터페이스를 매개 변수 형식으로 사용하는 함수를 만들 수 있습니다. 함수ViewCloudStorageBlob부터 실현ViewBlob 인터페이스CloudStorageViewer 방법의 모든 유형을 받아들일 수 있습니다. 이것은 클라우드 메모리 구조에서 Blob 이외의 기능을 볼 수 있도록 제한합니다.
func ViewCloudStorageBlob(cs *CloudStorageBucket, viewer CloudStorageViewer) {
    contents, err := viewer.ViewBlob(cs, "foo")
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Printf("key foo contains %v", contents)
}

func main() {
    storage := NewCloudStorageBucket()

    endUser := EndUser{}
    cloudFunction := CloudFunction{}
    developer := Developer{}

    ViewCloudStorageBlob(storage, endUser)
    ViewCloudStorageBlob(storage, cloudFunction)
    ViewCloudStorageBlob(storage, developer)
}
우리의 세 가지 사용자 구조가 모두 ViewBlob 방법을 실현했기 때문에 모두 ViewCloudStorageBlob의 두 번째 매개 변수로 사용할 수 있다.이 함수는blob 생성이나 삭제에 대한 정보를 알 필요도 없고 실현CloudStorageViewer을 한 사용자의 다른 상세한 정보를 알 필요도 없습니다.ViewCloudStorageBlobViewBlob만 알면 호출될 수 있다.이렇게소형 모듈화 인터페이스를 만들어 단용도 기능으로만 이 목적을 충족시키기 위해 필요한 정보를 제공합니다.
같은 절차도 수용CloudStorageCreator 유형의 함수에 적용된다.
func CreateCloudStorageBlob(cs *CloudStorageBucket, creator CloudStorageCreator) {
    err := creator.CreateBlob(cs, "foo", []int{1,2,3})
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println("new blob with key 'foo' successfully created")
}

func main() {
    storage := NewCloudStorageBucket()

    endUser := EndUser{}
    cloudFunction := CloudFunction{}
    developer := Developer{}

    CreateCloudStorageBlob(storage, cloudFunction)
    CreateCloudStorageBlob(storage, developer)
}
이번에 우리의 함수는 세 가지 사용자 유형 중 두 가지를 매개 변수로만 호출할 수 있다.CloudFunctionDeveloper는 여전히 저장소 블록을 볼 수 있지만 CreateCloudStorageBlob는 이런 행위를 모른다. 왜냐하면 그것을 알 필요가 없기 때문이다.EndUser 구조를 CloudStorageCreator 유형으로 사용하려고 하면 프로젝트를 구축할 때 다음과 같은 메시지가 표시됩니다.
cannot use endUser (type EndUser) as type CloudStorageCreator in argument to CreateCloudStorageBlob:
EndUser does not implement CloudStorageCreator (missing CreateBlob method)
EndUserCloudStorageCreator 형식의 요구를 충족시키지 못하기 때문에 컴파일할 때 오류 메시지를 받을 것입니다. 함수가 접근할 수 없는 CreateBlob 동작을 호출하려는 시도를 알 수 있습니다.
마지막으로, 함수는 완전한 접근 권한을 가진 형식, CloudStorageAdmin 인터페이스를 매개 변수 형식으로 사용하는 형식이 필요합니다.우선, 우리는 클라우드 저장소blob를 삭제하는 함수를 만들 것입니다. 이것은 우리가 이미 만든 보기와 창설 함수와 유사합니다.
func DeleteCloudStorageBlob(cs *CloudStorageBucket, deleter CloudStorageDeleter) {
    contents, err := deleter.DeleteBlob(cs, "foo")
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Printf("successfully deleted %v", contents)
}
필요한 CloudStorageAdmin 형식의 함수를 작성하기 전에 개발자 struct를 확인하십시오. 이 함수는 다른 세 가지 함수를 보기, 만들기, 삭제할 수 있는 매개 변수입니다.
func main() {
    storage := NewCloudStorageBucket()

    developer := Developer{}

    ViewCloudStorageBlob(storage, developer)
    CreateCloudStorageBlob(storage, developer)
    DeleteCloudStorageBlob(storage, developer)
}
Developer 구조가 충족CloudStorageViewer,CloudStorageCreatorCloudStorageDeleter 인터페이스이기 때문에 이러한 유형의 세 가지 함수를 받아들이는 매개 변수로 사용할 수 있다.
만약 그것이 각각 이 세 가지 유형으로 작동한다면, 그것은 현식 수용 CloudStorageAdmin 유형의 함수로 작동해야 한다.
func PerformAdminActions(cs *CloudStorageBucket, admin CloudStorageAdmin) {
    ViewCloudStorageBlob(cs, admin)
    CreateCloudStorageBlob(cs, admin)
    DeleteCloudStorageBlob(cs, admin)
}

func main() {
    storage := NewCloudStorageBucket()

    developer := Developer{}

    PerformAdminActions(storage, developer)
}
이전의 함수는 매개 변수로 받아들여지는 구체적인 유형에 대한 정보가 매우 적었을 뿐, 작은 단일 방법 인터페이스는 우리로 하여금 어떠한 다른 행위도 숨길 수 있게 했다.현재 우리는 클라우드 메모리 구조에 대해 여러 가지 조작을 해야 하는 기능이 생겼다. 우리는 서로 다른 방식으로 이런 작고 단일한 방법의 인터페이스를 이용하여 그것들을 새로운 인터페이스에 조합할 수 있다.
최종 결과는 우리의 Developer 구조는 매우 적은 정보를 필요로 하는 함수, 예를 들어 ViewCloudStorageBlob 함수와 대량의 정보를 필요로 하는 함수, 예를 들어 PerformAdminActions에 사용될 수 있다.이 두 가지 상황에서 필요한 행위만 매개 변수 유형을 통해 함수에 공개된다. 설령 밑바닥 구조가 같다 하더라도.

최소 특권 원칙의 장점을 이해하고 응용하다
인터페이스 디자인에서 최소 특권 원칙을 응용하는 장점은 아날로그 클라우드 서비스를 위해 작성된 코드에만 국한되지 않는다.같은 사고 과정도 모든 응용 프로그램의 디자인에 응용하여 코드를 더욱 확장성 있고 의도를 더욱 명확하게 할 수 있다.
함수가 매개 변수의 내용을 이해할 수 있도록 허용해야 한다는 것을 고려하면, 함수는 더 큰 재사용에서 이득을 볼 수 있습니다.클라우드 IAM에서 미리 정의된 역할이 새 사용자에게 관련 권한을 부여하는 것을 더욱 쉽게 하는 것처럼 인터페이스가 함수의 매개 변수 형식으로 사용할 때 이 인터페이스의 새로운 구체적인 형식도 매개 변수로 사용할 수 있으며 함수 자체를 변경할 필요가 없다.
인터페이스를 설계하고 명명할 때 노출된 행동을 고려해 의도를 전달한다.GCP IAM 역할과 동일한 기능을 제공합니다.호출자는 사용자가 이 캐릭터에 할당되어 실행할 수 있는 조작을 전달하고io 등 인터페이스도 마찬가지다.카드 리더기 또는 io.컴파일러는 그것을 매개 변수 형식의 함수로 사용하려는 의도를 전달한다.인터페이스를 통해 의도를 전달하면 다른 개발자와 미래의 자신이 함수가 어떤 행위인지 알 수 있고 매개 변수를 호출할 필요가 없습니다.
코드의 장점을 제외하고 최소 특권 원칙을 이해하고 응용하는 것은 개발자에게 인터페이스의 역할을 유형적으로 생각하는 방식을 제공하여 코드를 재구성하여 그들의 기회를 이용하는 것을 발견하고 이익을 얻을 수 있도록 도와준다.인터페이스의 합법적인 용례 능력이 향상된 것을 발견하면 코드의 가독성과 확장성도 향상됩니다.

좋은 웹페이지 즐겨찾기