> Source: https://www.ymotongpoo.com/works/goblog-ja/get-familiar-with-workspaces/


# ワークスペースに慣れよう

[Get familiar with workspaces](https://go.dev/blog/get-familiar-with-workspaces) by Beth Brown, for the Go team

Go 1.18ではワークスペースモードが追加され、複数のモジュールを同時に扱いながら作業できるようになりました。

Go 1.18は[ダウンロード](https://go.dev/dl/)ページから入手できます。すべての変更点の詳細は
[リリースノート](https://go.dev/doc/go1.18)を参照してください。

## ワークスペース

Go 1.18の[ワークスペース](https://go.dev/ref/mod#workspaces)を使うと、モジュールごとに `go.mod`
ファイルを編集することなく、複数のモジュールを同時に扱いながら作業できます。ワークスペース内の各モジュールは、
依存関係を解決する際にメインモジュールとして扱われます。

これまでは、あるモジュールに機能を追加して別のモジュールで使うには、最初のモジュールへの変更を公開するか、
あるいは依存先モジュールの `go.mod` ファイルを[編集](https://go.dev/doc/tutorial/call-module-code)して、
ローカルの未公開のモジュール変更に対する `replace` ディレクティブを追加する必要がありました。エラーなく
公開するためには、最初のモジュールへのローカルの変更を公開した後に、依存先モジュールの `go.mod` ファイルから
`replace` ディレクティブを削除しなければなりませんでした。

Goワークスペースを使うと、ワークスペースディレクトリのルートにある `go.work` ファイルによって、
すべての依存関係を制御できます。 `go.work` ファイルには、個々の `go.mod` ファイルを上書きする `use`
ディレクティブと `replace` ディレクティブがあるため、 `go.mod` ファイルをそれぞれ個別に編集する必要はありません。

ワークスペースを作成するには、モジュールのディレクトリのリストをスペース区切りの引数として `go work init`
を実行します。ワークスペース自体がその作業対象のモジュールを含んでいる必要はありません。 `init` コマンドは、
ワークスペース内のモジュールを列挙した `go.work` ファイルを作成します。引数なしで `go work init` を実行すると、
空のワークスペースが作成されます。

ワークスペースにモジュールを追加するには、 `go work use [moddir]` を実行するか、 `go.work` ファイルを
手動で編集します。 `go work use -r .` を実行すると、引数に指定したディレクトリ配下で `go.mod` ファイルを持つ
ディレクトリを再帰的にワークスペースへ追加します。あるディレクトリに `go.mod` ファイルがない場合、あるいは
そのディレクトリがすでに存在しない場合は、そのディレクトリに対する `use` ディレクティブが `go.work` ファイルから
削除されます。

`go.work` ファイルの構文は `go.mod` ファイルと似ており、次のディレクティブを含みます。

* `go`：goツールチェインのバージョン（例えば `go 1.18`）
* `use`：ディスク上のモジュールをワークスペース内のメインモジュール群に追加します。引数には、そのモジュールの
  `go.mod` ファイルを含むディレクトリへの相対パスを指定します。 `use` ディレクティブは、指定したディレクトリの
  サブディレクトリにあるモジュールは追加しません。
* `replace`：`go.mod` ファイルの `replace` ディレクティブと同様に、 `go.work` ファイルの `replace`
  ディレクティブは、あるモジュールの特定のバージョン、またはすべてのバージョンの内容を、別の場所にある内容で
  置き換えます。

## ワークフロー

ワークスペースは柔軟で、さまざまなワークフローに対応しています。以下の節では、私たちが最もよく使われると
考えているワークフローの概要を簡単に紹介します。

### 上流モジュールに機能を追加し、自分のモジュールで利用する

1. ワークスペース用のディレクトリを作成します。

2. 編集したい上流モジュールをクローンします。

3. 上流モジュールのローカルバージョンに、自分の機能を追加します。

4. ワークスペースフォルダで `go work init [path-to-upstream-mod-dir]` を実行します。

5. 上流モジュールに追加した機能を実装するために、自分のモジュールに変更を加えます。

6. ワークスペースフォルダで `go work use [path-to-your-module]` を実行します。

   `go work use` コマンドは、自分のモジュールへのパスを `go.work` ファイルに追加します。

   ```
   go 1.18

   use (
          ./path-to-upstream-mod-dir
          ./path-to-your-module
   )
   ```

7. 上流モジュールに追加された新機能を使って、自分のモジュールを実行しテストします。

8. 新機能を加えた上流モジュールを公開します。

9. その新機能を利用する自分のモジュールを公開します。

### 同一リポジトリ内にある相互依存する複数のモジュールを扱う

同一リポジトリ内の複数のモジュールで作業する場合、各モジュールの `go.mod` ファイルで `replace`
ディレクティブを使う代わりに、 `go.work` ファイルでワークスペースを定義します。

1. ワークスペース用のディレクトリを作成します。

2. 編集したいモジュールを含むリポジトリをクローンします。 `use` ディレクティブで各モジュールへの相対パスを
   指定するため、モジュールをワークスペースフォルダの中に置く必要はありません。

3. ワークスペースディレクトリで `go work init [path-to-module-one] [path-to-module-two]` を実行します。

   例えば、 `example.com/x/tools` モジュール内の他のパッケージに依存する `example.com/x/tools/groundhog`
   を作業対象とします。

   リポジトリをクローンし、ワークスペースフォルダで `go work init tools tools/groundhog` を実行します。

   `go.work` ファイルの内容は次のようになります。

   ```
   go 1.18

   use (
           ./tools
           ./tools/groundhog
   )
   ```

   `tools` モジュールに加えたローカルの変更は、ワークスペース内の `tools/groundhog` から利用されます。

### 依存関係の設定を切り替える

異なる依存関係の設定でモジュールをテストするには、別々の `go.work` ファイルを持つ複数のワークスペースを
作成するか、あるいは1つのワークスペースを維持したまま、1つの `go.work` ファイル内で不要な `use`
ディレクティブをコメントアウトするという方法があります。

複数のワークスペースを作成するには次のようにします。

1. 依存関係のニーズごとに別々のディレクトリを作成します。
2. 各ワークスペースディレクトリで `go work init` を実行します。
3. `go work use [path-to-dependency]` を使って、各ディレクトリに必要な依存関係を追加します。
4. 各ワークスペースディレクトリで `go run [path-to-your-module]` を実行すると、その `go.work`
   ファイルで指定された依存関係が使われます。

同一ワークスペース内で異なる依存関係を試すには、 `go.work` ファイルを開いて、必要な依存関係を追加したり、
不要なものをコメントアウトしたりします。

### GOPATHを使っている場合

ワークスペースを使うことで、考えが変わるかもしれません。 `GOPATH` を使っているユーザーは、 `GOPATH`
ディレクトリの基点に置いた `go.work` ファイルを使って依存関係を解決できます。ワークスペースは `GOPATH`
のすべてのワークフローを完全に再現することを目指しているわけではありませんが、モジュールの利点を保ちながら、
`GOPATH` の利便性の一部を共有するセットアップを作れます。

GOPATH用のワークスペースを作成するには次のようにします。

1. `GOPATH` ディレクトリのルートで `go work init` を実行します。
2. ローカルモジュールや特定のバージョンをワークスペース内の依存関係として使うには、
   `go work use [path-to-module]` を実行します。
3. モジュールの `go.mod` ファイル内の既存の依存関係を置き換えるには、
   `go work replace [path-to-module]` を使います。
4. `GOPATH` 内、あるいは任意のディレクトリにあるすべてのモジュールを追加するには、 `go work use -r`
   を実行します。これにより、 `go.mod` ファイルを持つディレクトリが再帰的にワークスペースへ追加されます。
   あるディレクトリに `go.mod` ファイルがない場合、あるいはそのディレクトリがすでに存在しない場合は、
   そのディレクトリに対する `use` ディレクティブが `go.work` ファイルから削除されます。

> `go.mod` ファイルを持たないプロジェクトをワークスペースに追加したい場合は、そのプロジェクトディレクトリに
> 移動して `go mod init` を実行し、その後 `go work use [path-to-module]` で新しいモジュールをワークスペースに
> 追加してください。

## ワークスペースのコマンド

`go work init` と `go work use` に加えて、Go 1.18ではワークスペース向けに次のコマンドが導入されました。

* `go work sync`：`go.work` ファイル内の依存関係を、ワークスペース内の各モジュールの `go.mod`
  ファイルへ反映します。
* `go work edit`：`go.work` を編集するためのコマンドラインインターフェースを提供します。主にツールや
  スクリプトからの利用を想定しています。

モジュール対応のビルドコマンドや一部の `go mod` サブコマンドは、ワークスペースのコンテキスト内にあるかどうかを
判定するために、 `GOWORK` 環境変数を調べます。

`GOWORK` 変数が `.work` で終わるファイルへのパスを示している場合、ワークスペースモードが有効になります。
どの `go.work` ファイルが使われているかを確認するには、 `go env GOWORK` を実行します。 `go` コマンドが
ワークスペースモードでない場合、出力は空になります。

ワークスペースモードが有効な場合、 `go.work` ファイルが解析され、ワークスペースモードの3つのパラメータ、
すなわちGoのバージョン、ディレクトリのリスト、置き換え（replacement）のリストが決定されます。

ワークスペースモードで試してみるとよいコマンドをいくつか挙げます（すでに何をするコマンドかご存知の前提です）。

```
go work init
go work sync
go work use
go list
go build
go test
go run
go vet
```

## エディタ体験の改善

私たちが特に心待ちにしているのは、Goの言語サーバーである
[gopls](https://pkg.go.dev/golang.org/x/tools/gopls)と
[VSCode Go拡張機能](https://marketplace.visualstudio.com/items?itemName=golang.go)のアップグレードです。
これにより、LSP対応エディタで複数のモジュールを扱う作業が、スムーズでやりがいのある体験になります。

参照の検索、コード補完、定義へのジャンプは、ワークスペース内のモジュールをまたいで機能します。 `gopls` の
[バージョン0.8.1](https://github.com/golang/tools/releases/tag/gopls%2Fv0.8.1)では、 `go.work`
ファイルに対する診断、補完、フォーマット、ホバー表示が導入されました。これらの `gopls` の機能は、任意の
[LSP](https://microsoft.github.io/language-server-protocol/)対応エディタで利用できます。

#### エディタ固有の注意点

* 最新の[vscode-goリリース](https://github.com/golang/vscode-go/releases/tag/v0.32.0)では、Goステータス
  バーのクイックピックメニューから、ワークスペースの `go.work` ファイルにすばやくアクセスできます。

![Goステータスバーのクイックピックメニューからgo.workファイルにアクセスする](./get-familiar-with-workspaces_quick-pick-menu.gif)

* [GoLand](https://www.jetbrains.com/go/)はワークスペースをサポートしており、 `go.work` ファイルに対する
  シンタックスハイライトとコード補完を追加する計画があります。

さまざまなエディタで `gopls` を使う方法の詳細については、
[goplsのドキュメント](https://pkg.go.dev/golang.org/x/tools/gopls#readme-editors)を参照してください。

## 次のステップ

* [Go 1.18](https://go.dev/dl/)をダウンロードしてインストールする。
* [Goワークスペースのチュートリアル](https://go.dev/doc/tutorial/workspaces)で
  [ワークスペース](https://go.dev/ref/mod#workspaces)を試してみる。
* ワークスペースで問題に遭遇した場合や、提案したいことがある場合は、
  [issueを作成する](https://go.dev/issue/new)。
* [ワークスペースのメンテナンスに関するドキュメント](https://pkg.go.dev/cmd/go#hdr-Workspace_maintenance)を読む。
* [単一モジュールの外で作業するためのモジュールコマンド](https://go.dev/ref/mod#commands-outside)
  （`go work init` や `go work sync` など）を調べてみる。

By Beth Brown, for the Go team

