1
0

Goモジュールを作成してみた

Posted at

背景・目的

前回、Goについて簡単なプログラムを書いてみました。今回はGoモジュールを作成てしみます

まとめ

下記に特徴をまとめます。

特徴 説明
Goモジュールの概要 関連するパッケージをモジュールに収集し、他の開発者が使用できるようにモジュールを公開できる
Goモジュール公開の概要 ・モジュールに含まれるパッケージを設計しコーディングする

・Go ツールを介して他のユーザーが確実に利用できるようにする規則を使用して、コードをリポジトリにコミットする

・開発者から見つけられるようにモジュールを作成し公開する

・時間の経過とともに、各バージョンの安定性と下位互換性を示すバージョン番号つき規則を使用するバージョンでモジュールを改定する
go.modファイルの概要 モジュールは、ルートディレクトリにgo.modという名前のUTF-8でエンコードされたテキストファイルにより定義される
go mod tiny メイン モジュール内のすべてのパッケージと、それらがインポートするすべてのパッケージを再帰的にロードすることで機能する

概要

Developing and publishing modules

下記を基に整理します。

You can collect related packages into modules, then publish the modules for other developers to use. This topic gives an overview of developing and publishing modules.

  • 関連するパッケージをモジュールに収集し、他の開発者が使用できるようにモジュールを公開できる

Workflow for developing and publishing modules

When you want to publish your modules for others, you adopt a few conventions to make using those modules easier.

The following high-level steps are described in more detail in Module release and versioning workflow.

  1. Design and code the packages that the module will include.
  2. Commit code to your repository using conventions that ensure it’s available to others via Go tools.
  3. Publish the module to make it discoverable by developers.
  4. Over time, revise the module with versions that use a version numbering convention that signals each version’s stability and backward compatibility.
  • 他者に自分のモジュールを公開したい場合は、それらのモジュールを簡単に使用できるように、いくつかの規則を適用する
    1. モジュールに含まれるパッケージを設計しコーディングする
    2. Go ツールを介して他のユーザーが確実に利用できるようにする規則を使用して、コードをリポジトリにコミットする
    3. 開発者から見つけられるようにモジュールを作成し公開する
    4. 時間の経過とともに、各バージョンの安定性と下位互換性を示すバージョン番号つき規則を使用するバージョンでモジュールを改定する

Design and development

Your module will be easier for developers to find and use if the functions and packages in it form a coherent whole. When you’re designing a module’s public API, try to keep its functionality focused and discrete.

  • 関数とパッケージが一貫した全体を形成している場合、開発者はモジュールを見つけられ使用することは簡単
  • モジュールのパブリック API を設計するときは、その機能に焦点を当て、個別に保つようにする

Also, designing and developing your module with backward compatibility in mind helps its users upgrade while minimizing churn to their own code. You can use certain techniques in code to avoid releasing a version that breaks backward compatibility. For more about those techniques, see Keeping your modules compatible on the Go blog.

  • 下位互換性を念頭に置きモジュールを設計、開発すると、ユーザが独自のコードへの変更を最小限に抑えながらアップグレードするのに役立つ
  • コード内で特定のテクニックを使用すると、下位互換性をそこなバージョンのリリースを回避できる

Before you publish a module, you can reference it on the local file system using the replace directive. This makes it easier to write client code that calls functions in the module while the module is still in development. For more information, see “Coding against an unpublished module” in Module release and versioning workflow.

  • モジュールを公開する前に、replaceディレクティブを使用してローカルファイルシステム上でモジュールを参照できる
  • これによりモジュールの開発中にモジュール内の関数を呼び出すクライアントコードを簡単に作成できる

Decentralized publishing

In Go, you publish your module by tagging its code in your repository to make it available for other developers to use. You don’t need to push your module to a centralized service because Go tools can download your module directly from your repository (located using the module’s path, which is a URL with the scheme omitted) or from a proxy server.

  • Goでは、リポジトリ内のコードにタグ付けし、モジュールを公開し、他の開発者が使用できるようにする
  • Goツールはリポジトリ、プロキシサーバからモジュールを直接ダウンロードできるので、モジュールを一元化されたサービスにPushする必要はない

