본문 바로가기
프로그래밍/Golang

Golang Package(패키지) 기본 개념: 구조, 사용법 및 모범 사례 가이드

by slowin 2024. 7. 15.

Golang Package 기본개념

 

[https://go.dev/blog/organizing-go-code 참고]

Golang 에서 package 란?

패키지는 관련된 Go 코드들을 모아놓은 폴더라고 생각하면 됩니다. 예를 들어, 수학 계산과 관련된 코드를 모아놓은 패키지를 "math"라고 하고, 문자열을 다루는 코드들을 "strings"라는 패키지로 모아둡니다.

이처럼 패키지의 특성을 명확히 나타내는 이름을 지정하면, 패키지 이름만 보고도 어떤 기능들이 있는지 유추하기 쉬워집니다. 또한, 관련된 코드가 한 곳에 모이기 때문에 코드의 응집성이 높아지고 유지보수성이 향상될 수 있습니다.

 

구문(Syntax)

1. 패키지 선언

package main

각 소스 파일은 파일의 맨 위에 `package` 키워드를 사용하여 자신이 속한 패키지를 선언해야 합니다. 예를 들어, `main 패키지`는 일반적으로 실행 가능한 애플리케이션의 진입점입니다.

 

2. 패키지 가져오기

import "fmt"

다른 패키지에 정의된 함수를 사용하려면 `import` 키워드를 사용하여 해당 패키지를 가져와야 합니다. 예를 들어, 표준 라이브러리의 `fmt` 패키지를 가져오는 방법은 다음과 같습니다.

 

3. 접근 제어

패키지 내에서 정의된 함수, 변수, 상수 등의 식별자는 대문자로 시작하면 공개(public)되고, 소문자로 시작하면 비공개(private)됩니다. 예를 들어, fmt.Println은 공개 함수이며, 다른 패키지에서 사용할 수 있습니다.

package mathutil

// 공개 함수
func Add(a int, b int) int {
    return a + b
}

// 비공개 함수
func subtract(a int, b int) int {
    return a - b
}

// 공개 상수
const Pi = 3.14

// 비공개 변수
var secretNumber = 42

 

4. 사용자 정의 패키지

개발자는 자신의 필요에 맞게 사용자 정의 패키지를 만들 수 있습니다. 예를 들어,`mathutil`이라는 패키지를 만들고 이를 사용한 코드 예시를 알아보겠습니다.

// mathutil/mathutil.go
package mathutil

func Add(a int, b int) int {
    return a + b
}

// main.go
package main

import (
    "fmt"
    "path/to/your/project/mathutil"
)

func main() {
    result := mathutil.Add(1, 2)
    fmt.Println(result)
}

 

구조 / 관리

Go 프로젝트는 일반적으로 여러 패키지로 구성됩니다. 각 패키지는 디렉터리 단위로 관리되며, 각 디렉터리는 하나의 패키지를 나타냅니다.

 

패키지 구조와 디렉터리 관리

Go 프로젝트에서 각 디렉터리는 하나의 패키지를 나타냅니다. 그러나 디렉터리 이름과 패키지 이름이 반드시 일치할 필요는 없습니다. 이는 패키지를 더 유연하게 구성할 수 있게 해줍니다.

 

- 예시 프로젝트 구조

myproject/
├── go.mod
├── main.go
├── user/
│   ├── auth.go
│   └── profile.go
├── db/
│   ├── mysql/
│   │   └── connection.go
│   └── redis/
│       └── cache.go
└── utils/
    ├── logger.go
    └── config.go

 

  • main.go는 package main을 사용합니다.
  • user 디렉터리의 파일들은 package user를 사용할 수 있습니다.
  • db/mysql/connection.go는 package mysql을 사용할 수 있습니다.
  • utils 디렉터리의 파일들은 package utils를 사용할 수 있습니다.

패키지 이름과 디렉터리 이름

패키지 이름과 디렉터리 이름이 다를 수 있다는 점은 중요합니다.

// file: myproject/db/mysql/connection.go
package database

func Connect() {
    // MySQL 연결 로직
}

이 경우, 디렉터리 이름은 `mysql`이지만 패키지 이름은 `database`입니다.

이를 사용할 때는 다음과 같이 임포트합니다.

import "myproject/db/mysql"

func main() {
    database.Connect()
}

 

내부 패키지 (Internal Packages)

Go는 internal 디렉터리를 특별하게 취급합니다.

internal 디렉터리 내의 패키지는 같은 모듈 내의 코드에서만 임포트할 수 있습니다.

myproject/
├── internal/
│   └── auth/
│       └── token.go
└── api/
    └── handlers.go

이 구조에서 `auth` 패키지는 `myproject` 모듈 내에서만 사용할 수 있습니다.

 

패키지 선언시 알아두어야 할것

1.노출되는 인터페이스 최소화하기

패키지의 노출된 인터페이스를 최소화하세요. 노출하는 인터페이스가 클수록 지원해야 할 것이 많아집니다.

  • 사용자들은 여러분이 노출한 모든 타입, 함수, 변수, 상수에 빠르게 의존하게 됩니다.
  • 의심스럽다면 노출하지 마세요!

2. 코드 문서화하기

사용하기 쉽고 유지보수 가능한 코드의 필수적인 품질은 좋은 문서입니다. Go 언어에서는 코드 문서화가 특히 중요하며, Godoc이라는 강력한 도구를 통해 이를 지원합니다.

 

Godoc 작성 가이드라인

 

2.1. 패키지 개요 작성:

  • 패키지의 메인 소스 파일(보통 패키지 이름과 같은 .go 파일)에 패키지 수준의 문서를 작성합니다.
  • 패키지의 목적, 주요 기능, 사용 예시 등을 포함합니다.
// Package stringutil contains utility functions for working with strings.
//
// It provides functions for manipulating UTF-8 encoded strings,
// including conversion, comparison, and searching operations.
package stringutil

 

 

2.2. 함수와 메서드 문서화

 

  • 각 외부로 노출된(Exported) 함수와 메서드 위에 해당 함수의 동작을 설명하는 주석을 작성합니다.
  • 파라미터와 반환 값에 대한 설명을 포함합니다.
// Reverse returns the reverse of the input string.
//
// It handles multi-byte UTF-8 characters correctly.
func Reverse(s string) string {
    // 함수 구현...
}

 

 

2.3. 주의사항과 제한사항 명시

  • 함수나 타입 사용 시 주의해야 할 점이나 제한사항이 있다면 반드시 문서에 포함시킵니다.
// Note: This function is not concurrency-safe. Use with caution in multi-goroutine scenarios.

 

관련

Golang 패키지 네이밍 가이드: 효과적인 패키지 이름 짓기 12가지 팁
Golang 패키지 종속성 관리와 모듈화
Golang 모듈 발행 가이드: GitHub에 패키지 배포