At a Glance
package user
import "time"
type Profile struct {
ID string
createdAt time.Time
}Go에서는 같은 디렉터리의 일반 Go 파일이 하나의 package를 이루고, 대문자로 시작하는 이름만 외부 package에 공개됩니다. internal 디렉터리는 이름 규칙과 별도로 import 범위를 한 번 더 제한합니다.
기본 흐름
파일 첫 줄은 package 선언이다
package user같은 디렉터리에 있는 Go 파일은 보통 같은 package 이름을 가집니다. package는 import와 공개 API의 단위입니다.
internal/user/
model.go // package user
repository.go // package user_test.go 파일은 같은 package로 테스트하거나 package user_test처럼 외부 사용자의 관점에서 테스트할 수 있습니다. 반면 일반 소스 파일은 한 디렉터리에서 package를 섞을 수 없습니다.
import는 module 경로 기준으로 읽는다
import "example.com/myapp/internal/user"내 프로젝트 안의 package를 import할 때는 go.mod의 module 경로가 기준입니다. 표준 라이브러리는 "fmt", "time", "net/http"처럼 짧은 경로를 씁니다.
대문자로 시작하면 exported name이다
type User struct {
ID string
name string
}User, ID는 다른 package에서 접근할 수 있습니다. name은 같은 package 안에서만 접근할 수 있습니다.
가져오기 형태
보통은 기본 import를 쓴다
import (
"fmt"
"time"
)여러 package는 import block으로 묶습니다. 사용하지 않는 import는 컴파일 오류가 됩니다.
alias는 이름 충돌이나 가독성 때문에 쓴다
import userrepo "example.com/myapp/internal/user/repository"alias import는 package 이름이 겹치거나 호출부 이름을 더 명확히 해야 할 때만 제한적으로 씁니다.
import path와 코드에서 쓰는 package 이름은 항상 같지 않습니다. repository처럼 긴 이름을 alias로 줄일 수는 있지만, 이름을 감추는 alias는 검색과 추적을 어렵게 만들 수 있습니다.
side effect import는 명시적으로 드러낸다
import _ "net/http/pprof"밑줄 import는 package의 init side effect만 필요할 때 씁니다. 자주 쓰는 패턴은 아니므로 이유가 코드에서 드러나야 합니다.
internal은 module 안의 import 경계를 만든다
internal 디렉터리의 package는 그 internal의 부모 디렉터리 아래에 있는 코드만 import할 수 있습니다.
example.com/myapp/
internal/user/ // example.com/myapp/... 에서만 import 가능
cmd/api/ // import 가능
public/client/ // import 가능외부 module은 example.com/myapp/internal/user를 import할 수 없습니다. 대문자 공개 규칙이 symbol 단위의 API를 정한다면, internal은 package 자체를 외부 구현 세부사항으로 두는 경계입니다.
import cycle은 설계 오류로 막힌다
Go는 a가 b를 import하고 b가 다시 a를 import하는 순환 import를 컴파일 오류로 막습니다. 공용 type을 별도 package로 옮기거나, 의존하는 쪽에 작은 interface를 두어 한 방향으로 흐르게 만듭니다. cycle을 피하려고 넓은 util package에 아무 코드나 모으면 의존성 문제만 숨기게 됩니다.
선택 기준
| 상황 | 먼저 떠올릴 선택 |
|---|---|
| 같은 책임의 코드 묶음 | 같은 package |
| 외부에 공개할 타입/함수 | 대문자로 시작 |
| 내부 구현 세부사항 | 소문자로 시작 |
| 표준 라이브러리 사용 | 짧은 import 경로 |
| 프로젝트 내부 import | module 경로 기준 |
| side effect만 필요 | _ import |
주의할 점
Go의 공개 범위는 public, private 키워드가 아니라 이름의 첫 글자로 결정됩니다. 타입은 exported인데 필드가 unexported이면 외부 package에서 직접 채울 수 없습니다. API로 노출할 구조체는 필드 공개 여부까지 같이 설계해야 합니다.
참고 링크
3 sources