Pada proyek Go Fiber, masalah DX tim sering bukan ada di framework-nya, tetapi di cara setiap developer menjalankan aplikasi. Satu orang memakai go run, yang lain air, yang lain lagi punya alias shell sendiri. Akibatnya, onboarding melambat, dokumentasi cepat usang, dan pipeline CI bisa berbeda perilaku dengan workflow lokal.
Solusi yang paling praktis adalah membuat satu antarmuka perintah yang konsisten untuk semua aktivitas utama: menjalankan app, hot reload, test, lint, format, generate, build, dan validasi environment. Di ekosistem Go, pilihan paling umum adalah Makefile, atau task runner seperti just dan Task. Artikel ini fokus pada rancangan workflow yang sederhana, mudah dipelihara, dan cocok untuk tim yang memakai Go Fiber.
Mengapa workflow perlu distandarkan?
Tanpa standardisasi, setiap developer biasanya membangun kebiasaannya sendiri. Itu terlihat sepele, tetapi dampaknya nyata:
- Perintah tidak seragam: ada yang menjalankan aplikasi dari
cmd/api, ada yang dari root project. - Tooling tidak sinkron: sebagian developer menjalankan
gofmt, yang lain memakai formatter editor, hasilnya bisa berbeda. - CI dan lokal berbeda: lint lolos di lokal, gagal di pipeline karena command atau flags tidak sama.
- Onboarding lebih mahal: developer baru harus membaca banyak dokumentasi hanya untuk tahu cara menjalankan proyek.
- Error diagnosis lebih sulit: ketika perintah dasar tidak standar, sulit memastikan bug berasal dari kode atau dari lingkungan eksekusi.
Target yang baik bukan membuat workflow paling canggih, tetapi membuat workflow yang bisa diprediksi. Jika semua orang menjalankan make test dan CI juga menjalankan perintah yang sama, tim punya satu sumber kebenaran.
Prinsip desain target Makefile untuk proyek Go Fiber
Sebelum menulis Makefile, tentukan beberapa prinsip agar file-nya tidak berubah menjadi skrip acak yang sulit dirawat.
1. Satu target untuk satu intent
Nama target sebaiknya merepresentasikan niat, bukan implementasi detail. Contoh yang baik:
rununtuk menjalankan aplikasidevuntuk mode pengembangan dengan hot reloadtestuntuk menjalankan unit testlintuntuk static analysisfmtuntuk formattingbuilduntuk produksi atau artefak lokal
Hindari nama seperti run-air-main-go atau execute-api-local karena terlalu spesifik terhadap implementasi saat ini.
2. Pisahkan target developer dan target komposit
Beberapa target sebaiknya menjalankan satu tugas spesifik, lalu dibuat target komposit untuk alur lengkap. Misalnya:
fmt,lint,testsebagai target granularchecksebagai gabungan darifmt,lint, dantest
Pola ini membuat developer bisa menjalankan langkah tertentu saat debugging, tetapi CI tetap punya entry point sederhana.
3. Hindari logika shell yang terlalu kompleks
Makefile cocok sebagai command orchestrator, bukan sebagai bahasa scripting utama. Jika logika sudah terlalu bercabang, pertimbangkan pindahkan ke script shell kecil di direktori seperti scripts/, lalu panggil dari Makefile.
4. Buat target yang gagal cepat
Workflow yang baik harus berhenti ketika validasi penting gagal, misalnya environment belum lengkap atau dependency tool belum tersedia. Ini membantu error terlihat lebih awal.
Struktur Makefile yang sederhana dan mudah dipelihara
Contoh berikut memakai asumsi struktur proyek Go Fiber yang umum, misalnya entry point ada di cmd/api/main.go. Anda bisa menyesuaikannya sesuai layout proyek.
APP_NAME := app
CMD_DIR := ./cmd/api
BIN_DIR := ./bin
BUILD_OUT := $(BIN_DIR)/$(APP_NAME)
GO_PACKAGES := ./...
.PHONY: help env-check deps run dev test test-race lint fmt vet generate build clean check ci
help:
@echo "Available targets:"
@echo " make env-check - validasi environment dasar"
@echo " make deps - download dependency Go"
@echo " make run - jalankan aplikasi"
@echo " make dev - jalankan aplikasi dengan hot reload (Air)"
@echo " make fmt - format kode"
@echo " make vet - jalankan go vet"
@echo " make lint - jalankan golangci-lint"
@echo " make test - jalankan unit test"
@echo " make test-race - jalankan test dengan race detector"
@echo " make generate - jalankan go generate"
@echo " make build - build binary produksi"
@echo " make clean - hapus artefak build"
@echo " make check - fmt + vet + lint + test"
@echo " make ci - target untuk pipeline CI"
env-check:
@command -v go >/dev/null || (echo "Error: Go tidak ditemukan" && exit 1)
@command -v golangci-lint >/dev/null || (echo "Error: golangci-lint tidak ditemukan" && exit 1)
@echo "Environment OK"
deps:
go mod download
run:
go run $(CMD_DIR)
dev:
@command -v air >/dev/null || (echo "Error: Air tidak ditemukan. Install terlebih dahulu." && exit 1)
air
fmt:
gofmt -w .
go fmt $(GO_PACKAGES)
vet:
go vet $(GO_PACKAGES)
lint:
golangci-lint run
test:
go test $(GO_PACKAGES)
test-race:
go test -race $(GO_PACKAGES)
generate:
go generate $(GO_PACKAGES)
build:
mkdir -p $(BIN_DIR)
CGO_ENABLED=0 go build -ldflags="-s -w" -o $(BUILD_OUT) $(CMD_DIR)
clean:
rm -rf $(BIN_DIR)
check: fmt vet lint test
ci: env-check deps generate check buildMakefile di atas sengaja tidak terlalu pintar. Itu justru kelebihannya. Developer bisa membaca dan memahami alurnya dalam beberapa menit.
Penjelasan target yang penting
env-check: memverifikasi tool dasar tersedia sebelum target lain dijalankan. Ini berguna untuk onboarding dan CI fail-fast.run: untuk menjalankan app tanpa hot reload. Cocok untuk debugging yang ingin perilaku lebih dekat ke eksekusi biasa.dev: mode pengembangan berbasis Air.fmt: menstandarkan format kode. Dalam beberapa tim, cukupgofmt; menambahkango fmtbisa membantu memastikan package formatting tetap konsisten.vet: analisis bawaan Go yang berguna untuk menangkap masalah umum.lint: pintu masuk utama untuk aturan kualitas tambahan lewatgolangci-lint.check: target komposit untuk validasi lokal sebelum commit.ci: target yang dipakai pipeline agar lokal dan CI menjalankan workflow yang sama.
Integrasi Air untuk hot reload Go Fiber
Pada proyek Go Fiber, mode pengembangan biasanya lebih nyaman dengan hot reload. Salah satu tool yang umum dipakai adalah Air. Daripada setiap developer mengingat command Air masing-masing, cukup standarkan lewat target make dev.
Selain itu, sebaiknya konfigurasi Air disimpan di repository agar perilakunya konsisten. Contoh file .air.toml yang sederhana:
root = "."
tmp_dir = "tmp"
[build]
cmd = "go build -o ./tmp/app ./cmd/api"
bin = "./tmp/app"
include_ext = ["go", "tpl", "tmpl", "html"]
exclude_dir = ["tmp", "vendor", "bin"]
delay = 500
stop_on_error = true
[log]
time = trueKenapa pendekatan ini bekerja?
- Developer tidak perlu tahu command build internal Air.
- Entry point aplikasi tetap satu, sehingga perubahan struktur direktori cukup diubah di satu tempat.
- Perilaku hot reload menjadi stabil lintas mesin developer.
Kesalahan yang sering terjadi adalah membiarkan setiap orang menulis konfigurasi Air-nya sendiri atau menyimpan path build yang berbeda. Hasilnya, bug bisa muncul hanya di sebagian mesin.
Integrasi golangci-lint, go test, dan generate
Lint yang konsisten
golangci-lint efektif jika konfigurasinya eksplisit dan target Makefile-nya stabil. Minimal, simpan file konfigurasi di repository, misalnya .golangci.yml. Tidak perlu terlalu agresif di awal; mulai dari aturan yang benar-benar ingin ditegakkan tim.
Tujuan utamanya bukan menambah sebanyak mungkin linter, tetapi memastikan hasil lint:
- konsisten di lokal dan CI,
- cukup cepat untuk dipakai rutin,
- tidak menghasilkan terlalu banyak noise.
Jika lint terlalu lambat atau terlalu cerewet, developer akan cenderung mengabaikannya.
Testing sebagai target default yang mudah diingat
make test harus menjadi kebiasaan dasar. Hindari command test yang terlalu kompleks kecuali memang dibutuhkan. Jika ingin validasi tambahan, buat target terpisah seperti test-race.
Pemisahan ini berguna karena race detector lebih berat, sehingga tidak selalu ideal dijalankan di setiap iterasi lokal. Namun untuk CI tertentu atau sebelum merge besar, target tersebut sangat berguna.
Generate harus eksplisit
Jika proyek memakai go generate untuk mock, codegen, atau artefak lain, jangan andalkan developer mengingat command-nya sendiri. Sediakan make generate dan panggil target itu di CI bila generated files memang bagian dari workflow resmi.
Jika generated file harus committed ke repository, pastikan CI memverifikasi bahwa hasil
make generatetidak mengubah working tree. Ini membantu mencegah commit yang lupa menyertakan hasil generate.
Build produksi yang sederhana dan dapat diprediksi
Untuk build, fokus artikel ini bukan deployment, tetapi tetap penting punya target build yang seragam. Tujuannya adalah menghasilkan binary dengan cara yang sama di semua lingkungan.
build:
mkdir -p $(BIN_DIR)
CGO_ENABLED=0 go build -ldflags="-s -w" -o $(BUILD_OUT) $(CMD_DIR)Beberapa catatan:
CGO_ENABLED=0sering dipakai untuk menghasilkan binary yang lebih mudah dipindahkan, tetapi pastikan sesuai kebutuhan dependency proyek Anda.-ldflags="-s -w"umum dipakai untuk mengurangi metadata debug pada binary. Ini berguna, tetapi saat debugging produksi tertentu Anda mungkin ingin build tanpa flag tersebut.- Simpan output ke direktori seperti
bin/agar artefak build tidak bercampur dengan source code.
Jika tim membutuhkan build yang berbeda untuk debug dan release, buat target terpisah seperti build dan build-debug, bukan membuat satu target dengan logika shell yang rumit.
Pengecekan environment yang berguna, bukan berlebihan
Salah satu sumber friksi terbesar pada onboarding adalah environment yang setengah siap. Makefile bisa membantu, tetapi jangan mencoba memverifikasi terlalu banyak hal sampai sulit dipelihara.
Yang biasanya layak dicek:
- binary inti seperti
go,air, dangolangci-lint, - file environment yang wajib ada, misalnya
.envjika proyek memang bergantung pada file itu di lokal, - variabel minimum yang benar-benar wajib untuk menjalankan app.
Contoh sederhana validasi file environment:
env-file-check:
@test -f .env || (echo "Error: file .env tidak ditemukan" && exit 1)Namun hati-hati: jangan memaksa Makefile mengelola semua secret atau provisioning lokal. Makefile cukup menjadi pengarah, bukan pengganti sistem konfigurasi.
Tips naming target dan error handling
Gunakan nama yang pendek dan jelas
Nama target yang baik biasanya berupa kata kerja atau intent singkat:
rundevtestlintfmtbuildcleancheckci
Ini memudahkan hafalan dan membuat dokumentasi lebih ringkas.
Pisahkan target lokal dan CI jika perlu, tapi tetap dekat
Tidak semua hal yang cocok di CI cocok dijalankan terus-menerus di lokal. Misalnya test-race atau validasi tambahan bisa dibuat khusus. Namun tetap usahakan CI memanggil target yang juga tersedia di lokal, bukan shell script yang sama sekali berbeda.
Tampilkan pesan error yang membantu
Pesan seperti command not found sering terlalu mentah bagi anggota tim baru. Lebih baik beri pesan yang jelas tentang tool apa yang hilang dan tindakan umum yang perlu dilakukan.
Contoh:
@command -v air >/dev/null || (echo "Error: Air tidak ditemukan. Install terlebih dahulu." && exit 1)Ini jauh lebih informatif daripada membiarkan shell gagal tanpa konteks.
Gunakan .PHONY untuk target non-file
Ini penting agar Make tidak mengira target seperti test atau build adalah nama file. Jika lupa, perilaku bisa membingungkan saat ada file dengan nama yang sama.
Memakai Makefile di CI agar lokal dan pipeline konsisten
Kesalahan umum adalah mendefinisikan workflow lokal lewat Makefile, tetapi menulis command yang berbeda lagi di CI. Akibatnya, tim merasa sudah menjalankan pemeriksaan yang sama, padahal sebenarnya tidak.
Pendekatan yang lebih aman:
- Definisikan target inti di Makefile.
- Pakai target yang sama di pipeline CI.
- Biarkan CI hanya bertanggung jawab pada setup environment dan pemanggilan target.
Contoh yang ideal di CI bukan menulis semua command satu per satu, melainkan cukup:
make ciAtau jika ingin tahap terpisah demi visibilitas log:
make env-check
make generate
make lint
make test
make buildKeuntungan pendekatan ini:
- lokal dan CI memakai kontrak perintah yang sama,
- saat workflow berubah, cukup ubah Makefile,
- dokumentasi tim lebih sederhana.
Trade-off-nya, Makefile menjadi bagian penting dari workflow engineering, sehingga perubahan di sana harus direview dengan hati-hati. Tetapi ini tetap lebih mudah dikelola daripada membiarkan command tersebar di wiki, README, shell alias, dan file pipeline yang berbeda-beda.
Makefile vs just vs Task: kapan memilih yang mana?
Makefile
Kelebihan:
- Hampir selalu tersedia di lingkungan Unix-like dan umum dipahami engineer.
- Cocok untuk workflow sederhana sampai menengah.
- Mudah diintegrasikan ke CI.
Kekurangan:
- Sintaksnya tidak selalu ramah, terutama terkait tab, escaping, dan perilaku shell.
- Kurang nyaman untuk logika scripting yang kompleks.
- Di sebagian lingkungan Windows, pengalaman bisa kurang mulus jika tool pendukung tidak tersedia.
Pilih Makefile jika: tim Anda ingin solusi standar, ringan, dan fokus pada konsistensi command.
just
Kelebihan:
- Sintaks lebih mudah dibaca untuk command recipe.
- Lebih enak dipakai sebagai command runner dibanding Makefile untuk banyak kasus non-build dependency.
- Biasanya lebih jelas untuk passing argument dan deklarasi recipe.
Kekurangan:
- Tidak selalu tersedia secara default di mesin developer atau runner CI.
- Menambah satu dependency tooling lagi untuk tim.
Pilih just jika: tim Anda merasa Makefile terlalu kaku, dan siap menstandarkan instalasi tool tambahan.
Task
Kelebihan:
- Struktur YAML mudah dibaca banyak orang.
- Nyaman untuk task orchestration dan workflow multi-step.
- Lebih fleksibel untuk kebutuhan skrip tim yang berkembang.
Kekurangan:
- Sama seperti just, ini menambah dependency tooling.
- Untuk workflow yang sangat sederhana, bisa terasa berlebihan.
Pilih Task jika: kebutuhan otomasi tim mulai lebih kompleks, tetapi Anda tetap ingin task runner yang eksplisit dan mudah dibaca.
Untuk banyak proyek Go Fiber skala kecil sampai menengah, Makefile biasanya sudah cukup. Jika nanti workflow berkembang dan sintaks Makefile mulai menghambat, migrasi ke just atau Task bisa dilakukan bertahap tanpa mengubah intent target yang sudah dikenal tim.
Kesalahan umum yang perlu dihindari
- Terlalu banyak target sejak awal: mulai dari target inti dulu. Target yang terlalu banyak justru membuat orang bingung.
- Mencampur concern build dan deploy: artikel ini fokus pada workflow developer. Jangan masukkan deployment detail ke Makefile utama jika itu membuat DX jadi berat.
- Command lokal dan CI berbeda: ini sumber inkonsistensi paling umum.
- Tidak menyimpan konfigurasi tool di repository: misalnya config Air atau lint hanya ada di mesin salah satu developer.
- Membuat target yang diam-diam mengubah banyak hal: target seperti
checksebaiknya bersifat validasi, bukan melakukan operasi destruktif tak terduga.
Rekomendasi workflow minimal untuk tim Go Fiber
Jika Anda ingin memulai dari baseline yang masuk akal, gunakan target berikut sebagai standar tim:
make devuntuk pengembangan dengan hot reloadmake rununtuk menjalankan aplikasi tanpa hot reloadmake fmtuntuk formattingmake lintuntuk static analysismake testuntuk unit testmake generatejika proyek memakai code generationmake builduntuk build binarymake checkuntuk validasi sebelum commitmake ciuntuk dipakai pipeline
Dengan daftar ini, dokumentasi onboarding bisa sesederhana: install dependency dasar, lalu jalankan make dev. Itu sudah cukup mengurangi perbedaan workflow antar developer secara signifikan.
Penutup
Go Fiber: Makefile dan Task Runner untuk DX Tim yang Konsisten pada dasarnya bukan soal memilih tool paling populer, melainkan soal membuat satu kontrak kerja yang jelas untuk seluruh tim. Ketika semua aktivitas utama dibungkus dalam target yang rapi, developer baru lebih cepat produktif, debugging lebih mudah, dan CI tidak menjadi dunia yang berbeda dari lingkungan lokal.
Jika kebutuhan Anda masih sederhana, mulai dengan Makefile yang kecil, eksplisit, dan mudah dibaca. Pastikan target seperti dev, test, lint, generate, dan build benar-benar dipakai oleh developer dan pipeline. Konsistensi kecil seperti ini biasanya memberi dampak lebih besar daripada otomasi yang terlalu kompleks tetapi jarang dipakai.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!