Беглый взгляд на Go Workspaces в Go 1.18
Скоро выходит версия Go 1.18, и в массовом сознании она, скорее всего, будет ассоциироваться с Generic-ами. Но помимо них туда попадает еще несколько вкусных фичей. Например, Go Workspaces.
Что даёт Go Workspaces?
Go Workspaces позволяет работать одновременно с несколькими модулями. Теоретически это можно было делать и раньше, но Go Workspaces добавляет немного комфорта.
Ранее при работе с несколькими модулями одновременно их нужно было «связать» через директиву replace
в go.mod
-файле.
Подход с replace-ами в go.mod
имеет ряд существенных недостатков:
каждый модуль живёт своей независимой жизнью и некоторый инструментарий разработки умеет одновременно работать только с одним модулем.
replace
-ы не транзитивны. То есть если вы добавляете вgo.mod
новыйreplace
, то его надо добавить во все использующие его модули. Даже при небольшом количестве модулей это доставляет заметные неудобства.запустить утилиту через
go run
можно только из каталогов тех модулей, которые либо содержат эту утилиту, либо «видят» её через replace (при этом она еще должна быть объявлена какrequire
).
Go Workspaces добавляет немного комфорта:
gopls
предоставляет информацию сразу по всем используемым модулям;общие
replace
-ы можно описать в одном месте, и они видны для всех объявленных модулей;локальные правки с директивой
replace
не нужно прописывать внутриgo.mod
файлов, которые лежат в репозитории;сборка и запуск утилит для всех объявленных модулей может быть из каталога, в котором лежит
go.work
и его дочерних каталогов;добавляется команда
go work sync
, которая позволяет обновить зависимости нескольких модулей до наиболее свежей общей версии.
Как оно работает?
При использовании go.work
-файла Go собирает общий список зависимостей из всех перечисленных в go.mod
-файлов, с учетом replace
-директив. На базе всех перечисленных зависимостей формируется единый граф зависимостей, который и применяется ко всем используемым модулям. Если для одного модуля указано в разных go.mod
несколько конфликтующих replace
-директив — будет ошибка.
К примеру, если один модуль требует зависимость на github.com/davecgh/go-spew версии v1.1.1
, а другой модуль требует зависимость на github.com/davecgh/go-spew версии v1.1.0
, то оба модуля будут исполняться с более старшей версией v1.1.1
.
Это работает для всех модулей одного Go Workspace, даже если между модулями нет зависимости.
Что не даёт Go Workspace?
Если вы хотите использовать несколько go.mod
-файлов в рамках одного (моно)репозитория, то go.work
вам никак в этом не поможет: в рамках одного Go Workspace используются общие зависимости, собранные на основе всех используемых go.mod
-файлов. То есть такой подход ничем принципиально не будет отличаться от использования одного go.mod
-файла, кроме увеличения сложности за счет большего количества используемых файлов.
Собственно ссылка на соседние модули через тэги или идентификатор коммита также остаются за кадром Go Workspace.
Как начать использовать Go Workspaces?
Для использования Go Workspaces добавилась группа команд go work
.
Для начала нужно вызвать команду go work init
в корне рабочего пространства.
Допустим у нас есть рабочее пространство вида:
Тогда для использования Go Workspaces надо:
Создать
go.work
файл:go work init
Добавить туда модули:
go work use shared go work use tools
В итоге создастся файл go.work
с содержимым вида:
go 1.18
use (
shared
tools
)
И далее, к примеру, можно вызвать сборку из любого подкаталога внутри рабочего пространства:
go run github.com/bozaro/go/go-work-play/tools/hello
Если в go.work
добавить replace
-ы, то они так же будут иметь эффект на все модули рабочего пространства.
Какие еще есть проблемы?
Важно понимать, что использование Go Workspaces меняет поведение некоторых команд, например:
go run
перестаёт работать для модулей, которые не объявлены вgo.work
;go list
не может менятьgo.mod
файлы:
go list -mod=mod -m -json
go: -mod may only be set to readonly when in workspace mode, but it is set to "mod"
Remove the -mod flag to use the default readonly value,
or set -workfile=off to disable workspace mode.
К этому изменению некоторые утилиты могут быть не готовы.
Подведение итогов
Я для себя сделал следующие выводы.
Использование Go Workspaces сильно упрощает выполнение каких-либо утилит за счет возможности вызова их из любого места рабочего пространства без лишних приседаний.
Можно не добавлять паразитные
replace
директивы вgo.mod
файлы для того, чтобы править одновременно несколько связанных проектов.При использовании
go.work
можно получить ситуацию, запускаемый код будет выполняться не с теми зависимостями, которые указаны вgo.mod
файле, и об этом нужно помнить. К счастью, зависимости можно свести через командуgo work sync
.Проблема с несколькими
go.mod
в рамках одного репозитория с помощью Go Workspaces не решается никак.