After importing your package in their code, developers use Go tools (including the go get command) to download your module’s code to compile with. To support this model, you follow conventions and best practices that make it possible for Go tools (on behalf of another developer) to retrieve your module’s source from your repository. For example, Go tools use the module’s module path you specify, along with the module version number you use to tag the module for release, to locate and download the module for its users.

  • パッケージをコードにインポートした後、開発者はGoツールを使用して、コンパイルに使用するモジュールのコードをダウンロードする
  • このモデルをサポートするには、Goツールがリポジトリからモジュールのソースを取得するための規則とベストプラクティスに従う
    • 例)Go ツールは、指定したモジュールのモジュール パスと、リリース用のモジュールにタグを付けるために使用したモジュールのバージョン番号を使用して、モジュールを見つけてユーザーにダウンロードする

Package discovery

After you’ve published your module and someone has fetched it with Go tools, it will become visible on the Go package discovery site at pkg.go.dev. There, developers can search the site to find it and read its documentation.

  • モジュールを公開したあと、Goツールからフェッチすると、そのモジュールはpkg.go.devに表示される

To begin using the module, a developer imports packages from the module, then runs the go get command to download its source code to compile with.

  • モジュールの試用を開始するには、開発者はモジュールからパッケージをインポートし、go getコマンドを実行しコンパイルに使用するソースをダウンロードする

Versioning

As you revise and improve your module over time, you assign version numbers (based on the semantic versioning model) designed to signal each version’s stability and backward compatibility. This helps developers using your module determine when the module is stable and whether an upgrade may include significant changes in behavior. You indicate a module’s version number by tagging the module’s source in the repository with the number.

  • 時間の経過とともに、モジュールの改訂、改善を行うと、各バージョンの安定性と下位互換性を示すように設計されたバージョン番号を割り当てる
  • モジュールを使用する開発者が、モジュールがいつ安定するか、およびアップグレードに動作の重大な変更が含まれるかどうかを判断するのに役立つ

go.mod files

下記を基に整理します。

A module is defined by a UTF-8 encoded text file named go.mod in its root directory. The go.mod file is line-oriented. Each line holds a single directive, made up of a keyword followed by arguments.

  • モジュールは、ルートディレクトリにgo.modという名前のUTF-8でエンコードされたテキストファイルにより定義される
  • go.modは行指向
  • 各行には、キーワードとそれに続く引数で構成される単一のディレクティブが含まれる
  • サンプルは、下記の通り
    module example.com/my/thing
    
    go 1.12
    
    require example.com/other/thing v1.0.2
    require example.com/new/thing/v2 v2.3.4
    exclude example.com/old/thing v1.2.3
    replace example.com/bad/thing v1.4.5 => example.com/good/thing v1.4.5
    retract [v1.9.0, v1.9.5]
    
    

The leading keyword can be factored out of adjacent lines to create a block, like in Go imports.

  • Go のインポートと同様に、先頭のキーワードを隣接する行から取り除いてブロックを作成できる

    require (
        example.com/new/thing/v2 v2.3.4
        example.com/old/thing v1.2.3
    )
    

The go.mod file is designed to be human readable and machine writable. The go command provides several subcommands that change go.mod files. For example, go get can upgrade or downgrade specific dependencies. Commands that load the module graph will automatically update go.mod when needed. go mod edit can perform low-level edits. The golang.org/x/mod/modfile package can be used by Go programs to make the same changes programmatically.

  • go.modファイルは、人間が読み取り、マシンが書き込みできるように設計されている
  • goコマンドは、go.modファイルを変更するいくつかのサブコマンドが提供されている
      • go get
        • 特定の依存関係をアップグレード、またはダウングレードできる
      • go edit
        • 低レベルの編集ができる

