Go 프로젝트를 레이아웃하는 현명한 방법은 무엇입니까?


113

더 복잡해지기 시작하는 go 프로젝트가 있으며 고통을 줄이기 위해 파일 시스템을 배치하고 싶습니다.

이치에 맞는 좋은 예가 있습니까?

답변:


132

2013 년 5 월 업데이트 : 공식 문서는 " 코드 구성 " 섹션에 있습니다 .

Go 코드는 작업 공간 내에 보관되어야합니다 .
작업 공간은 루트에 세 개의 디렉토리가있는 디렉토리 계층 구조입니다.

  • src 패키지로 구성된 Go 소스 파일을 포함합니다 (디렉토리 당 하나의 패키지).
  • pkg 패키지 객체를 포함하고
  • bin 실행 가능한 명령이 포함되어 있습니다.

go tool소스 패키지를 구축하고에 결과 바이너리를 설치 pkg하고 bin디렉토리.

src하위 디렉토리는 일반적으로 하나 개 이상의 소스 패키지의 개발을 추적 (예 : 힘내이나 의욕 만) 여러 버전 관리 저장소가 포함되어 있습니다.

bin/
    streak                         # command executable
    todo                           # command executable
pkg/
    linux_amd64/
        code.google.com/p/goauth2/
            oauth.a                # package object
        github.com/nf/todo/
            task.a                 # package object
src/
    code.google.com/p/goauth2/
        .hg/                       # mercurial repository metadata
        oauth/
            oauth.go               # package source
            oauth_test.go          # test source

2014 년 7 월 업데이트 : Ben Johnson의 " Go 에서 애플리케이션 구조화 "참조

이 기사에는 다음과 같은 팁이 포함되어 있습니다.

바이너리를 애플리케이션에서 분리하세요.

main.go동일한 패키지에서 파일과 애플리케이션 로직을 결합하면 두 가지 결과가 발생합니다.

  • 내 응용 프로그램을 라이브러리로 사용할 수 없게 만듭니다.
  • 애플리케이션 바이너리는 하나만 가질 수 있습니다.

이 문제를 해결하는 가장 좋은 방법은 cmd각 하위 디렉터리가 응용 프로그램 바이너리 인 프로젝트에서 " "디렉터리를 사용하는 것 입니다.

camlistore/
  cmd/
    camget/
      main.go
    cammount/
      main.go
    camput/
      main.go
    camtool/
      main.go

도서관 주도 개발

main.go루트 에서 파일을 이동하면 라이브러리 관점에서 애플리케이션을 빌드 할 수 있습니다. 애플리케이션 바이너리는 단순히 애플리케이션 라이브러리의 클라이언트입니다.

때로는 사용자가 여러 방식으로 상호 작용하도록하여 여러 바이너리를 만들 수 있습니다.
예를 들어, adder사용자가 숫자를 함께 추가 할 수 있는“ ”패키지가있는 경우 웹 버전뿐 아니라 명령 줄 버전도 릴리스 할 수 있습니다.
다음과 같이 프로젝트를 구성하여 쉽게 수행 할 수 있습니다.

adder/
  adder.go
  cmd/
    adder/
      main.go
    adder-server/
      main.go

사용자는 줄임표를 사용하여 "go get"으로 "adder"응용 프로그램 바이너리를 설치할 수 있습니다.

$ go get github.com/benbjohnson/adder/...

그리고 짜잔, 당신의 사용자는 " adder"와 " adder-server"이 설치되어 있습니다!

서브 패키지에 미쳐 가지 마세요

일반적으로 내 프로젝트의 유형은 모두 매우 관련이 있으므로 유용성과 API 관점에서 더 적합합니다.
이러한 유형은 API를 작고 명확하게 유지하는 내보내기되지 않은 호출을 활용할 수도 있습니다.

  1. 관련 유형 및 코드를 각 파일에 함께 그룹화하십시오. 유형과 기능이 잘 구성되어 있으면 파일이 200 ~ 500 SLOC 사이 인 경향이 있습니다. 이것은 많이 들릴지 모르지만 탐색하기 쉽습니다. 1000 SLOC는 일반적으로 단일 파일에 대한 상한선입니다.
  2. 파일 맨 위에 가장 중요한 유형을 구성하고 파일 맨 아래로 갈수록 중요도가 낮아지는 유형을 추가합니다.
  3. 응용 프로그램이 10,000 SLOC를 초과하기 시작하면 더 작은 프로젝트로 나눌 수 있는지 심각하게 평가해야합니다.

참고 : 마지막 연습이 항상 좋은 것은 아닙니다.

이 관행에 동의 할 수 없어서 죄송합니다.
유형을 파일로 분리하면 코드 관리, 가독성, 유지 관리, 테스트 가능성에 도움이됩니다.
또한 단일 책임과 개방 / 폐쇄 원칙의 준수를 보장
할 수 있습니다. 순환 종속성을 허용하지 않는 규칙은 패키지의 명확한 구조를 갖도록하는 것입니다.


