Go 1.19 제네릭 도입 후 실무 적용기

배경

사내 API 서버는 Go 1.17로 운영 중이었다. 공통 유틸리티 함수들이 interface{}를 남발하고 있어 타입 안정성이 부족했다. Go 1.19로 업그레이드하면서 제네릭을 실무에 적용해봤다.

개선 사례

1. 슬라이스 유틸리티

기존 코드는 reflection을 사용하거나 interface{}로 처리했다.

// 기존
func Contains(slice []interface{}, item interface{}) bool {
    for _, v := range slice {
        if v == item {
            return true
        }
    }
    return false
}

제네릭 적용 후:

func Contains[T comparable](slice []T, item T) bool {
    for _, v := range slice {
        if v == item {
            return true
        }
    }
    return false
}

타입 변환 없이 사용 가능해졌고, 컴파일 타임에 타입 체크가 된다.

2. Response Wrapper

API 응답을 감싸는 공통 구조체에도 적용했다.

type ApiResponse[T any] struct {
    Data    T      `json:"data"`
    Message string `json:"message"`
    Code    int    `json:"code"`
}

func NewSuccessResponse[T any](data T) ApiResponse[T] {
    return ApiResponse[T]{
        Data:    data,
        Message: "success",
        Code:    200,
    }
}

각 엔드포인트마다 응답 구조체를 만들 필요가 없어졌다.

주의사항

  • 메소드에는 제네릭을 쓸 수 없다. 타입 파라미터는 함수나 타입 정의에만 가능하다
  • 기존 라이브러리들이 아직 제네릭을 지원하지 않는 경우가 많다
  • 과도한 사용은 오히려 코드를 복잡하게 만든다

결론

슬라이스 처리, 옵셔널 타입, 공통 래퍼 정도에만 선택적으로 적용했다. 당장 모든 코드를 바꿀 필요는 없고, 새로 작성하는 유틸리티 위주로 점진적으로 도입하는 게 현실적이었다.