The Go Blog
Goコードの整理
はじめに
Goコードは他の言語とは異なる方法で整理されています。この記事では、ユーザーにとって最も役立つようにGoプログラムの要素に名前を付け、パッケージ化する方法について説明します。
良い名前を選ぶ
選択する名前は、コードに対する考え方に影響を与えるため、パッケージとそのエクスポートされた識別子に名前を付ける際には注意が必要です。
パッケージの名前は、その内容のコンテキストを提供します。たとえば、標準ライブラリのbytesパッケージはBuffer型をエクスポートします。Bufferという名前だけではあまり記述的ではありませんが、パッケージ名と組み合わせるとその意味が明確になります。bytes.Bufferです。パッケージの記述性が低い名前、たとえばutilのような名前であった場合、バッファはutil.BytesBufferという長くぎこちない名前になる可能性が高いでしょう。
作業中に名前を変更することをためらわないでください。プログラムに時間を費やすにつれて、その各部分がどのように連携しているかをよりよく理解し、したがって、それらの名前がどうあるべきかを理解するでしょう。初期の決定に縛られる必要はありません。(gofmtコマンドには、構文を認識する検索および置換を提供する-rフラグがあり、大規模なリファクタリングを容易にします。)
良い名前は、ソフトウェアインターフェースの最も重要な部分です。名前は、コードのすべてのクライアントが最初に目にするものです。したがって、よく選ばれた名前は、良いドキュメントの出発点となります。以下の多くの実践は、良い命名から自然に生まれます。
良いインポートパスを選ぶ (パッケージを「go get」可能にする)
インポートパスは、ユーザーがパッケージをインポートするための文字列です。これは、パッケージのソースコードが格納されているディレクトリ($GOROOT/src/pkgまたは$GOPATH/srcからの相対パス)を指定します。
インポートパスはグローバルに一意であるべきなので、ソースリポジトリのパスをベースとして使用してください。たとえば、go.netサブパッケージのwebsocketパッケージは、インポートパスが"golang.org/x/net/websocket"です。Goプロジェクトは"github.com/golang"のパスを所有しているため、そのパスは別の作者が異なるパッケージに使用することはできません。リポジトリのURLとインポートパスが同じであるため、go getコマンドはパッケージを自動的にフェッチしてインストールできます。
ホストされたソースリポジトリを使用しない場合は、ドメイン、会社、またはプロジェクト名など、一意のプレフィックスを選択してください。例として、Googleの内部Goコードのすべてのインポートパスは、文字列"google"で始まります。
インポートパスの最後の要素は、通常、パッケージ名と同じです。たとえば、インポートパス"net/http"にはパッケージhttpが含まれています。これは必須ではありません。必要に応じて異なるものにすることもできますが、予測可能性のために慣例に従うべきです。ユーザーは、"foo/bar"のインポートがquuxという識別子をパッケージ名空間に導入することに驚くかもしれません。
GOPATHをソースリポジトリのルートに設定し、パッケージをリポジトリのルートからの相対パス(例: "src/my/package")に置く人がいます。一方で、これによりインポートパスが短くなります("github.com/me/project/my/package"ではなく"my/package")。しかし、他方では、go getが動作しなくなり、ユーザーはパッケージを使用するためにGOPATHを再設定する必要があります。これをしないでください。
エクスポートされたインターフェースを最小化する
コードは多くの小さな有用なコードの断片で構成されている可能性が高いため、その機能の多くをパッケージのエクスポートされたインターフェースで公開したくなるかもしれません。その衝動に抵抗してください!
提供するインターフェースが大きければ大きいほど、サポートしなければならないことも増えます。ユーザーは、エクスポートするすべての型、関数、変数、定数にすぐに依存するようになり、永続的に守らなければならない、またはユーザーのプログラムを壊すリスクを負う暗黙の契約を作成することになります。Go 1の準備では、標準ライブラリのエクスポートされたインターフェースを慎重にレビューし、コミットする準備ができていない部分を削除しました。独自のライブラリを配布する際にも同様の注意を払うべきです。
迷ったら、外しておこう!
パッケージに何を入れるか
すべてを「何でもあり」のパッケージに詰め込むのは簡単ですが、これはパッケージ名の意味を希薄化させ(多くの機能を網羅する必要があるため)、パッケージの小さな部分のユーザーに、多くの無関係なコードをコンパイルしてリンクすることを強制します。
一方、コードを小さなパッケージに分割しすぎるのも簡単です。その場合、単に仕事を終わらせるよりも、インターフェース設計に没頭してしまう可能性が高いでしょう。
Goの標準ライブラリを参考にしてください。そのパッケージの中には大きく、小さいものもあります。たとえば、httpパッケージは17個のGoソースファイル(テストを除く)で構成され、109個の識別子をエクスポートしています。一方、hashパッケージは1つのファイルで構成され、たった3つの宣言をエクスポートしています。厳格なルールはありません。どちらのアプローチも、それぞれのコンテキストにおいて適切です。
そうは言っても、`main`パッケージは他のパッケージよりも大きくなることがよくあります。複雑なコマンドには、実行可能ファイルのコンテキスト外ではほとんど役に立たない多くのコードが含まれており、すべてを1か所にまとめておく方が簡単な場合が多いです。たとえば、goツールは34個のファイルにわたって12000行以上のコードが記述されています。
コードをドキュメント化する
良いドキュメンテーションは、使いやすく保守性の高いコードにとって不可欠な品質です。Godoc: Goコードをドキュメント化するの記事を読んで、良いドキュメントコメントの書き方を学びましょう。
次の記事: App Engine 1.7.1におけるGoの更新
前の記事: GCC 4.7.1におけるGccgo
ブログインデックス