go mod tidy

下記を基に整理します。

  • Usage:
    go mod tidy [-e] [-v] [-go=version] [-compat=version]
    

go mod tidy ensures that the go.mod file matches the source code in the module. It adds any missing module requirements necessary to build the current module’s packages and dependencies, and it removes requirements on modules that don’t provide any relevant packages. It also adds any missing entries to go.sum and removes unnecessary entries.

  • go mod tidyは、go.modファイルがモジュール内のソースコードと一致することを確認する
  • 現在のモジュールのパッケージと依存関係を構築するために必要な不足しているモジュール要件が追加され、関連するパッケージを提供しないモジュールの要件が削除される
  • 不足しているエントリがあれば go.sum に追加され、不要なエントリが削除される

go mod tidy works by loading all of the packages in the main module and all of the packages they import, recursively. This includes packages imported by tests (including tests in other modules). go mod tidy acts as if all build tags are enabled, so it will consider platform-specific source files and files that require custom build tags, even if those source files wouldn’t normally be built. There is one exception: the ignore build tag is not enabled, so a file with the build constraint // +build ignore will not be considered. Note that go mod tidy will not consider packages in the main module in directories named testdata or with names that start with . or _ unless those packages are explicitly imported by other packages.

  • go mod tinyは、メイン モジュール内のすべてのパッケージと、それらがインポートするすべてのパッケージを再帰的にロードすることで機能する
    • テストによりインポートされたパッケージが含まれる
  • すべてのビルドタグが有効であるかのように動作するため、プラットフォーム固有のソースとカスタムビルドタグを必要とするファイルが、通常はビルドされないソースであっても考慮される

実践

前提

下記を使用しています。

  • MacOS
  • VSCode
  • Go 1.23.0

Start a module that others can use

下記を基に試します
https://go.dev/doc/tutorial/create-module

このチュートリアルでは、2 つのモジュールを作成します。

  • 1 つ目は、他のライブラリまたはアプリケーションによってインポートされることを目的としたライブラリ
  • 2 つ目で、最初のアプリケーションを使用する呼び出し側アプリケーションを作成します

Start a module that others can use

Goモジュールを作成します。

  • Goコードは、パッケージにグループ化され、パッケージはモジュールにグループ化される
  • モジュールは、Goのバージョンや他のモジュールのセットなど、コードを実行するために必要な依存関係を指定する
  • モジュールの機能を追加または改善すると、モジュールの新しいバージョンが公開される
  • モジュール内の関数を呼び出すコードを作成する開発者は、実稼働環境で使用する前に、モジュールの更新されたパッケージをインポートし、新しいバージョンでテストできる
  1. Goモジュールコードを配置するgreetingsディレクトリを作成します

    go-tutrial $ mkdir greetings
    go-tutrial $ cd greetings 
    
  2. go mod initコマンドにより、モジュールパスを指定します。(example.com/greetings)を使用します

    • モジュールを公開する場合、Goツールによりモジュールをダウンロードできるパスである必要がある。(これがコードのリポジトリになる)
    • go mod initコマンドにより、コードの依存関係を追跡するためのgo.modファイルを作成する
      • はじめに、ファイルには、モジュールの名前と、コードがサポートするGoバージョンが含まれている
      • 依存関係を追加すると、コードが依存するバージョンがgo.modファイルにリストされる
      • これにより、ビルドの再現性が維持され使用するバージョンを直接制御できる
    greetings $ go mod init example.com/greetings
    go: creating new go.mod: module example.com/greetings
    greetings $ ls 
    go.mod
    greetings $ cat go.mod 
    module example.com/greetings
    
    go 1.23.0
    greetings $ 
    
  3. grettings.goというファイルを作成します

    greetings $ touch grettings.go
    greetings $ ls
    go.mod          grettings.go
    greetings $
    
  4. 下記のコードを書きます

    • 関数に渡されたnameで挨拶する
    package greetings
    
    import "fmt"
    
    // Hello returns a greeting for the named person.
    func Hello(name string) string{
    	message := fmt.Sprintf("Hi, %v. Welcome!", name)
    	return message
    }
    
    • stringのnameを受け取る

      • 戻り値もstring
      • Goでは、名前が大文字で始まる関数は、同じパッケージにない関数から呼び出せる(Goではエクスポート名という)
      • :=オペレータは、1行で変数の宣言と初期化を行うショートカット
        • 右側の値を使用して変数の型を決めている
        • 省略しない書き方に直すと下記になる
        var message string
        message = fmt.Sprintf("Hi, %v. Welcome!", name)
        

