Penamaan, komentar & API yang enak dipakai
Go punya sedikit sekali aturan gaya, tapi yang sedikit itu dipatuhi hampir universal. Mengikutinya membuat kodemu terbaca oleh orang yang belum pernah melihat repomu.
Intisari
- Nama pendek untuk umur pendek:
i,r,buf. Nama panjang untuk yang diekspor dan berumur panjang. - Nama diperpendek oleh konteks: di paket
produk, tulisproduk.Cari, bukanproduk.CariProduk. - Singkatan tetap satu kesatuan huruf:
userID,HTTPServer,URLPathโ bukanuserId. - Komentar dokumentasi diawali nama yang dijelaskannya dan berupa kalimat lengkap.
- Interface satu method biasanya dinamai kata kerja +
-er:Reader,Formatter,Penyimpan.
Panjang nama sebanding dengan jaraknya
// Pendek โ hidupnya tiga baris, konteksnya jelas
for i, p := range daftar {
if p.Harga > batas {
hasil = append(hasil, p)
}
}
// Panjang โ diekspor, dibaca orang yang tidak melihat isinya
func HitungOngkirBerdasarkanZona(ctx context.Context, tujuan Alamat) (Rupiah, error)
Ini kebalikan dari kebiasaan di beberapa bahasa lain, di mana nama panjang dianggap selalu lebih baik. Di
Go, i di dalam loop tiga baris lebih jelas daripada indeksProdukSaatIni,
karena pembaca bisa melihat seluruh hidupnya dalam satu pandangan.
| Konteks | Nama yang lazim |
|---|---|
| Penerima method | Satu-dua huruf dari nama tipe: func (p *Pesanan) |
| Handler HTTP | w http.ResponseWriter, r *http.Request โ selalu |
| Context | ctx, selalu parameter pertama |
| Error | err |
| Loop | i, k, v |
Konteks paket sudah jadi awalan
| โ | โ |
|---|---|
produk.CariProduk() | produk.Cari() |
auth.AuthMiddleware | auth.Middleware |
config.ConfigLoad() | config.Muat() |
http.HTTPClient | http.Client |
Yang dibaca di tempat pemakaian adalah paket.Nama secara utuh, jadi rancanglah kalimat itu.
bytes.Buffer, time.Now, slices.Sort โ semuanya terbaca sebagai frasa.
Singkatan tidak pernah dipecah
userID ID URL HTTPServer apiKey XMLData
// bukan:
userId Id Url HttpServer ApiKey XmlData
Aturannya: singkatan ditulis konsisten seluruhnya besar atau seluruhnya kecil, tergantung apakah nama itu
diekspor. xmlData (privat) dan XMLData (publik), tidak pernah XmlData.
Linter revive dan staticcheck menegakkannya (Fase 8).
Komentar dokumentasi
// Package produk berisi model dan aturan bisnis katalog produk.
//
// Paket ini tidak tahu apa pun tentang HTTP maupun database; penyimpanan
// diakses lewat interface yang dideklarasikan di sini.
package produk
// ErrTidakDitemukan dikembalikan saat produk yang diminta tidak ada.
// Lapisan HTTP memetakannya jadi 404.
var ErrTidakDitemukan = errors.New("produk tidak ditemukan")
// Cari mengembalikan produk yang namanya mengandung kata, diurutkan dari
// yang paling murah. Ia mengembalikan slice kosong (bukan error) kalau tidak
// ada yang cocok.
//
// Kata dibandingkan tanpa memperhatikan huruf besar-kecil.
func Cari(ctx context.Context, kata string) ([]Produk, error) {
| Aturan | Alasan |
|---|---|
| Diawali nama yang dijelaskan | go doc dan pkg.go.dev memotong per kalimat pertama |
| Kalimat lengkap, diakhiri titik | Ia muncul sebagai deskripsi di daftar, di luar konteks kodenya |
| Jelaskan apa dan kenapa, bukan bagaimana | "Bagaimana" ada di kodenya, dan berubah lebih cepat |
| Sebutkan perilaku tepi | Nil? Slice kosong? Aman dipanggil dari banyak goroutine? Itu yang dicari pembaca |
go doc ./internal/produk # baca dokumentasi paketmu sendiri
go doc ./internal/produk Cari # satu simbol
go doc -http=:6060 # jelajahi seluruh modul di browser
Komentar yang tidak menambah apa-apa lebih buruk daripada tidak ada komentar, karena ia ikut
membusuk. // Cari mencari hanya menambah baris yang harus dijaga tetap benar. Yang layak
ditulis adalah keputusan: kenapa batasnya 100, kenapa urutannya begitu, kenapa fungsi ini tidak
mengembalikan error.
Nama interface dan konstruktor
// Satu method: kata kerja + -er
type Reader interface { Read(...) }
type Penyimpan interface { Simpan(...) }
// Beberapa method: nama peran, bukan -er yang dipaksakan
type PenyimpanProduk interface {
Ambil(ctx context.Context, id int64) (Produk, error)
Simpan(ctx context.Context, p Produk) error
}
// Konstruktor
func New(...) *Layanan // kalau paketnya cuma punya satu tipe utama
func NewLayanan(...) *Layanan // kalau ada beberapa
Yang membuat API enak dipakai
ctx context.Contextselalu parameter pertama, dan tidak pernah disimpan di dalam struct.errorselalu nilai kembalian terakhir.- Nilai nol yang berguna โ kalau tipemu perlu konstruktor, itu keputusan sadar.
- Terima interface, kembalikan struct.
- Jangan kembalikan nilai kembalian tak bernama yang lebih dari dua โ tiga nilai anonim adalah tanda struct hasil dibutuhkan.
- Fungsi yang bisa gagal harus mengembalikan error, bukan mencatat log lalu diam.
Latihan: ambil satu paket yang sudah kamu tulis, jalankan go doc padanya, dan baca
hasilnya seolah kamu belum pernah melihat kode itu. Perbaiki setiap nama yang terbaca berulang
(produk.ProdukX), lalu tulis komentar paket satu paragraf yang menjelaskan apa yang paket ini
tidak tahu.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.