Pola pengembangan modern sering memecah satu produk menjadi banyak module: library utilitas, library domain, lalu beberapa aplikasi. Masalahnya, mode default Go menyelesaikan dependency lewat go.mod — yang berarti pihak lain harus merilis versi dulu sebelum bisa dipakai. Mau memperbaiki satu baris di library sambil langsung mengujinya di aplikasi? Kita terpaksa salin-salin path atau main replace manual. Sejak Go 1.18, berkas go.work menjadi jawaban resmi untuk ini: satu workspace yang menyatukan beberapa module lokal dalam satu sesi pengembangan. Pada chapter ini kita akan membangun workspace nyata dari dua module dan membandingkannya dengan cara lama.
Masalah: Module Terpisah yang Saling Membutuhkan #
Demo kita terdiri dari dua module terpisah. Module contoh.com/formatter menyediakan fungsi Kapital, sementara module contoh.com/aplikasi mengimpornya:
package main
import (
"fmt"
"contoh.com/formatter"
)
func main() {
fmt.Println(formatter.Kapital("go workspace"))
}package formatter
import "strings"
// Kapital mengubah seluruh huruf menjadi kapital.
func Kapital(s string) string {
return strings.ToUpper(s)
}Menjalankan aplikasi dalam keadaan polos gagal — go.mod-nya belum menyebut formatter karena modul itu belum pernah dirilis:
cd mod-b && go run .Output yang Dihasilkan:
main.go:6:2: no required module provides package contoh.com/formatter; to add it:
go get contoh.com/formatterSaran go get contoh.com/formatter hanya berhasil bila module tersebut sudah dipublikasikan ke repository dan proxy. Untuk pengembangan lokal, kita butuh mekanisme lain.
Cara Lama: Directive replace #
Solusi era sebelum workspace adalah replace pada go.mod pemanggil, diarahkan ke direktori lokal:
module contoh.com/aplikasi
go 1.27.2
require contoh.com/formatter v0.0.0
replace contoh.com/formatter => ../mod-aDengan konfigurasi tersebut go run . kembali berhasil dan mencetak GO WORKSPACE (exit 0). Namun cara ini punya tiga ketidaknyamanan: setiap rekan tim harus menulis replace versinya sendiri, path relatif menuntut struktur folder yang sama persis di semua mesin, dan go.mod produksi harus dibersihkan sebelum rilis agar tidak menunjuk ke folder pribadi pengembang.
go work init: Workspace Resmi #
Perintah go work init membuat berkas go.work yang mendaftarkan module lokal ke dalam satu workspace. Dijalankan dari direktori induk yang memuat kedua module:
go work init ./mod-a ./mod-bPerintah ini berhasil dengan status 0 tanpa keluaran. Isi go.work yang terbentuk:
go 1.27.2
use (
./mod-a
./mod-b
)Direktif use menyatakan: “saat build berlangsung dalam workspace ini, resolusi import path contoh.com/formatter diarahkan ke ./mod-a lokal” — tanpa menyentuh go.mod kedua module sama sekali. Sekarang program berjalan:
go run ./mod-bOutput yang Dihasilkan:
GO WORKSPACEMari kita telaah mekanisme yang barusan terjadi:
- Pencarian workspace: tool
gomencarigo.workmulai dari direktori aktif naik ke atas; workspace aktif berlaku untuk semua perintah di dalam pohonnya. - Resolusi lewat
use: importcontoh.com/formatterterjawab oleh module lokal./mod-a—go.modmilikmod-btidak perlurequiremaupunreplace. - Tanpa publikasi: perubahan apa pun di
mod-alangsung terasa dimod-bpada build berikutnya — siklus edit-build kembali secepat proyek tunggal.
Perintah dan Berkas Pendukung #
| Perintah | Fungsi |
|---|---|
go work init ./a ./b | Membuat go.work berisi module yang disebut |
go work use ./c | Menambah (atau menghapus) module dari workspace |
go work sync | Menyelaraskan go.mod module workspace dengan build list |
go work edit | Mengubah go.work dari skrip |
Berkas go.work.sum menyimpan checksum module yang dibutuhkan khusus oleh workspace — sepadan dengan go.sum pada module, muncul hanya bila workspace turut menarik dependency eksternal. Menonaktifkan workspace sesaat bisa dilakukan tanpa menghapus berkasnya:
GOWORK=off go run ./mod-bOutput yang Dihasilkan:
main.go:6:2: no required module provides package contoh.com/formatter; to add it:
go get contoh.com/formatterTanpa workspace, kita dilempar kembali ke masalah awal — bukti bahwa resolusi lokal tadi memang kerja go.work, bukan sulap pada go.mod.
Kapan Workspace Dipakai #
Workspace bersinar pada tiga skenario: monorepo berisi banyak aplikasi dan library yang saling memakai; migrasi besar satu module menjadi beberapa module secara bertahap; serta pengembangan library bersama aplikasi konsumen di repo berbeda. Sebaliknya, proyek satu module tidak butuh go.work — go.mod sudah memadai.
Workspace menyatukan module-module lokal, tetapi suatu saat karya kita harus meninggalkan meja kerja: diberi nomor versi, ditandai, lalu dikonsumsi orang lain. Aturan penomoran tersebut — semantic versioning, tag git, dan konsekuensi /v2 — kita bahas pada chapter Versioning Module
.
Referensi #
- Go Modules Reference: go.work files — format resmi berkas go.work.
- Wiki Go: Modules — catatan resmi komunitas seputar module.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
src/mod-a/formatter.go
Unduh berkaspackage formatter
import "strings"
// Kapital mengubah seluruh huruf menjadi kapital.
func Kapital(s string) string {
return strings.ToUpper(s)
}
src/mod-b/main.go
Unduh berkaspackage main
import (
"fmt"
"contoh.com/formatter"
)
func main() {
fmt.Println(formatter.Kapital("go workspace"))
}