Call your code from another module

ここでは、上記で作成したモジュール内のHello関数を呼び出すコードを作成します

  1. helloディレクトリを作成します

    go-tutrial $ mkdir hello
    go-tutrial $ tree
    .
    ├── greetings
    │   ├── go.mod
    │   └── grettings.go
    └── hello
    
    go-tutrial $ cd hello
    hello $ 
    
  2. go mod initコマンドを実行し依存関係の追跡を有効にします

    • example.com/helloのモジュールパスを使用します
    hello $ go mod init example.com/hello
    go: creating new go.mod: module example.com/hello
    hello $ ls
    go.mod
     hello $ cat go.mod 
    module example.com/hello
    
    go 1.23.0
    hello $
    
  3. hello.goファイルを作成します

    hello $ touch hello.go
    hello $ ls
    go.mod          hello.go
    hello $
    
  4. Hello関数を呼び出すコードを書きます

    package main
    
    import (
    	"fmt"
    
    	"example.com/greetings"
    )
    
    func main() {
    	// Get a greeting message and print it.
    	message := greetings.Hello("Gladys")
    	fmt.Println(message)
    }
    
    • mainパッケージを宣言する。(Goではアプリケーションとして実行されるコードはメインパッケージに存在する必要がある)
    • fmtexample.com/greetingsパッケージをインポートすることで、コードからこれらのパッケージ内の関数にアクセスできる
      • example.com/greetingsパッケージをインポートすることで、Hello関数にアクセスできる
  5. ローカルのexample.com/greetingsを使用するようにexample.com/helloモジュールを変更します

    • 本番環境で使用する場合は、リポジトリからexample.com/greetingsモジュールを公開する
    • 現時点では、モジュールを公開してないので、ローカルファイルシステム上でexample.com/greetingsコードを見つけられるように、example.com/helloを調整する
    • go mod editコマンドを使用して、example.com/helloモジュールを編集し、Goツールをそのモジュールパスからローカルディレクトリにリダイレクトする
    hello $ pwd
    /HOMEDIR/XXXX/YYY/go-tutrial/hello
    hello $
    hello % go mod edit -replace example.com/greetings=../greetings
    hello % cat go.mod 
    module example.com/hello
    
    go 1.23.0
    
    replace example.com/greetings => ../greetings
    
    • replace されました
  6. go mod tidyコマンドを実行し、example.com/helloモジュールの依存関係を同期し、モジュール内で追跡されていない依存関係を追加します

    hello $ go mod tidy
    go: found example.com/greetings in example.com/greetings v0.0.0-00010101000000-000000000000
    hello $
    hello $ cat go.mod 
    module example.com/hello
    
    go 1.23.0
    
    replace example.com/greetings => ../greetings
    
    require example.com/greetings v0.0.0-00010101000000-000000000000
    hello $
    
    • greetingsディレクトリでローカルコードを見つけ、example.com/helloexample.com/greetingsを必要とすることを指定するrequireディレクトリが追加される
    • モジュールパス後の数字は、擬似的なバージョン
  7. go run .により実行します

    hello $ go run .
    Hi, Gladys. Welcome!
    hello $
    

考察

今回は、Goモジュールの作成を試してみました。モジュールを作成し、利用する際の取り込み方法まで実践できました。
引き続き、チュートリアルに基づき理解を深めていきたいと思います。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0