1. ホーム
  2. go

[解決済み] Goプロジェクトの賢明なレイアウト方法とは [終了しました]。

2022-09-08 08:55:25

質問

私は、より複雑になりつつあるgoプロジェクトを持っており、苦痛を減らすためにファイルシステムをそのようにレイアウトしたいと思っています。

何が理にかなっているのか、そこにいくつかの良い例がありますか?

どのように解決するのですか?

2013年5月更新:公式ドキュメントは、「"」のセクションにあります。 コード構成 "にあります。

Goコードは ワークスペース .

ワークスペースは、3つのディレクトリをルートとするディレクトリ階層です。

  • src は、パッケージに整理されたGoのソースファイルを含んでいます(1つのディレクトリに1つのパッケージ)。
  • pkg にはパッケージオブジェクトが含まれ
  • bin は実行可能なコマンドを含んでいます。
<ブロッククオート

この go tool はソースパッケージをビルドし、生成されたバイナリを pkgbin ディレクトリを作成します。

src サブディレクトリには、通常、一つ以上のソースパッケージの開発を追跡する複数のバージョンコントロールリポジトリ (Git や Mercurial など) が含まれています。

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月更新:"をご覧ください。 Goでアプリケーションを構造化する からの ベン ジョンソン

その記事には、次のようなヒントがあります。

アプリケーションからバイナリを分離する

を組み合わせることで main.go ファイルと私のアプリケーションロジックを同じパッケージで組み合わせることは、2つの結果をもたらします。

  • 私のアプリケーションをライブラリとして使用できなくなります。
  • アプリケーションのバイナリが1つしか持てなくなります。

これを解決するために私が見つけた最良の方法は、単に " cmd " ディレクトリを使用し、そのサブディレクトリの各々がアプリケーション バイナリであることです。

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

ライブラリ駆動開発

<ブロッククオート

を移動させる main.go ファイルをルートから移動させることで、ライブラリの観点からアプリケーションを構築することができます。アプリケーションのバイナリは、単にアプリケーションのライブラリのクライアントとなります。

時には、ユーザーが複数の方法で対話することを望むかもしれないので、複数のバイナリを作成します。

例えば、" adder " パッケージがあった場合、Web 版だけでなくコマンドライン版もリリースしたいと思うかもしれません。

このようにプロジェクトを整理することで、簡単にこれを行うことができます。

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

<ブロッククオート

ユーザーは "adder "アプリケーションのバイナリを、省略記号を使用して "go get "でインストールすることができます。

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

<ブロッククオート

すると、あなたのユーザは " adder " と " adder-server " がインストールされました!

サブパッケージの使用は控えましょう

通常、私のプロジェクトのタイプはすべて非常に関連しているので、ユーザビリティとAPIの観点から、その方が適しています。

これらのタイプはまた、APIを小さく明確に保つそれらの間でunexportedを呼び出すことを利用することができます。

  1. 関連する型とコードを各ファイルでグループ化します。型と関数がよく整理されていれば、ファイルは 200 から 500 SLOC の間になる傾向があることがわかります。これは多いと思われるかもしれませんが、私はこの方がナビゲートしやすいと思います。1000 SLOC は通常、1 つのファイルに対する私の上限です。
  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 チェックアウトのルートとなります。

しかしそれはいくつかの批判を集め、この reddit ページ :

<ブロッククオート

あなたのような方法でレポを構造化しないことを強くお勧めします。 go get を壊してしまいます。

Goを知っている人がコンパイルする可能性が高いので、コードを書くほうがはるかによいです。

そして、そうでない人たちは、少なくとも言語の感触を得ることができます。

メインパッケージをレポのルートに置く。

サブディレクトリにアセットを持つ(すっきりさせるため)。

コードの本体はサブパッケージで管理する(バイナリの外で再利用したい人のために)。

レポのルートにセットアップスクリプトを含めて、簡単に見つけられるようにする。

まだ、ダウンロード、ビルド、インストール、セットアップの2ステップだけです。

  • " go get <your repo path> ": アセット用のサブディレクトリを含む、goコードのダウンロードとインストールを行います。
  • $GOPATH/<your repo path>/setup.sh : アセットを適切な場所に配布し、サービスをインストールします。