2 poin oleh GN⁺ 2023-08-15 | 1 komentar | Bagikan ke WhatsApp
  • Go 1.21 berfokus pada penurunan beban upgrade dengan memperluas kompatibilitas berbasis GODEBUG, agar toolchain baru dapat mengimplementasikan perilaku versi Go lama se-stabil mungkin
  • Sejak Go 1 pada 2012, Go telah menjanjikan kompatibilitas source dan mengurangi kerusakan akibat penghapusan atau perubahan melalui pemeriksaan API publik serta pengujian internal berskala besar
  • Bahkan perbaikan yang diizinkan dalam dokumentasi seperti peningkatan presisi time.Now, perubahan implementasi sort, perubahan output compress/flate, perluasan input strconv.ParseInt, dan perubahan parsing net.ParseIP tetap dapat merusak program lama
  • Mulai Go 1.21, pengaturan GODEBUG untuk kompatibilitas dipertahankan minimal selama 2 tahun atau 4 rilis Go, dan dapat mempertahankan perilaku lama sebagai nilai default berdasarkan versi go di go.mod
  • Go 2 tidak akan hadir sebagai spesifikasi baru yang merusak program Go 1; meski menambahkan fitur baru, Go tetap memprioritaskan kompatibilitas agar upgrade toolchain tetap stabil

Prinsip dasar kompatibilitas Go 1

  • Pada Go 1 tahun 2012, melalui dokumen “Go 1 and the Future of Go Programs”, Go menetapkan tujuan bahwa program yang sesuai dengan spesifikasi Go 1 akan terus dapat dikompilasi dan dijalankan dengan benar tanpa perubahan selama masa hidup spesifikasi tersebut
  • Inti dari janji ini adalah kompatibilitas source
    • Saat memperbarui ke versi Go baru, kode harus dikompilasi ulang
    • API baru boleh ditambahkan, tetapi penambahan yang merusak kode lama harus dihindari
  • Tidak mungkin menjamin bahwa perubahan di masa depan tidak akan pernah merusak program apa pun
    • Jika program bergantung pada perilaku bug, program itu bisa rusak saat bug tersebut diperbaiki
    • Go berupaya menjaga upgrade tetap stabil sambil meminimalkan kerusakan semaksimal mungkin

Mencegah kerusakan kompatibilitas dengan pemeriksaan API publik

  • Dalam proses pengembangan Go, daftar API publik tiap package dikelola di file terpisah dari package sebenarnya
    • Sebagai contoh, go/api/go1.21.txt mencatat entri fungsi, metode, dan tipe dari bytes, cmp, context, dan lainnya
  • Pengujian standar memeriksa apakah API package yang sebenarnya sesuai dengan file-file tersebut
    • Jika API baru ditambahkan, file API juga harus diperbarui agar pengujian lulus
    • Jika API lama diubah atau dihapus, pengujian akan gagal
  • Bukan hanya penghapusan API, perubahan tipe juga bisa merusak kompatibilitas
    • os.Stdout adalah variabel global bertipe *os.File
    • Jika itu diubah menjadi interface dengan metode yang sama, kode seperti greet(f *os.File) yang memerlukan *os.File akan rusak
  • Pemeriksaan API berguna untuk menangkap perubahan atau penghapusan API, tetapi tidak dapat mencegah semua perubahan tidak kompatibel yang mungkin terjadi di Go

Kerusakan halus yang terungkap lewat pengujian

  • Versi pengembangan dari rilis Go baru terus diuji terhadap seluruh kode Go internal di Google
    • Jika pengujian lolos, commit tersebut dipasang ke toolchain Go produksi milik Google
    • Jika pengujian internal rusak, itu dianggap sebagai indikasi bahwa kode eksternal juga mungkin rusak, lalu dicari cara untuk mengurangi dampaknya
  • Dalam kebanyakan kasus, perubahan dibatalkan atau ditulis ulang agar tidak merusak program
  • Beberapa perubahan tetap penting dan dapat dipertahankan sebagai perubahan yang kompatibel menurut dokumentasi meski merusak program
    • Bahkan dalam kasus ini, cakupan dampak tetap diperkecil dan potensi masalah dicatat dalam catatan rilis

