[解決済み] Goプロジェクトの賢明なレイアウト方法とは [終了しました]。
質問
私は、より複雑になりつつあるgoプロジェクトを持っており、苦痛を減らすためにファイルシステムをそのようにレイアウトしたいと思っています。
何が理にかなっているのか、そこにいくつかの良い例がありますか?
どのように解決するのですか?
2013年5月更新:公式ドキュメントは、「"」のセクションにあります。 コード構成 "にあります。
Goコードは ワークスペース .
ワークスペースは、3つのディレクトリをルートとするディレクトリ階層です。
-
src
は、パッケージに整理されたGoのソースファイルを含んでいます(1つのディレクトリに1つのパッケージ)。 -
pkg
にはパッケージオブジェクトが含まれ -
bin
は実行可能なコマンドを含んでいます。
この
go tool
はソースパッケージをビルドし、生成されたバイナリを
pkg
と
bin
ディレクトリを作成します。
は
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を呼び出すことを利用することができます。
- 関連する型とコードを各ファイルでグループ化します。型と関数がよく整理されていれば、ファイルは 200 から 500 SLOC の間になる傾向があることがわかります。これは多いと思われるかもしれませんが、私はこの方がナビゲートしやすいと思います。1000 SLOC は通常、1 つのファイルに対する私の上限です。
- ファイルの一番上に最も重要なタイプを整理し、ファイルの一番下に向かって重要度が下がるようにタイプを追加します。
- アプリケーションが 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
: アセットを適切な場所に配布し、サービスをインストールします。
関連
-
[解決済み] Goでenumを表現する慣用的な方法は何ですか?
-
[解決済み] Goの文字列を印刷せずにフォーマットしますか?
-
[解決済み】C言語の三項演算子に相当するGoの慣用句は何ですか?
-
[解決済み】関数宣言の構文:関数名の前に括弧でくくられたもの
-
[解決済み】GitHub ProjectsとMilestoneの違い/関係は?
-
[解決済み】ソリューションでプロジェクトの依存関係を使用する場合、MSBuildは参照(DLLファイル)をコピーしない
-
[解決済み] Eclipseで既存のソースからプロジェクトを作成し、それを見つけるにはどうすればよいですか?
-
[解決済み] Goで2Dスライスを作成する簡潔な方法は何ですか?
-
[解決済み] Goプログラムで静的リソースをバンドルする最良の方法は何ですか?
-
[解決済み] os.Exit()とpanic()はいつ使うのか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】複数ファイルのGoプロジェクトを整理する【クローズド
-
[解決済み] カスタムパッケージの使用方法
-
[解決済み] サーバーでSSLが有効になっていない
-
[解決済み] time.Sleepを使わずにすべてのゴルーチンが終了するのを待つには?
-
[解決済み] intをint64に変換するには?
-
[解決済み] ゴルーチンの停止方法
-
[解決済み] Goを使って大きなファイルを効率よくダウンロードするにはどうしたらいいですか?
-
[解決済み] スライスを宣言するのか、スライスを作るのか?
-
[解決済み] 単一値コンテキストにおける複数値
-
[解決済み] Goでスライスを逆に反復処理する方法はありますか?