인터페이스 조합과 모범 사례
작은 인터페이스와 의존성 역전
인터페이스 조합과 모범 사례은(는) CoddyKit의 무료 Go Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Go Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Go Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
인터페이스 조합
Go 인터페이스는 다른 인터페이스를 임베드하여 더 큰 인터페이스를 조합할 수 있습니다:
package main
import "io"
// io.ReadWriter composes Reader and Writer
type ReadWriter interface {
io.Reader
io.Writer
}
// Your own composition:
type Processor interface {
io.Reader
Process() error
io.Closer
}
func main() { _ = (*Processor)(nil) }작은 인터페이스 원칙
가장 강력한 Go 인터페이스에는 메서드가 한두 개만 있습니다. 그러면 해당 인터페이스를 충족할 수 있는 타입의 수가 최대화됩니다:
io.Reader— 메서드 1개io.Writer— 메서드 1개error— 메서드 1개fmt.Stringer— 메서드 1개
큰 인터페이스는 모의 객체를 만들고 테스트하기가 더 어렵습니다.
의존성 역전
구체 타입 대신 함수 매개변수로 인터페이스를 받으세요. 이렇게 하면 코드가 특정 구현과 분리됩니다:
package main
import "fmt"
type Store interface {
Get(key string) (string, bool)
Set(key, val string)
}
func cache(s Store, key, value string) {
if _, ok := s.Get(key); !ok {
s.Set(key, value)
}
}
type MapStore struct{ m map[string]string }
func (ms *MapStore) Get(k string) (string, bool) { v, ok := ms.m[k]; return v, ok }
func (ms *MapStore) Set(k, v string) { ms.m[k] = v }
func main() {
s := &MapStore{m: map[string]string{}}
cache(s, "x", "hello")
v, _ := s.Get("x")
fmt.Println(v)
}인터페이스 분리
큰 인터페이스를 더 작고 목적이 분명한 인터페이스로 나누세요. 클라이언트는 자신이 사용하는 메서드에만 의존합니다:
package main
// Bad: large interface forces all methods
type BigStorage interface {
Read(key string) string
Write(key, val string)
Delete(key string)
List() []string
Backup() error
}
// Good: small, focused interfaces
type Reader interface{ Read(key string) string }
type Writer interface{ Write(key, val string) }
type Lister interface{ List() []string }
func readAll(r Reader) {} // only needs Read
func main() { _ = readAll }구체 타입 반환
생성자는 인터페이스가 아니라 구체 타입을 반환해야 합니다. 호출자는 언제든지 구체 타입을 인터페이스 변수에 할당할 수 있습니다:
package main
type Logger interface{ Log(string) }
type ConsoleLogger struct{}
func (c *ConsoleLogger) Log(s string) {}
// Good: return concrete *ConsoleLogger
func NewConsoleLogger() *ConsoleLogger { return &ConsoleLogger{} }
// Avoid: return Logger (hides the concrete type)
// func NewConsoleLogger() Logger { return &ConsoleLogger{} }
func main() { _ = NewConsoleLogger() }인터페이스 남용
“혹시 모르니” 모든 타입에 인터페이스를 만들지는 마세요. 다음과 같은 경우에만 인터페이스를 만드세요:
- 현재 또는 곧 여러 구현이 있을 때
- 테스트에서 의존성을 모의 객체로 대체해야 할 때
- 라이브러리를 만들면서 호출자를 분리하고 싶을 때
확장을 위한 인터페이스 임베딩
인터페이스를 임베드하여 기본값이 있는 선택적 메서드를 추가하세요:
package main
import "fmt"
type Handler interface{ Handle(msg string) }
type NamedHandler interface {
Handler
Name() string
}
func dispatch(h Handler) {
if nh, ok := h.(NamedHandler); ok {
fmt.Printf("[%s] ", nh.Name())
}
h.Handle("event")
}
type MyHandler struct{}
func (m MyHandler) Handle(msg string) { fmt.Println(msg) }
func (m MyHandler) Name() string { return "my" }
func main() { dispatch(MyHandler{}) }인터페이스를 사용한 모의 객체
의존성을 인터페이스로 정의하고, 테스트에서 모의 객체를 주입하세요:
package main
import "fmt"
type Clock interface{ Now() int64 }
type MockClock struct{ T int64 }
func (m MockClock) Now() int64 { return m.T }
func isExpired(c Clock, expiresAt int64) bool {
return c.Now() > expiresAt
}
func main() {
mc := MockClock{T: 1000}
fmt.Println(isExpired(mc, 500)) // true
fmt.Println(isExpired(mc, 1500)) // false
}재사용을 위한 인터페이스 임베딩과 구조체 임베딩 비교
API 조합에는 인터페이스 임베딩을 사용하고 코드 재사용에는 구조체 임베딩을 사용하세요. 두 방식은 목적이 다르므로 혼동해서는 안 됩니다.
컴파일 시 인터페이스 충족 여부 확인
빈 식별자를 사용한 컴파일 시점 확인으로 타입이 인터페이스를 충족하는지 검증하세요:
package main
type Doer interface{ Do() }
type MyType struct{}
func (m *MyType) Do() {}
// Compile-time check — no runtime cost
var _ Doer = (*MyType)(nil)
func main() {}빠른 확인
Go에서 새 인터페이스는 언제 정의해야 하나요?
복습: 인터페이스 모범 사례
핵심 내용:
- 인터페이스를 작게 유지하세요 — 메서드는 한두 개
- 더 작은 인터페이스로 인터페이스를 조합하세요
- 인터페이스를 받고 구체 타입을 반환하세요
- 테스트 가능성과 여러 구현을 위해 인터페이스를 만드세요
- 빈 할당을 사용한 컴파일 시점 확인을 사용하세요
연습 문제
Notify(msg string) error를 포함하는 Notifier 인터페이스를 설계하세요. 이를 EmailNotifier와 SMSNotifier에 구현하세요. []Notifier에 전송하는 broadcast 함수를 작성하세요.
자주 묻는 질문
“인터페이스 조합과 모범 사례” 강의는 무료인가요?
네 — “인터페이스 조합과 모범 사례” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Go Academy 강의 전체를 잠금 해제할 수 있습니다. Go Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“인터페이스 조합과 모범 사례”에서 뭘 배우나요?
작은 인터페이스와 의존성 역전 브라우저에서 직접 실행하는 실습 코드로 Go Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Go Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Go Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“인터페이스 조합과 모범 사례” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Go Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Go Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 인터페이스 정의와 구현
- 표준 라이브러리의 핵심 인터페이스
- 타입 단언과 타입 스위치
- 인터페이스 조합과 모범 사례