目次

    Goの命名規則ベストプラクティス:変数・関数・パッケージ名をマスターする
    Go命名規則ベストプラクティスコード品質可読性

    2025-06-18

    梯子登っている男性の絵

    Goの命名規則ベストプラクティス:変数・関数・パッケージ名をマスターする

    はじめに

    良いコードは読みやすいコードである。そしてGoでは、その読みやすさは「優れた命名」から始まります。Goが「シンプルさ」と「明瞭さ」を重視する言語であることは広く知られていますが、その思想は命名規則にも色濃く反映されています。Javaの冗長な命名文化とは対照的に、Goは文脈を活用した簡潔で意味のある命名を推奨します。

    この記事では、Goの公式ドキュメントでも推奨されている、パッケージ、変数、関数、インターフェースなどの命名に関するベストプラクティスを、具体的な例と共に解説していきます。これらの規則をマスターすることで、より「イディオマティックなGo(Goらしい作法)」を実践できるようになるでしょう。

    Go命名規則のベストプラクティス

    ここで紹介するプラクティスの多くは、Goの公式ドキュメントEffective Goに基づいています。

    ① パッケージ名:短く、簡潔に、単数形で

    Goにおけるパッケージ名は、そのパッケージの機能を端的に表現する重要な要素です。

    ルール

    • 小文字の単一単語で、意味が明確な名前を選ぶ
    • スネークケース(_)やキャメルケースは使わない
    • 利用者が推測しやすい、一般的な名前を選ぶ

    NG例とOK例

    go
    1// NG例
    2
    3package http_utils // スネークケースはNG
    4package httpClient // キャメルケースはNG
    5
    6// OK例(標準ライブラリの例)
    7
    8package http
    9package user
    10package context

    注意:

    • Go 1.16以降、ioutilパッケージは非推奨となり、主な関数はioosパッケージに移管されています。新規開発ではio.ReadAllなどを使用してください。過去資産でioutil.ReadAll等が使われている場合は、io.ReadAllに置き換えることを推奨します。古いコードをメンテナンスする際はこの点にご注意ください。
    • 上記は標準ライブラリの命名例です。自作パッケージで標準ライブラリと同名(contexthttpなど)を使用すると、importの際に衝突が起こる可能性があります。自作パッケージでは用途に応じて衝突を避ける命名を検討してください。

    なぜこうするのか?

    インポートした際にhttp.Clientのように使われるため、パッケージ名自体が名前空間として機能します。http.HTTPClientのような冗長な繰り返し(スタッター)を避ける設計思想がGoには根付いています。パッケージ名は短く保つことで、利用する側のコードがより読みやすくなります。

    注意: utilcommonといった曖昧すぎる名前は避けましょう。パッケージの具体的な機能を表現する名前を選ぶことで、コードの意図がより明確になります。

    ② 変数名:スコープの広さが長さを決める

    Goでは、変数のスコープの広さによって適切な名前の長さが決まります。

    ルール

    • スコープが狭ければ短い名前(ierrreqresp
    • スコープが広ければより説明的な名前を選ぶ
    • mixedCaps(一般的にcamelCaseと呼ばれる)を使用する(snake_caseは非推奨)

    注意: Go公式では「mixedCaps」という用語を使用しますが、一般的には「camelCase」として知られています。

    公開・非公開の制御

    Goの最重要ルールの一つが、先頭が大文字なら公開(Exported)、小文字なら非公開(Unexported)という規則です。これがアクセス修飾子の代わりとなります。

    go
    1// 公開される変数・関数 (他パッケージからアクセス可能)
    2
    3var MaxConnections = 100
    4func ProcessRequest() {}
    5
    6// 非公開の変数・関数 (同一パッケージ内からのみアクセス可能)
    7
    8var maxRetries = 3
    9func validateInput() {}

    スコープに応じた命名例

    go
    1// 短いスコープ:簡潔な名前
    2
    3for i, user := range users {
    4    if err := processUser(user); err != nil {
    5        return fmt.Errorf("failed to process user %d: %w", i, err)
    6    }
    7}
    8
    9// 長いスコープ:説明的な名前
    10
    11type UserRepository struct {
    12    databaseConnection *sql.DB
    13    cacheClient        *redis.Client
    14}

    注意: コード例ではfmtsqlredisなどのimport文を省略しています。実際のコードでは適切なimport文が必要です。

    ③ 定数:ALL_CAPSは使わない

    多くの言語とは異なり、Goでは定数にALL_CAPS(スネークケースの大文字)を使用しません。

    ルール

    • 変数と同様に、公開・非公開に応じてPascalCasecamelCaseを使用する

    NG例とOK例

    go
    1// NG例
    2
    3const MAX_CONNECTIONS = 100
    4
    5// OK例
    6
    7const MaxConnections = 100  // 公開定数
    8const defaultTimeout = 30   // 非公開定数

    iotaを使った列挙定数

    go
    1type Status int
    2
    3const (
    4    StatusPending Status = iota  // 型名と同じベース名で始める
    5    StatusRunning
    6    StatusCompleted
    7    StatusFailed
    8)

    この慣習により、コードの見た目がより統一されます。

    ④ 関数・メソッド名:何をするかが明確にわかるように

    ルール

    • 変数と同様に、公開・非公開を大文字・小文字で制御する
    • Getプレフィックスは冗長な場合が多いため、付けないのが慣習
    • 頭字語(HTTP、URL、JSONなど)は全て大文字で扱う

    Getterの命名

    go
    1// NG例(単純なフィールドアクセス)
    2
    3func (u *User) GetName() string { return u.name }
    4
    5// OK例(単純なフィールドアクセス)
    6
    7func (u *User) Name() string { return u.name }
    8
    9// 別のロジックを含む場合は意味のある名前を使用
    10
    11func (u *User) DisplayName() string { 
    12    if u.nickname != "" {
    13        return u.nickname
    14    }
    15    return u.name
    16}
    17
    18func (u *User) FullName() string {
    19    return u.firstName + " " + u.lastName
    20}
    21
    22// 文脈によってはGetが適切な場合もある
    23
    24func GetUserData(userID string) (*User, error) {} // 外部リソース取得

    注意: 単純なフィールドアクセスではGetプレフィックスを避けますが、外部リソース取得やAPI呼び出しなど、文脈上Getが自然な場合は使用することもあります。同じパッケージ内でName()が紛らわしい場合は、DisplayName()FullName()など、より意味のある名前を使用しましょう。FetchLoadRetrieveなどの動詞がより意味を表す場合もあります。

    頭字語(Initialisms)の扱い

    Goでは、HTTP、URL、JSONなどの頭字語は、型名や関数名などの識別子中で大文字綴りとする慣習があります。

    go
    1// NG例: 頭字語の一部だけ大文字/小文字混在
    2
    3func parseJson(data []byte) error {}     // "Json" の "J" は大文字、残りは小文字 → NG
    4func HttpGet(url string) error {}        // "Http" の "H" は大文字、残りは小文字 → NG
    5
    6// OK例: 頭字語をすべて大文字
    7
    8func parseJSON(data []byte) error {}     // 非公開関数
    9func HTTPGet(url string) error {}        // 公開関数
    10func NewAPIClient() *APIClient {}        // API も頭字語として扱う

    標準的なInitialisms

    代表的な頭字語例:HTTPURLJSONXMLAPIIDSQLCPUDBTLSUUIDなど

    注意:

    • パッケージ名は全て小文字のためhttpurlと書きますが、型や関数ではHTTPURLとします。
    • プロジェクト固有の略語を使う場合は、チーム内でリスト化・ルール化し、一貫して運用することを推奨します。

    ⑤ インターフェース名:「-er」サフィックスの慣習

    Goのインターフェース命名には独特の慣習があります。

    ルール

    • 単一のメソッドを持つインターフェースには、メソッド名に「-er」を付けた名前が推奨される

    go
    1// Read()メソッドを持つインターフェース
    2
    3type Reader interface {
    4    Read([]byte) (int, error)
    5}
    6
    7// Write()メソッドを持つインターフェース
    8
    9type Writer interface {
    10    Write([]byte) (int, error)
    11}
    12
    13// Goの標準ライブラリで最も有名な例の一つ
    14// String()メソッドを持つインターフェース
    15
    16type Stringer interface {
    17    String() string
    18}

    この命名規則は、標準ライブラリのfmt.Stringerなど、至る所で見られます。

    複数メソッドの場合

    複数のメソッドを持つ場合は、機能を表す名詞やInterfaceを名称に含めるパターンを用います。

    go
    1// 複数メソッドを持つインターフェース
    2
    3type Handler interface {
    4    ServeHTTP(ResponseWriter, *Request)
    5}
    6
    7// sortパッケージの例:何のインターフェースかが明確
    8
    9type Interface interface {
    10    Len() int
    11    Less(i, j int) bool
    12    Swap(i, j int)
    13}
    14
    15// 機能を表す名詞を使用
    16
    17type Database interface {
    18    Query(query string, args ...interface{}) (*Rows, error)
    19    Exec(query string, args ...interface{}) (Result, error)
    20    Close() error
    21}
    22
    23// 自作パッケージでは具体的な名前を推奨
    24
    25type UserInterface interface {
    26    GetID() int
    27    GetName() string
    28    IsActive() bool
    29}

    注意: 標準ライブラリのsort.Interfaceのように、パッケージ内では単にInterfaceという名前でも文脈から意味が明確ですが、自作パッケージではUserInterfacePaymentInterfaceなど、何のインターフェースかが分かる名前を使用することを推奨します。

    コラム:なぜGoの命名は短いのか?

    Goの命名が他の言語と比べて短い理由には、深い思想的背景があります。Goでは、変数が宣言された場所と使われる場所の「距離」が短い場合、短い名前(例:i, err, req)の方が、冗長な名前よりもノイズが少なく、コードの主要なロジックを追いやすいという考え方があります。

    go
    1// forループ内の 'i' が 'index' であることは文脈から明らか
    2
    3for i := 0; i < len(users); i++ {
    4    // ...
    5}

    また、Goツールチェーン(gofmtgoimports)により自動で整形されるため、簡潔な命名はgofmt後の可読性も向上させます。短い関数名は視線移動コストを下げ、チーム開発においてはレビューコストの低減にも寄与します。

    ただし、Goではあえて短くしすぎない(スコープが広い場合は説明的名前を使う)バランスが重要です。短すぎて意味が不明になることも、長すぎてノイズになることも避け、コンテキストを効果的に利用することで、適切な長さの名前を選択できるようになります。

    まとめ:良い命名は、未来の自分と同僚への思いやり

    Goにおける良い命名とは「明瞭さ、簡潔さ、そして文脈の活用」です。これらの命名規則をマスターすることは、単なるルールの遵守ではなく、読みやすく保守性の高いコードを書くためのプロフェッショナルな習慣です。

    良い命名は、6か月後の自分がコードを読み返したときの理解を助け、チーム開発を円滑にします。これらは、プロジェクトの成功に直結する重要なスキルなのです。

    私たちGoForceは、このようなイディオマティックなGoを書きこなす、プロ意識の高いエンジニアを高く評価しています。あなたのその「綺麗なコードを書く力」を、次の挑戦的なフリーランス案件で活かしませんか。ぜひ一度、私たちにご相談ください。

    会員登録はこちら

    最適なGo案件を今すぐチェック!

    会員登録

    生年月日 *

    /

    /

    Go経験年数 *

    /

    利用規約プライバシーポリシーに同意してお申し込みください。