フューチャー技術ブログ

Go 1.18集中連載 Workspacesモードを試してみた

はじめに

Go 1.18連載の5本目です。

Go 1.18からGoのマルチモジュール1での開発を便利にするWorkspacesモードが導入されます。Workspacesモードの導入背景はマルチモジュールでの開発体験を改善することです。詳しくはProposal: Multi-Module Workspaces in cmd/goのBackgroundやScopeに記載があります。

Workspacesモードがどのように動作するか知るためには、実際に動かしてみるのがよいでしょう。本記事ではWorkspacesモードを試してみた結果を紹介します。GoのバージョンはGo 1.18 beta2を使っています。

マルチモジュール構成

早速、例として、Workspacesモードが存在しない場合のマルチモジュール構成を考えてみます。

> tree

.
├── names
│   ├── company.go
│   └── go.mod
└── tools
├── cmd
│   └── main.go
└── go.mod
  • names モジュール
names/go.mod
module github.com/d-tsuji/sample-go-workspace/names

go 1.18
names/company.go
package names

const Name = "Future"
  • tools モジュール
tools/go.mod
module github.com/d-tsuji/sample-go-workspace/tools

go 1.18

require github.com/d-tsuji/sample-go-workspace/names v0.0.0-20220215133818-3d5d200fc3de

replace github.com/d-tsuji/sample-go-workspace/names => ../names
tools/cmd/main.go
package main

import (
"fmt"
"github.com/d-tsuji/sample-go-workspace/names"
)

func main() {
fmt.Println(names.Name)
}

マルチモジュール構成で開発している場合、ローカルファイルシステムに存在する依存モジュールを参照するために go.mod ファイルで replace ディレクティブを使って参照することがあります。本例では replace ディレクティブが必要な go.mod ファイルは1つですが、複数のモジュールが依存していると複数のモジュールの go.mod をもれなくメンテナンスする必要があります。マルチモジュール構成の開発で replace ディレクティブに苦しめられたのは私だけではないはずです。

Workspacesモード

さて本題のWorkspacesモードを紹介します。

go work init コマンドでWorkspacesモードの対象とするモジュールのパスを指定して、go.work ファイルを作成します。go.work ファイルが存在すると、go コマンドはWorkspacesモードになります。

> go work init names tools

ディレクトリ構成は以下です。go.work ファイルが存在することと go.modreplace ディレクティブが存在しないことが最初に紹介したマルチモジュール構成の例との大きな違いです。

.
├── go.work
├── names
│   ├── company.go
│   └── go.mod
└── tools
├── cmd
│   └── main.go
└── go.mod

go.work ファイルは go.mod ファイルと同様な形式で記述されるファイルです。go.work ファイルに含まれる use ディレクティブは go.mod ファイルを含む相対パスまたは絶対パスが記述されます。また use ディレクティブにはコメントを書くこともできます。

go.work
go 1.18

use (
./names // github.com/d-tsuji/sample-go-workspace/names
./tools
)

go.mod ファイルには replace ディレクティブは不要です。

tools/go.mod
module github.com/d-tsuji/sample-go-workspace/tools

go 1.18

require github.com/d-tsuji/sample-go-workspace/names v0.0.0-20220215133818-3d5d200fc3de

replace ディレクティブなしに use で指定したモジュールの依存を解決できます。以下のように動作を確認できます。

> go run tools\cmd\main.go
Future

もちろん以下のように go.work ファイルで指定しなかった場合は依存関係を解決できません。

go.work
go 1.18
-
-use (
- ./names
- ./tools
-)
go run tools\cmd\main.go
tools\cmd\main.go:5:2: package github.com/d-tsuji/sample-go-workspace/names is not in GOROOT (c:\go\src\github.com\d-tsuji\sample-go-workspace\names)

go work コマンドは init の他に、go.work ファイルを修正する edit コマンドや go.work ファイルにディレクトリを追加する use コマンド、sync コマンドなどいくつかのコマンドがあります。Go Modules Reference にある go work init などに詳しく書いてあります。

  • gopls でのサポート
    今後、gopls においてもWorkspacesモードをサポートするProposalもあります。開発ツール含めて、マルチモジュールの開発体験を改善していく動きがあります。
  • go.work ファイルはリポジトリにコミットしない慣習
    Proposalでは go.work ファイルはリポジトリにコミットしないことを推奨しています。go.work ファイルによってリポジトリのビルド構成が変更されてしまうため、とあります。github/gitignore のGoのテンプレートにも go.work ファイルが追加されていました。2

とはいえ、go.work ファイルを共有したいユースケースもありそうなので、このあたりの議論に詳しい方、こっそり教えて下さい。

さいごに

Go 1.18で導入されるWorkspacesモードを試してみました。Workspacesモードを学ぶにあたって、Proposalを書いた本人のデモ動画(Go Workspaces Proposal Demo)なども参考になりました。マルチモジュールの開発体験が向上するWorkspacesモード、リリースが楽しみです。


  1. 1.マルチモジュールとは、あるリポジトリに複数のモジュールが含まれるようなリポジトリを指し、それぞれのモジュールが go.mod ファイルを持ちます。https://github.com/golang/go/wiki/Modules#faqs--multi-module-repositories
  2. 2.https://github.com/github/gitignore/blob/438cb4af67f3a09c008c5c3f5c1ec325511b8970/Go.gitignore