11장 패키지

Go는 훌륭한 소프트웨어 공학 실천법을 독려하도록 설계된 언어다. 고품질 소프트웨어의 중요한 부분 중 하나는 "반복하지 말라"라는 원칙에 내포된 코드 재사용이다.

7장에서 살펴본 것과 같이 함수는 코드 재사용을 돕는 첫 번째 수단이다. Go에서는 패키지라는 코드 재사용을 위한 또 다른 메커니즘을 제공한다. 지금까지 살펴본 거의 모든 프로그램에는 다음과 같은 줄이 포함돼 있었다.

import "fmt"

fmt는 형식화와 화면 출력과 관련된 다양한 함수가 포함된 패키지의 이름이다. 이런 식으로 코드를 첨가하면 3가지 목적을 달성할 수 있다.

  1. 이름이 겹치는 가능성이 줄어든다. 이렇게 하면 함수명을 짧고 간결하게 유지할 수 있다.

  2. 재사용하고자 하는 코드를 찾기 쉽게 코드가 구성된다.

  3. 프로그램을 구성하는 작은 부분들만을 다시 컴파일하면 되므로 컴파일 속도가 빨라진다. fmt라는 패키지를 사용하더라도 프로그램을 변경할 때마다 해당 패키지를 다시 컴파일하지 않아도 된다.

11.1 패키지 생성

패키지는 개별 프로그램에서 패키지를 사용하는 경우에만 아주 효율적이다. 이런 식으로 프로그램이 분리돼 있지 않으면 우리가 만든 패키지를 사용할 방법이 없다. 앞으로 작성할 패키지를 사용하는 애플리케이션을 만들어 보자. ~/Go/src/golang-book 안에 chapter11이라는 폴더를 만든다. 이 폴더 안에 main.go라는 파일을 만들고 다음과 같은 내용을 입력한다.

package main

import "fmt"
import "golang-book/chapter11/math"

func main() {
    xs := []float64{1,2,3,4}
    avg := math.Average(xs)
    fmt.Println(avg)
}

이제 chapter11 폴더 안에 math라는 폴더를 하나 더 만든다. 이 폴더 안에 math.go라는 파일을 만들고 다음과 같은 내용을 입력한다.

package math

func Average(xs []float64) float64 {
    total := float64(0)
    for _, x := range xs {
        total += x
    }
    return total / float64(len(xs))
}

터미널을 이용해 방금 생성한 math 폴더 안에서 go install을 실행한다. 그러면 math.go 프로그램이 컴파일되고 링크 가능한 오브젝트 파일(~/Go/pkg/os_arch/golang-book/chapter11/math.a)이 만들어진다(여기서 oswindows와 같은 것이고, archamd64와 같은 것이다).

이제 chapter11 폴더로 되돌아와 go run main.go를 실행한다. 그러면 2.5가 출력될 것이다. 다음과 같은 사항을 알아두자.

  1. math는 Go의 표준 배포판을 구성하는 패키지의 이름이지만 Go 패키지는 계층 구조를 띠고 있기 때문에 여기서 작성한 패키지에 같은 이름을 사용해도 문제가 없다(실제 math 패키지는 그냥 math이고, 우리가 작성한 패키지는 golang-book/chapter11/math다).

  2. math 라이브러리를 임포트할 때 전체 이름(import "golang-book/chapter11/math")을 썼는데, main.go 파일에서는 마지막 부분(package math)만 썼다.

  3. 라이브러리에 들어 있는 함수를 참조할 때도 math라는 짧은 이름만 썼다. 동일한 프로그램에서 라이브러리도 사용하고 싶었다면 Go에서는 별칭(alias)을 사용하는 것도 허용한다.

    import m "golang-book/chapter11/math"
    
    func main() {
        xs := []float64{1,2,3,4}
        avg := m.Average(xs)
        fmt.Println(avg)
    }
    

    여기서 m은 별칭이다.

  4. 지금까지 살펴본 패키지 안의 함수는 모두 대문자로 시작한다는 사실을 눈치챘을지도 모르겠다. Go에서는 뭔가가 대문자로 시작하면 다른 패키지(및 프로그램)에서도 그것을 볼 수 있음을 의미한다. 함수의 이름을 Average 대신 average라고 지었다면 main 프로그램에서는 해당 함수를 볼 수 없었을 것이다.

    다른 패키지에서도 사용할 수 있게 만들고자 하는 것만 노출하고 그 밖의 다른 것들은 모두 숨기는 것이 좋은 습관이다. 이렇게 하면 나중에 다른 프로그램이 망가지는 것에 대해 걱정할 필요 없이 그러한 부분들을 자유롭게 변경할 수 있고 우리가 만든 패키지를 사용하기 쉽게 만들어준다.

  5. 패키지명은 해당 패키지가 들어 있는 폴더와 이름이 일치해야 한다. 이를 우회하는 방법도 있지만 이러한 패턴을 따르는 것이 훨씬 더 수월하다.

11.2 문서화

Go에서는 표준 패키지 문서화와 비슷한 방식으로 우리가 작성한 패키지에 대한 문서를 자동으로 생성하는 기능을 제공한다. 터미널에서 다음 명령어를 실행한다.

godoc golang-book/chapter11/math Average

그러면 방금 작성한 함수에 대한 정보가 출력된다. 함수 위에 주석을 추가해서 이 문서를 개선할 수 있다.

// 인자로 전달된 숫자의 평균을 구한다
func Average(xs []float64) float64 {

math 폴더 안에서 go install을 실행한 후 godoc 명령어를 다시 실행하면 앞에서 작성한 주석이 함수 정의 아래에 출력되는 것을 볼 수 있다. 이러한 문서화 내용은 다음 명령어를 실행한 후

godoc -http=":6060"

브라우저에서 아래 URL를 입력해 웹 형태로도 볼 수 있다.

http://localhost:6060/pkg/

그러면 시스템에 설치된 모든 패키지를 열람할 수 있다.

연습 문제

  1. 패키지를 사용하는 이유는 무엇인가?

  2. 대문자로 시작하는 식별자와 그렇지 않은 식별자의 차이점은 무엇인가? (Averageaverage)

  3. 패키지 별칭이란 무엇인가? 패키지 별칭은 어떻게 만드는가?

  4. 7장의 average 함수를 새 패키지로 복사한다. float64 타입의 슬라이스에 들어 있는 값 가운데 최솟값과 최댓값을 찾는 MinMax 함수를 각각 만들어라.

  5. 4번 문제에서 만든 함수에 대해 어떻게 문서화하겠는가?

← 이전다음 →