Dua contoh yang muncul di Go 1.1

  • Struct literal dan field baru

    • Pada Go 1, net.TCPAddr adalah struct dengan dua field, IP dan Port, dan composite literal tanpa nama field juga bisa dikompilasi
    • Saat field Zone ditambahkan ke net.TCPAddr di Go 1.1, kode lama tidak lagi bisa dikompilasi karena error “too few initializers in struct literal”
    • Cara penulisan yang kompatibel adalah menggunakan literal dengan label field
var myAddr = &net.TCPAddr{
    IP: net.IPv4(18, 26, 4, 9),
    Port: 80,
}
  • Jika Zone tidak ditentukan, field tersebut memakai zero value berupa string kosong
  • Persyaratan untuk menggunakan composite literal berlabel pada struct di standard library tercantum dalam dokumen kompatibilitas, dan go vet melaporkan literal tanpa label yang memerlukan label agar tetap kompatibel dengan versi mendatang
  • Presisi waktu

    • Setelah Go 1, time.Now diubah agar mengembalikan presisi nanodetik, bukan mikrodetik
    • Perubahan ini dapat merusak pengujian yang mengharapkan nilai time.Now tetap identik setelah bolak-balik melalui save dan load
    • Jika representasi penyimpanan hanya mempertahankan presisi mikrodetik, pengujian bisa berhasil di Go 1 tetapi gagal di Go 1.1
    • Untuk membantu memperbaiki pengujian seperti ini, Go menambahkan metode Round dan Truncate, lalu merangkum potensi masalah dan metode baru tersebut dalam catatan rilis
    • Karena presisi yang lebih tinggi adalah perilaku yang lebih baik dan masih berada dalam cakupan fungsi yang terdokumentasi, perubahan ini tetap dirilis meski merusak sebagian program

Tiga jenis perubahan yang dapat merusak kompatibilitas

  • Perubahan output

    • Perubahan output terjadi saat fungsi menghasilkan output berbeda dari sebelumnya, tetapi output baru itu tetap sama benarnya atau bahkan lebih benar daripada output lama
    • Penambahan presisi nanodetik pada time.Now adalah contoh utamanya
    • Di Go 1.6, implementasi sort diubah agar sekitar 10% lebih cepat, sehingga urutan elemen yang dianggap bernilai sama ikut berubah
    • Output Go 1.5: [red blue green white black yellow orange indigo violet]
    • Output Go 1.6: [red blue white green black orange yellow indigo violet]
    • Pengurutan tetap dianggap benar meski mengembalikan urutan apa pun untuk elemen yang setara, tetapi program yang mengharapkan urutan tertentu bisa rusak
    • Di Go 1.8, compress/flate ditingkatkan agar menghasilkan output yang lebih kecil dengan overhead CPU dan memori yang serupa
    • Akibatnya, build arsip reproducible internal di Google tidak lagi dapat mereproduksi arsip lama secara persis
    • Proyek tersebut akhirnya mem-fork compress/flate dan compress/gzip untuk mempertahankan algoritme lama
    • Untuk mengantisipasi perubahan output, sebaiknya program dan pengujian ditulis agar menerima semua output yang valid
    • Jika benar-benar membutuhkan output yang reproducible secara persis, kode bisa di-fork, tetapi konsekuensinya adalah terlepas juga dari perbaikan bug
  • Perubahan input

    • Perubahan input terjadi saat fungsi mengubah input yang diterima atau cara memprosesnya
    • Go 1.13 menambahkan sintaks underscore untuk keterbacaan angka, dan strconv.ParseInt juga diubah agar menerima sintaks baru ini
    • Kode milik pengguna eksternal yang memakai angka dipisahkan underscore sebagai format data terpisah pun rusak
    • Kode itu lebih dulu mencoba ParseInt, lalu hanya menangani underscore jika parsing gagal, tetapi kini ParseInt tidak lagi gagal
    • net.ParseIP awalnya menerima alamat IP desimal dengan nol di depan mengikuti contoh dalam RFC IP awal
    • Go membaca 18.032.4.011 sebagai 18.32.4.11
    • Library C keluarga BSD menafsirkan nol di depan sebagai awalan oktal, sehingga string yang sama dibaca sebagai 18.26.4.9
    • Di Go 1.17, net.ParseIP diubah agar menolak nol di depan sama sekali
    • Pilihan ini dibuat agar saat Go dan C sama-sama berhasil mem-parse alamat IP, keduanya memiliki makna yang sama
    • Kubernetes khawatir konfigurasi tersimpan lama mungkin tidak bisa di-parse di Go 1.17, dan mulai memakai fork dari net.ParseIP lama
    • Untuk input pengguna, pendekatan yang baik adalah memvalidasi dulu sintaks yang ingin diterima sebelum mem-parse nilainya, tetapi dalam beberapa kasus kode mungkin tetap perlu di-fork
  • Perubahan protokol

    • Perubahan protokol terjadi saat perubahan package muncul dalam bentuk yang terlihat pada protokol komunikasi dengan dunia luar
    • Go 1.6 menambahkan dukungan HTTP/2 otomatis
    • Klien Go 1.5 hanya memakai HTTP/1.1, sehingga bisa berfungsi normal di lingkungan perangkat perantara jaringan tertentu
    • Setelah upgrade ke Go 1.6, HTTP/2 akan digunakan, dan jika HTTP/2 tidak berjalan di lingkungan tersebut, program bisa rusak
    • Go ingin mendukung protokol modern secara default, tetapi pengaktifan HTTP/2 dapat merusak program meski tidak ada kesalahan pada program maupun Go itu sendiri
    • Go 1.6 merangkum perubahan ini dalam catatan rilis dan menyediakan cara untuk menonaktifkan HTTP/2
    • Mengatur field TLSNextProto secara eksplisit
    • Menetapkan GODEBUG=http2client=0, GODEBUG=http2server=0, atau keduanya
    • Dukungan sertifikat HTTPS berbasis SHA1 juga merupakan contoh perubahan protokol yang lebih halus
    • Otoritas sertifikat berhenti menerbitkan sertifikat SHA1 pada 2015, dan browser utama berhenti menerimanya pada 2017
    • Go 1.18 menonaktifkan dukungan sertifikat SHA1 secara default dan menyediakan bypass lewat GODEBUG
    • Karena beberapa instalasi Kubernetes masih memakai sertifikat SHA1 privat, Go memutuskan untuk mempertahankan pengaturan bypass itu lebih lama dari rencana awal

