16 KiB
표준 Go 프로젝트 레이아웃
번역:
개요
이 레포지토리는 Go 어플리케이션 프로젝트의 기본 레이아웃입니다. 이 레포지토리는 코어 Go 개발팀에 의해 정의된 공식적인 표준은 아니지만, Go 생태계에서 역사적이거나 급부상중인 프로젝트 레이아웃 패턴들의 공통된 부분들입니다. 몇몇 패턴들은 다른 패턴들보다 유명합니다. 또한 이는 충분히 큰 현실세계 어플리케이션들에서 공통적으로 사용하는 여러 보조 디렉터리와 함께 다수의 작은 개선 사항들을 포함하고 있습니다.
만약 당신이 Go를 배우려하거나, 혼자 PoC나 토이 프로젝트를 만드는 거라면 이 프로젝트 레이아웃은 과한 것입니다. 아주 간단한 것부터 시작하세요 (main.go
파일 하나면 아주 충분합니다). 프로젝트가 성장하면서 당신의 코드가 잘 구조화 되도록 하는 것이 중요합니다. 그렇지 않으면 많은 숨겨진 종속성들과 전역 상태가 있는 지저분한 코드로 끝나게 될 것 입니다. 더 많은 사람들이 프로젝트에 참여할 때 더 많은 구조가 필요합니다. 그 때가 패키지/라이브러리를 관리하는 공통된 방법을 도입하는 것이 중요한 시점입니다. 당신이 오픈 소스 프로젝트를 가지고 있거나 다른 프로젝트가 당신의 프로젝트 레포지토리에서 코드를 임포트 하고있다면 프라이빗 (internal
로 일컫어지는) 패키지와 코드를 도입하는게 중요합니다. 이 레포지토리를 Clone하고, 당신에게 필요한것만 남긴다음 나머지 것들을 다 지우세요! 거기에 있다고 해서 다 사용해야하는 것은 아닙니다. 모든 프로젝트에서 다 사용하는 패턴은 없습니다. vendor
패턴 조차 보편적이지 않습니다.
Go 1.14로 Go Modules
은 최종적으로 프로덕션 준비가 완료되었습니다. 특별히 사용하지 않을 사유가 없다면 Go Modules
를 사용하세요. 그러면 $GOPATH와 어디에 내 프로젝트를 놓을지 고민할 필요가 없습니다. 레포지토리에서 기본적인 go.mod
파일은 프로젝트가 GitHub에 호스팅되어있다고 가정합니다만, 필수사항은 아닙니다. 모듈 패스는 어느것이든 될 수 있지만 첫번째 모듈 패스 컴포넌트는 그 이름에 점이 있어야 합니다. (현재 버전의 Go는 더이상 이를 강제하지는 않지만, 만약 조금 더 오래된 버전을 사용하고 있다면 점이 없을때 빌드가 실패해도 놀라지 마세요). 이에 대해 더 알아보고 싶으시면 이슈 37554
와 32819
를 읽어보세요.
이 프로젝트 레이아웃은 의도적으로 일반적이며 특정 Go 패키지 구조를 강요하지 않습니다.
이 레포지토리는 커뮤니티의 노력입니다. 새 패턴을 찾았거나, 있는 패턴들 중 하나가 업데이트가 필요하다고 생각된다면 이슈를 열어주세요.
네이밍, 포매팅, 스타일에 대해 도움이 필요하시다면, gofmt
와 golint
를 돌리는 것으로 시작해보세요. 또한 Go 코드 스타일 가이드라인과 권장 사항들을 꼭 읽어보세요:
- https://talks.golang.org/2014/names.slide
- https://golang.org/doc/effective_go.html#names
- https://blog.golang.org/package-names
- https://github.com/golang/go/wiki/CodeReviewComments
- Style guideline for Go packages (rakyll/JBD)
자세한 배경 지식에 대해서는 Go Project Layout
를 확인하세요.
다른 코드 구조 추천과 네이밍과 패키지 구성에 대해 더 알아보기:
- GopherCon EU 2018: Peter Bourgon - Best Practices for Industrial Programming
- GopherCon Russia 2018: Ashley McNamara + Brian Ketelsen - Go best practices.
- GopherCon 2017: Edward Muller - Go Anti-Patterns
- GopherCon 2018: Kat Zien - How Do You Structure Your Go Apps
패키지 지향 디자인 가이드라인과 설계 레이어에 대한 중국어 글
Go 디렉터리
/cmd
이 프로젝트의 메인 어플리케이션들입니다.
각 어플리케이션의 디렉터리명은 만들고싶은 실행 파일 이름과 같아야 합니다 (e.g., /cmd/myapp
).
어플리케이션 디렉터리에 많은 코드를 넣지마세요. 다른 프로젝트들에서 임포트되고 사용될 것 같으면, /pkg
디렉터리에 있어야합니다. 코드가 재사용성이 없거나 다른사람들이 재사용하지 않기를 바란다면 코드를 /internal
디렉터리에 넣으세요. 다른사람들이 무얼 할지 놀라게 될거에요. 그러니 의도를 분명하게 밝혀주세요!
흔히 /internal
와 /pkg
디렉터리 코드를 임포트, 호출만 하는 작은 main
함수는 흔히 볼 수 있습니다.
예시는 /cmd
를 보세요.
/internal
개인적인 어플리케이션과 라이브러리 코드. 다른 사람들이 어플리케이션이나 라이브러리에서 임포트 하기를 원하지 않는 코드들입니다. 이 레이아웃 패턴은 Go 컴파일러 자체에 강제됩니다. 더 알아보고 싶다면 Go 1.4 release notes
를 참고하세요. 이는 최상단 internal
디렉터리에 국한되는 것은 아닙니다. 프로젝트 트리의 모든 레벨에서 하나 이상의 internal
디렉터리를 가질 수 있습니다.
Internal 패키지에서 공유되는 내부 코드와 공유되지 않는 내부 코드를 구분하기 위해 부가적인 구조체를 추가할 수 있습니다. 필수사항은 아니지만(특히 작은 프로젝트에서는), 의도된 패키지 사용법을 보여주는 시각적인 단서를 남기는 것이 좋습니다. 실제 어플리케이션 코드는 /internal/app
디렉터리에 넣고 (e.g., /internal/app/myapp
) , 그 앱들에서 공유되는 코드들은 /internal/pkg
디렉터리 (e.g., /internal/pkg/myprivlib
) 에 넣을 수 있습니다.
/pkg
외부 어플리케이션에서 사용되어도 괜찮은 라이브러리 코드입니다 (e.g., /pkg/mypubliclib
). 다른 프로젝트는 이 라이브러리들이 작동할거라고 예상하고 임포트 할 것 이므로, 여기에 무언가를 넣기 전에 두번 고민하세요 :-) internal
디렉터리는 개인적인 패키지들이 임포트 불가능하도록 하는 더 좋은 방법인데, 이유는 Go가 이를 강제하기 떄문입니다. /pkg
디렉터리는 그 디렉터리 안의 코드가 다른 사람들에 의해 사용되어도 안전하다고 명시적으로 보여주는 좋은 방법입니다. Travis Jeffery의 I'll take pkg over internal
블로그 포스트는 pkg
와 internal
디렉터리와 언제 쓰는게 맞을지에 대해 좋은 개요를 제공합니다.
또한 루트 디렉터리에 많은 Go가 아닌 컴포넌트와 디렉터리를 포함하고 있다면 Go 코드를 한 곳에 모아서 다양한 Go 툴들을 쉽게 실행할 수 있습니다 (이 발표들에서 언급되었던것 처럼: GopherCon EU 2018의 Best Practices for Industrial Programming
, GopherCon 2018: Kat Zien - How Do You Structure Your Go Apps 와 GoLab 2018 - Massimiliano Pippi - Project layout patterns in Go).
이 프로젝트 레이아웃 패턴을 사용하는 유명한 Go 레포지토리들을 보고 싶다면 /pkg
를 보세요. 이는 흔한 레이아웃 패턴이나, 보편적으로 받아드려지는 것은 아니며 Go 커뮤니티의 일부는 이를 추천하지 않습니다.
앱 프로젝트가 정말 작고 추가적인 레벨의 중첩이 많이 효과적이지 않다면 사용하지 않아도 괜찮습니다 (정말로 원하지 않는 한 :-)). 프로젝트가 더 커지고 루트 디렉터리가 꽤 바빠질 때 고려해보세요 (특히 Go가 아닌 앱 컴포넌트가 많이 있다면).
/vendor
어플리캐이션 종속성 (직접 혹은 새 빌트인 Go Modules
피쳐와 같은 종속성 관리 도구로 관리되는). go mod vendor
명령어는 /vendor
디렉터리를 만들어 줄 것 입니다. go build
명령어를 사용할 때 Go 1.14를 사용하지 않는다면 Go 1.14에서 기본으로 켜져있는 -mod=vendor
플래그를 추가해야 할 수 있습니다.
만약 당신이 라이브러리를 만들고 있다면 당신의 어플리케이션 종속성을 커밋하지 마세요.
1.13
부터 Go는 모듈 프록시 기능(기본적으로 https://proxy.golang.org
를 모듈 프록시 서버로 사용하여)을 활성화하였습니다. 이것이 당신의 요구조건과 제한사항을 모두 만족하는지 보려면 여기
를 읽어보세요. 만약 만족한다면, vendor
디렉터리가 전혀 필요하지 않을 것입니다.
서비스 어플리케이션 디렉터리
/api
OpenAPI/Swagger 스펙들, JSON schema 파일들, 프로토콜 정의 파일들.
예시로 /api
디렉터리를 확인하세요.
웹 어플리케이션 디렉터리
/web
웹 어플리케이션의 특정한 컴포넌트들: 정적 웹 에셋들, 서버 사이드 템플릿과 SPA들.
공통 어플리케이션 디렉터리
/configs
설정 파일 템플릿이나 기본 설정들.
confd
or consul-template
템플릿 파일들을 여기에 놓으세요.
/init
시스템 init (systemd, upstart, sysv) 과 프로세스 매니저/슈퍼바이저 (runit, supervisord) 설정들.
/scripts
빌드, 설치, 분석, 기타 작업을 위한 스크립트들.
이 스크립트들은 루트의 Makefile을 작고 간단하게 유지해줍니다 (e.g., https://github.com/hashicorp/terraform/blob/master/Makefile
).
예시로 /scripts
디렉터리를 확인하세요.
/build
패키징과 지속적인 통합(CI).
클라우드 (AMI), 컨테이너 (Docker), OS (deb, rpm, pkg) 패키지 설정과 스크립트를 /build/package
디렉터리에 넣으세요.
CI (travis, circle, drone) 설정과 스크립트를 /build/ci
에 넣으세요. 몇몇 CI 도구들은 (e.g., Travis CI) 설정파일들 위치에 대해 굉장히 까다롭다는 것을 알아두세요. 설정 파일들을 /build/ci
에 넣고 CI 도구들이 기대하는 위치에 링크해보세요. (가능하다면).
/deployments
IaaS, PaaS, 시스템과 컨테이너 오케스트레이션 배포 설정과 템플릿 (docker-compose, kubernetes/helm, mesos, terraform, bosh). 몇몇 레포지토리 (특히 쿠버네티스로 배포되는 앱들) 에서 이 디렉터리는 /deploy
라고 불립니다.
/test
추가적인 외부 테스트 앱들과 테스트 데이터들. /test
디렉터리를 자유롭게 구조화하세요. 더 큰 프로젝트에서 데이터 서브디렉터리를 갖는것이 합당합니다. 예시로, 이 디렉터리에 무엇이 있는지 Go가 무시하려면 /test/data
또는 /test/testdata
를 만들면 됩니다. Go는 "." 나 "_" 로 시작하는 디렉터리들이나 파일들도 무시하니, 테스트 데이터 디렉터리 이름을 더 자유롭게 지을 수 있습니다.
예시로 /test
디렉터리를 확인하세요.
다른 디렉터리들
/docs
디자인과 사용자 문서들 (godoc이 만든 문서에 더불어).
예시로 /docs
디렉터리를 확인하세요.
/tools
이 프로젝트에서 사용하는 도구들. 이 도구들이 /pkg
나 /internal
디렉터리에서 코드를 임포트 할 수 있음을 알아두세요.
예시로 /tools
디렉터리를 확인하세요.
/examples
어플리케이션 혹은 공개된 라이브러리의 예시들.
예시로 /examples
디렉터리를 확인하세요.
/third_party
사용하는 외부 도구들, 포크된 코드들과 다른 서드 파티 유틸리티들 (e.g., Swagger UI).
/githooks
Git hooks.
/assets
레포지토리와 함께 사용될 에셋들 (이미지, 로고, 기타).
/website
GitHub pages를 사용하고 있지 않다면 프로젝트의 웹사이트 데이터를 넣는 곳입니다.
예시로 /website
디렉터리를 확인하세요.
있으면 안되는 디렉터리
/src
몇몇 Go 프로젝트들은 분명 src
폴더를 가지고 있으나, 이는 개발자들이 해당 패턴이 흔한 Java 세계에서 왔을 때 대부분 발생합니다. 만약 할 수 있다면 이 Java 패턴을 사용하지 않도록 해보세요. Go 코드나 Go 프로젝트가 Java처럼 보이는걸 원하지 않잖아요 :-)
프로젝트 레벨의 /src
디렉터리와 How to Write Go Code
에서 설명된 것 처럼 Go에서 워크스페이스로 사용하는 /src
디렉터리와 혼동하지 마세요. $GOPATH
환경 변수는 당신의 (현재) 워크스페이스를 가리킵니다 (기본적으로 윈도우가 아닌 시스템에서는 $HOME/go
를 가리킵니다). 이 워크스페이스는 최상위 /pkg
, /bin
, /src
디렉터리를 포함하고 있습니다. 실제 프로젝트는 결국 /src
의 서브디렉터리이므로, 프로젝트 안에 /src
디렉터리가 있다면 프로젝트 주소는 이럴 것입니다: /some/path/to/workspace/src/your_project/src/your_code.go
. Go 1.11에서는 GOPATH
밖에 프로젝트를 만드는게 가능하지만, 이 레이아웃 패턴을 사용하는게 좋다는 뜻은 아님을 알아두세요.
뱃지
-
Go Report Card - 이는 당신의 코드를
gofmt
,go vet
,gocyclo
,golint
,ineffassign
,license
,misspell
로 스캔합니다.github.com/golang-standards/project-layout
를 당신의 프로젝트 주소로 바꾸세요. -
GoDoc - 온라인 버전의 GoDoc 생성 문서를 제공합니다. 당신의 프로젝트를 가리키도록 링크를 바꾸세요. -
Pkg.go.dev - Pkg.go.dev는 Go 검색 및 문서들을 위한 새로운 사이트입니다. badge generation tool을 사용해서 새로운 뱃지를 만들 수 있습니다.
-
Release - 프로젝트의 최신 릴리즈 넘버를 보여줍니다. 당신의 프로젝트를 가리키도록 깃헙 링크를 바꾸세요.
참고
샘플/재사용 가능한 설정, 스크립트와 코드를 포함하는 더 의견이 담긴 프로젝트 템플릿은 작업 중입니다.