(2013 년 2 월 대안, 관련 사항 src만 해당)
" GitHub 코드 레이아웃 "에 설명 된 클래식 레이아웃을 찾을 수 있습니다 .

앱과 두 라이브러리는 각각 자체 저장소에있는 Github에 있습니다.
$GOPATH프로젝트의 루트입니다. 각 Github 저장소는 아래의 여러 폴더에서 체크 아웃됩니다 $GOPATH.

코드 레이아웃은 다음과 같습니다.

$GOPATH/
    src/
        github.com/
            jmcvetta/
                useless/
                    .git/
                    useless.go
                    useless_test.go
                    README.md
                uselessd/
                    .git/
                    uselessd.go
                    uselessd_test.go
                    README.md

아래의 각 폴더 src/github.com/jmcvetta/는 별도의 git 체크 아웃의 루트입니다.

하지만이 레딧 페이지 에서 몇 가지 비판을 받았습니다 .

나는 당신이 가지고있는 방식으로 repo를 구조화하지 않는 것이 좋습니다. 그것은 go getGo의 가장 유용한 것 중 하나 인 " "을 깨뜨릴 것입니다.
Go를 아는 사람들을 위해 코드를 작성하는 것이 훨씬 낫습니다. Go를 컴파일하는 사람 일 가능성이 가장 높기 때문입니다.
그리고 그렇지 않은 사람들에게는 적어도 언어에 대한 느낌이들 것입니다.

저장소의 루트에 기본 패키지를 넣으십시오.
자산을 하위 디렉토리에 보관하십시오 (정리를 유지하기 위해).
코드의 핵심을 하위 패키지에 보관하십시오 (누구나 바이너리 외부에서 재사용하려는 경우).
쉽게 찾을 수 있도록 저장소의 루트에 설정 스크립트를 포함합니다.

다운로드, 빌드, 설치 및 설정하는 과정은 여전히 ​​2 단계에 불과합니다. :

  • " go get <your repo path>": 자산의 하위 디렉토리와 함께 go 코드를 다운로드하고 설치합니다.
  • $GOPATH/<your repo path>/setup.sh: 자산을 적소에 배포하고 서비스를 설치

15
하나의 (큰) 문제 setup.sh는 Go가 합리적으로 크로스 플랫폼이지만 POSIX 쉘 스크립트는 그렇지 않다는 것입니다.
kostix 2013.02.14

쓸모없는 수입은 쓸모 없기 때문에 jmcvetta 구조는 go get을 깨지 않을 것입니다. go get은 go get ... / uselessd로 둘 다 설치합니다. 그러나 쓸모없는 것이 쓸모없는 사람을 위해 특별히 만들어진 라이브러리라면 하위 폴더 또는 형제로 단일 git 저장소에 보관하는 것이 더 합리적이라는 데 동의합니다.
mna

@PuerkitoBio 동의합니다. 버전 제어 및 구성 요소 기반 관리 ( stackoverflow.com/a/933735/6309 )에 대한 교육은 저를 리포지토리 당 하나의 구성 요소로 연결하므로이 답변의 두 번째 부분입니다.
VonC 2013

7

'프로젝트'는 Go 패키지가 아니라 개발 한 소프트웨어라고 가정합니다. 그렇지 않으면 여기여기에서 도움을받을 수 있습니다 . 그러나 Go 용 패키지를 작성하는 것과 크게 다르지 않습니다. 패키지를 사용하고 각 패키지에 대한 폴더를 만들고 해당 패키지를 애플리케이션에 결합합니다.

자신의 의견을 쌓으려면 github ( https://github.com/trending/go) 에서 유행하는 Go 저장소를 살펴볼 수 있습니다 . 주목할만한 예는 cayleyzeus 입니다.

가장 널리 사용되는 체계는 기본 Go 파일과 자체 디렉토리에 많은 모듈 및 하위 모듈을 포함하는 것입니다. 메타 파일 (문서, 라이센스, 템플릿 등)이 많은 경우 소스 코드를 하위 디렉토리에 넣을 수 있습니다. 그게 내가 지금까지 한 일입니다.


@aussiegeek, 저는 Go 전문가는 아니지만 nemo가 제 코드에서 제안한 것을 성공적으로 적용했습니다. 아이디어는 프로젝트 디렉토리 아래에 모듈 가질 수 있다는 것입니다. 전체 접두사를 사용하여 참조하면됩니다. 에 $GOPATH/src또는 사용 go get- 테이블 이름을.
kostix 2013

doozerd좋은 예가 아니며 테스트조차 약합니다.
Inanc Gumus

@InancGumus 더 나은 예를 제안 해 주시기 바랍니다.
nemo

.
Inanc 구 무스

1

권장되는 방법 을 정의하는 방법 이동 도구 및 지원 소스 제어 시스템에 가장 잘 작동하도록 코드를 레이아웃하는 것을 Golang의 작성자는


1
이것이 디렉토리 $GOROOT내의 코드가 아닌 레이아웃 방법 src/<project>입니다.
docwhat

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.