Dukungan GODEBUG yang diperluas di Go 1.21

  • Go 1.21 memperluas dan memformalkan penggunaan GODEBUG untuk lebih mengurangi masalah kompatibilitas yang halus
  • Untuk perubahan yang diizinkan oleh aturan kompatibilitas Go 1 tetapi tetap dapat merusak program lama, ditetapkan pengaturan GODEBUG agar tiap program dapat menolak perilaku baru tersebut
    • Mungkin ada kasus sangat langka ketika penambahan pengaturan seperti ini tidak memungkinkan
  • Pengaturan GODEBUG untuk kompatibilitas dipertahankan minimal selama 2 tahun, yaitu 4 rilis Go
    • Pengaturan seperti http2client dan http2server dapat dipertahankan jauh lebih lama, bahkan tanpa batas dalam beberapa kasus
  • Jika memungkinkan, tiap pengaturan GODEBUG dihubungkan dengan counter runtime/metrics
    • Nama counter memakai format /godebug/non-default-behavior/<name>:events
    • Sebagai contoh, jika GODEBUG=http2client=0 diatur, maka /godebug/non-default-behavior/http2client:events menghitung jumlah HTTP transport yang dikonfigurasi tanpa HTTP/2
  • Nilai default GODEBUG pada program disesuaikan dengan versi Go yang tertulis di go.mod package utama
    • Jika go.mod berisi go 1.20 dan Anda memperbarui ke toolchain Go 1.21, maka perilaku yang dikendalikan GODEBUG dan berubah di Go 1.21 akan tetap memakai perilaku Go 1.20 sampai go.mod diubah menjadi go 1.21
  • Setiap pengaturan GODEBUG dapat diubah lewat baris //go:debug di package main
  • Semua pengaturan GODEBUG dirangkum dalam daftar pusat

Kasus panic(nil)

  • Di Go 1.21, panic(nil) kini memicu runtime panic yang bukan nil
  • Perubahan ini membuat hasil recover dapat memberi tahu secara andal apakah goroutine saat ini sedang panic
  • Perilaku baru ini dikendalikan oleh pengaturan GODEBUG dan bergantung pada baris go di go.mod package utama
    • Jika go 1.20 atau lebih rendah, panic(nil) tetap diizinkan
    • Jika go 1.21 atau lebih tinggi, panic(nil) berubah menjadi panic dengan runtime.PanicNilError
  • Nilai default berbasis versi ini dapat ditimpa secara eksplisit dengan menambahkan baris berikut ke package main
//go:debug panicnil=1
  • Kombinasi ini memungkinkan upgrade ke toolchain baru sambil mempertahankan perilaku toolchain lama, mengendalikan hanya pengaturan yang diperlukan secara rinci, dan memantau di produksi apakah perilaku non-default sedang digunakan
  • Rincian lebih lanjut dirangkum dalam “Go, Backwards Compatibility, and GODEBUG

Go 2 tidak merusak Go 1

  • Dokumen “Go 1 and the Future of Go Programs” memang memuat catatan bahwa spesifikasi Go 2 mungkin suatu hari akan muncul
  • Go 2 dalam arti tidak lagi bisa mengompilasi program Go 1 tidak akan hadir
  • Go 2 dalam arti revisi besar terhadap Go 1 yang dimulai pada 2017 sebenarnya sudah terjadi
  • Go menilai kompatibilitas jauh lebih berharga daripada memutus hubungan dengan masa lalu, dan memilih arah yang semakin memperkuat kompatibilitas
  • Ke depan, pekerjaan baru yang menarik akan terus berlanjut, tetapi dilakukan dengan cara yang hati-hati dan kompatibel agar upgrade antar-toolchain tetap sestabil mungkin

1 komentar

 
GN⁺ 2023-08-15
Opini Hacker News
  • Pertanyaan penting soal kompatibilitas bukanlah “apakah akan melakukannya”, melainkan “bagaimana melakukannya”. Sebenarnya ini bukan sekadar kompatibilitas ke belakang, melainkan lebih dekat ke keinginan agar mulai sekarang kode saya terus berjalan begitu saja
    Go 1.21 menyediakan dua hal inti yang sulit ditemukan sekaligus di ekosistem bahasa lain: setiap perubahan punya pengaturan GODEBUG, bisa dikembalikan per perubahan, dan ada juga metrik untuk mendeteksi apakah implementasi lama digunakan. Selain itu ada versi toolchain per modul, dan toolchain Go yang lebih lama maupun lebih baru dapat otomatis diambil dengan aman seperti modul
    Sebagai bonus, jika menentukan versi tertentu seperti go 1.21.2, maka bahkan saat dijalankan di Go yang lebih baru, konfigurasi opt-out terkait akan otomatis diterapkan sampai Anda secara eksplisit meminta perilaku baru. Ini cara yang sederhana dan elegan yang dapat dideklarasikan di mana saja—kode, go.mod, atau variabel lingkungan—sehingga mencakup hampir semua kasus penggunaan kompatibilitas, dari pengembang sampai pihak yang men-deploy

    • Perl juga mirip: jika menulis use v5.24 di awal berkas, ia bisa dibuat berperilaku seperti Perl 5.24, dan ini berlaku per berkas, bukan per modul
    • Maaf, tetapi jika timnya cukup banyak dan kodenya lebih dari 1 juta–10 juta baris, pendekatan ini terdengar seperti mimpi buruk
      Sekadar apakah mendukung versi baru atau tidak saja sudah menimbulkan masalah yang luar biasa rumit, lalu muncul jurang dalam di mana “kami mengira mendukung versi baru dan versi baru juga mengira mendukung kami, tetapi keduanya saling melewatkan sesuatu”
    • Fitur seperti ini jelas ada juga di bahasa arus utama lain. Haskell bahkan melangkah lebih jauh dengan memungkinkan fitur bahasa dinyalakan dan dimatikan pada masing-masing berkas
    • Mengatakan “fitur inti yang tidak ada di ekosistem bahasa lain” lalu mencantumkan fitur yang umum di bahasa lain membuatnya terdengar seperti pengguna Go yang paling kurang antusias
  • Saya sangat menyukai arah seperti ini. Tidak ada yang sebaik bisa masuk ke codebase Go dan berharap cukup menaikkan versi Go saja semuanya akan tetap berjalan baik
    Namun saya khawatir sistem tipenya sulit ditingkatkan secara besar tanpa perubahan yang memecahkan kompatibilitas seperti “ini kode yang salah, jadi sekarang tidak lagi bisa dikompilasi”. Saya tidak tahu apakah tim Go tertarik pada hal seperti ini, tetapi ada banyak buah yang tergantung rendah yang bisa sangat meningkatkan ketangguhan saat kompilasi tanpa menambahkan fitur bahasa
    Misalnya pelaporan nil yang tidak diperiksa, pemeriksaan akses array, inferensi tipe untuk literal struct bertingkat, dan pemeriksaan menyeluruh untuk enum. Khususnya saat menulis panggilan gRPC bertingkat, yang dibutuhkan hanya satu tingkat inferensi tipe, dan karena tipe sudah ada di signature fungsi yang dipanggil, ini terasa sangat menyakitkan di Go

    • Untuk mengulang hal yang sama dari luar komunitas Go: enum dengan parameter ala Rust atau Swift terasa seperti anugerah dari langit. Begitu banyak program menjadi jauh lebih mudah digunakan
      Jika sistem tipe Go diperbaiki, saya berharap tipe data aljabar yang sederhana dan indah seperti ini ditambahkan. Itu akan sangat cocok untuk Go, jadi semoga Go menghadiahkannya untuk dirinya sendiri
  • Sepenuhnya setuju. Alasan rilis Go dinantikan adalah karena sering kali hal-hal berguna ditambahkan tanpa merusak apa pun
    Tidak ada bagian bahasa yang tampak begitu rusak sampai tidak bisa diperbaiki dengan perubahan yang kompatibel ke belakang. Bahkan beberapa jebakan seperti assignment variabel loop umumnya punya proposal yang tetap menjaga kompatibilitas

    • C# juga sepenuhnya menjaga kompatibilitas ke belakang, tetapi di kalangan pengembang .NET saya melihat suasana yang benar-benar berlawanan. Mereka berkata “bahasanya menjadi membengkak”, “jadi sulit dipelajari”
      Secara pribadi saya bersimpati pada cara pandang yang menantikan rilis Go, tetapi perbedaan sikap antara kedua ekosistem itu menarik
    • Menambahkan dua sen saya: saat upgrade Go, saya cukup sering mengalami kerusakan yang lumayan besar. Pada upgrade Rust atau gcc, masalahnya jauh lebih sedikit, dan pembaruan compiler C serta Rust benar-benar terasa seperti kompatibel ke belakang
      Dulu saya pernah merangkum sebagian kerusakan yang saya alami: https://news.ycombinator.com/item?id=29763324
      Rust atau gcc memberi fitur bahasa saat compiler dinaikkan, tetapi sebagian besar library yang kompleks tetap terpisah dan bisa dinaikkan secara terpisah. Misalnya HTTP di Rust adalah hyper, dan di C adalah libcurl
      Sebaliknya, saat menaikkan compiler Go, Anda tidak hanya ikut mendapatkan generics, embed, dan fitur toolchain, tetapi juga perubahan pada tls, library keamanan, serta klien/server HTTP. Gumpalan besar standard library seperti http, tls, dan crypto seharusnya jauh lebih baik jika berupa library terpisah. Dengan begitu compiler bisa dinaikkan tanpa rasa takut, sedangkan library bisa dinaikkan sesuai kecepatan saya sendiri
    • Secara umum saya setuju, tetapi masa depan tidak bisa diketahui. Edisi Rust 2018 memperkenalkan kata kunci async, dan karena pada edisi 2015 orang bisa membuat variabel atau fungsi bernama async, itu adalah perubahan yang memecahkan kompatibilitas
      Kompatibilitas ke belakang memang bagus, tetapi sulit merasa yakin apakah masa depan di mana Go tidak bisa melakukan inovasi X karena harus menjaga kompatibilitas adalah masa depan yang baik
    • Akan menyenangkan jika ada sum type dan cara yang lebih baik untuk mengurangi verbosity penanganan error
  • Saya sangat mendukung sikap bahwa Go 2 di masa depan sama sekali tidak akan merusak kompatibilitas Go 1. Kalau bahasa memang harus diubah sebesar itu, menurut saya lebih baik di-fork saja dan diganti namanya
    Namun saya penasaran mengapa tidak melangkah lebih jauh dan mengatakan “Go 2 tidak akan ada” untuk menghilangkan ambiguitas. Jika Go 2 secara teoretis menjalankan semua program Go 1, dalam hal apa ia berbeda dari rilis Go 1.xx? Tulisan itu mengatakan “tidak akan ada Go 2 yang merusak program Go 1”, tetapi tampaknya tidak mengatakan lebih dari itu

    • Lima tahun lalu sudah dikatakan bahwa “akan seperti itu”. Hanya saja ada prasyarat “jika”
      https://github.com/golang/proposal/blob/d661ed19a203000b7c54...
      Dijelaskan bahwa jika proses di atas berjalan sesuai rencana, dalam arti penting Go 2 tidak akan ada, dan transisi akan berlangsung perlahan melalui fitur bahasa dan pustaka baru. Pada suatu titik, secara pemasaran mungkin saja disebut “sekarang Go 2”, tetapi bisa juga dilewati begitu saja. Logikanya, kalau C 2.0 tidak ada, mengapa Go 2.0 diperlukan
      Bahasa populer seperti C, C++, dan Java pun pada dasarnya selalu berada di versi 1.N, dan menurut saya Go sebaiknya mengikuti itu. Go 2 yang sebenarnya, dalam arti bahasa baru atau pustaka inti baru yang tidak kompatibel, bukanlah pilihan yang baik bagi pengguna dan bisa merugikan
    • Java sudah melalui jalan ini. Ada Java 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, lalu kemudian berubah menjadi “toh kita tidak memutus kompatibilitas mundur, jadi daripada 1.x sebut saja Java 8, 9, 10…21”
      Pada akhirnya, menurut saya pendekatan itu masuk akal
    • Mungkin kita melebih-lebihkan skala perubahan yang diperlukan untuk merusak kompatibilitas source. Contoh yang ringan adalah menambahkan keyword
      Jika ada fitur bahasa baru yang jelas-jelas diinginkan komunitas, dan cara yang benar atau satu-satunya cara untuk memasukkannya adalah keyword baru, maka aturan bahwa kompatibilitas source tidak boleh pernah dirusak berarti fitur itu tidak akan pernah bisa ditambahkan. Saya setuju untuk perubahan besar yang mengubah semantik bahasa, tetapi perubahan yang tidak kompatibel ke belakang tidak selalu merupakan perubahan raksasa
    • Menurut saya edition di Rust adalah contoh tandingan yang bagus. Perbedaan antar-edition adalah breaking change, tetapi dalam praktiknya tidak terlalu besar
      Secara teori, gagasan bahwa kompatibilitas mundur tidak pernah berubah itu bagus, tetapi di dunia nyata ada juga breaking change yang bermakna. Tidak selalu terasa menguntungkan jika harus memikul selamanya fitur bahasa yang pada desain awalnya tidak mempertimbangkan X atau Y
    • Di bagian akhir tulisan sudah dikatakan demikian. Go 2 dalam arti memutus hubungan dengan masa lalu dan tidak lagi mengompilasi program lama tidak akan pernah terjadi, sedangkan Go 2 dalam arti revisi besar Go 1 yang mulai diarahkan pada 2017 sudah terjadi
  • Saya banyak memakai Go, dan arah seperti ini benar-benar menenangkan
    Kompatibilitas mungkin tidak terlalu menyenangkan bagi tim bahasa. Karena harus selalu menaruh satu kaki dengan kokoh di “masa lalu yang jauh”. Tetapi bagi orang yang harus memelihara sistem Go besar, ini benar-benar hadiah besar

    • Saya mengerjakan kompiler Go selama beberapa tahun, dan itu bukan masalah besar. Kami berpikir dengan hati-hati dan menolak banyak ide
      Jika tidak bisa dimasukkan dengan benar, berarti belum tepat, jadi kami mencoba lagi; kalau tetap tidak cocok, mungkin kami belum cukup memahami masalahnya, sehingga memang benar untuk membiarkannya matang lebih lama
      Saya sangat senang bekerja dengan orang-orang yang berpikir hati-hati dan berusaha agar ide yang tepatlah yang masuk. Saya berterima kasih karena Russ menjalankan peran BDFL, dan karena bisa bekerja dengan Ian, Rob, dan Rob; berkat itu saya menjadi engineer yang jauh lebih baik
  • Tulisan terkait: Forward Compatibility and Toolchain Management in Go 1.21 - https://news.ycombinator.com/item?id=37122932

  • Kalimat “Membosankan itu bagus. Membosankan itu stabil. Membosankan berarti Anda bisa fokus pada pekerjaan sendiri tanpa memikirkan apa yang berubah di Go” benar-benar terasa mengena
    Di pekerjaan utama saya menggunakan NodeJS dan ekosistem JS secara umum, dan memang sangat melelahkan. Ekosistemnya terfragmentasi dan semua orang punya caranya sendiri, sehingga sulit membuatnya stabil. Meski begitu saya masih menikmati pekerjaan ini, tetapi saya berharap ekosistem JS juga memiliki fondasi modern yang stabil yang bisa dipercaya dan diandalkan

    • Ekosistem JS, misalnya npm atau React, mungkin memang begitu. Namun perlu diakui juga bahwa JavaScript sebagai bahasa sudah memprioritaskan kompatibilitas mundur bahkan sebelum Go ada
    • Saya penasaran mengapa Go belum menjadi Java/.NET baru
      Banyak tool dan API ditulis dengan Go, dan fakta bahwa sistem target tidak membutuhkan runtime terpisah sering disebut sebagai keunggulan besar. Bahasanya juga tampak sederhana untuk dipelajari dan digunakan, dukungan VSC serta GoLand bagus, dan keluhan umum seperti error handling pun tidak terlihat seperti cacat fatal
      Saya penasaran apa lagi yang dibutuhkan Go agar menjadi arus utama pengembangan selama beberapa dekade ke depan, atau setidaknya mengambil bagian besar di pasar kerja. Di beberapa tempat, Go masih dianggap bahasa niche
    • JavaScript terkenal karena kompatibilitas mundurnya. Karena itulah ia menjadi keadaan kacau persis seperti yang kamu gambarkan
    • Sekarang menurut saya sebenarnya sudah ada fondasi yang stabil. Kode ES modules dan ES2020 didukung baik oleh Node maupun browser utama. Node juga punya test runner bawaan
      Masalahnya adalah membuat semua orang naik ke baseline ini. Kalau sudah sampai di sana, sepertinya akan jauh lebih baik
      Selain itu, ekosistem JS juga mencakup pekerjaan UI frontend, dan bidang penerapannya begitu luas sehingga kemunculan berbagai implementasi tidak bisa dihindari. Bahkan itu bisa dibilang baik
  • Memindahkan sebagian kode dari Python ke Golang sangat membantu dalam penskalaan. Saya sangat senang mendengar bahwa Go akan terus menjaga deklarasi intinya, yaitu kompatibilitas mundur

  • Berbicara soal parsing IP. Saya jadi penasaran, sebenarnya bagaimana inet_ntoa BSD yang asli ditulis?
    sscanf yang memakai atoi/atol dan %d/%u selalu mem-parse tepat sebagai bilangan bulat desimal, jadi untuk menghasilkan efek aneh seperti ini, mestinya harus memakai %i atau strtou berbasis 0

    • Tidak perlu menebak. Halaman manual inet_aton saya menyebutkan bahwa itu berasal dari 4.3BSD: https://github.com/dank101/4.3BSD-Reno/blob/master/lib/libc/...
      inet_addr pada 4.2BSD yang lebih awal juga memakai logika yang sama: https://github.com/dank101/4.2BSD/blob/master/lib/libc/inet/...
      inet_aton dan inet_addr mem-parse alamat dengan cara yang paling alami. Kalau memakai sesuatu seperti strtoul, atau apalagi sscanf, rasanya akan canggung. Keindahan pointer C adalah membuat pekerjaan parsing sederhana menjadi sangat mudah, dan mungkin malah terlalu mudah
    • Saya tertawa saat membaca bagian itu. Dulu saya pernah mencoba “merapikan” /etc/hosts dengan memberi padding 0 pada setiap oktet
      Akhirnya saya harus kembali dan menghapus angka 0 itu
  • Sebagai perancang bahasa, saya menghormati pilihan-pilihan yang diambil di sini, termasuk keputusan untuk tidak membuat Go 2 yang sebenarnya
    Saya juga berniat memakai teknik-teknik untuk menjamin kompatibilitas