1 poin oleh GN⁺ 2024-02-08 | 1 komentar | Bagikan ke WhatsApp
  • Variabel loop for kini dibuat baru pada setiap iterasi untuk menghindari bug berbagi yang tidak disengaja, dan range pada bilangan bulat juga kini dimungkinkan
  • Kompatibilitas tetap mengikuti janji kompatibilitas Go 1, dan hampir semua program Go diharapkan tetap dapat dikompilasi dan dijalankan seperti sebelumnya
  • Di workspace, direktori vendor yang dibuat dengan go work vendor dapat digunakan; jika ada vendor di workspace, -mod=vendor menjadi nilai default
  • Dukungan go get di luar modul pada mode legacy GOPATH dengan GO111MODULE=off dihentikan; perintah build lain seperti go build dan go test tetap berfungsi untuk program legacy GOPATH
  • Runtime kini menempatkan metadata GC berbasis tipe di dekat objek heap, meningkatkan performa CPU program Go sebesar 1–3% dan mengurangi overhead memori banyak program sekitar 1%
  • Penyelarasan alamat sebagian objek dapat berubah dari sebelumnya 16 byte atau lebih menjadi penyelarasan 8 byte; kode assembly yang mengasumsikan penyelarasan lebih tinggi perlu diperbaiki, dan GOEXPERIMENT=noallocheaders dapat digunakan sebagai solusi sementara
  • Build PGO dapat melakukan devirtualization pada lebih banyak pemanggilan, dan saat PGO diaktifkan pada sekumpulan program Go representatif, performa runtime meningkat 2–14%
  • Paket v2 pertama di standard library, math/rand/v2, ditambahkan; menyediakan Read yang tidak diwariskan, generator global yang selalu diberi seed acak, sumber ChaCha8 dan PCG, serta fungsi generik N
  • Pola routing net/http.ServeMux mendukung metode dan wildcard; ada sedikit perubahan yang memutus kompatibilitas mundur pada pola yang berisi {} dan pemrosesan path yang di-escape, dan perilaku lama dapat dipulihkan dengan GODEBUG=httpmuxgo121=1
  • Versi minimum default server crypto/tls berubah menjadi TLS 1.2 jika tidak ditentukan, dan cipher suite tanpa ECDHE tidak lagi disediakan secara default pada handshake sebelum TLS 1.3
  • Execution tracer dirombak besar-besaran: kini menggunakan jam OS di sebagian besar platform, menyediakan trace tersegmentasi yang dapat diproses secara streaming, durasi syscall penuh, serta informasi OS thread tempat goroutine berjalan
  • UI web alat trace diperbarui sebagai bagian dari dukungan tracer baru, dan pada trace dari program yang dibangun dengan Go 1.22 atau lebih baru mendukung tampilan berorientasi thread serta penampilan durasi syscall penuh
  • vet menyesuaikan peringatan loop closure agar sesuai dengan semantik variabel loop Go 1.22, serta menambahkan peringatan untuk append tanpa nilai, time.Since yang tidak ditunda di dalam defer, dan ketidakcocokan key/value log/slog
  • Bootstrap memerlukan setidaknya point release final Go 1.20; Go 1.24 diperkirakan akan mensyaratkan setidaknya point release final Go 1.22
  • Pada darwin/amd64, Go toolchain kini secara default menghasilkan PIE; Go 1.22 adalah rilis terakhir yang berjalan di macOS 10.15 Catalina, dan Go 1.23 memerlukan macOS 11 Big Sur atau lebih baru
  • Tipe Alias dan fungsi Unalias ditambahkan ke go/types; pada gotypesalias=1, klien harus menangani tipe Alias
  • slices.Delete, DeleteFunc, Compact, CompactFunc, Replace melakukan zeroing pada elemen di rentang yang diperkecil, dan Insert selalu memicu panic jika i berada di luar rentang
  • Fungsi pembacaan direktori Windows membaca entri secara batch untuk mengurangi jumlah system call, dengan peningkatan performa hingga 30%

1 komentar

 
GN⁺ 2024-02-08
Pendapat di Hacker News
  • Selama 3 tahun terakhir terutama memakai TypeScript, lalu belakangan mulai memakai Go; awalnya agak khawatir karena kurangnya fungsi array atau sistem tipe yang kurang fleksibel
    Namun ketika mencoba menyiapkan ulang proyek TypeScript untuk tim berukuran 4–5 orang, terlalu banyak waktu habis untuk linting, memilih library routing server, memilih server, standar coding, penanganan error dasar, memaksakan error kustom atau tipe Result agar terhindar dari neraka try/catch bertingkat, testing dan mocking, konfigurasi Prisma, dan sebagainya
    Saya memang suka TypeScript, tetapi memakai bahasa dengan standard library yang hebat, type safety yang benar, dan standar coding bawaan itu benar-benar nyaman. Go juga punya quirks, tetapi cukup bagus, dan routing yang kini masuk standard library berarti ada satu hal lagi yang tidak perlu dipikirkan, jadi menyenangkan. Sekarang tinggal menunggu fungsi map/filter/find untuk slice

    • Sebuah newsletter CTO baru-baru ini membandingkan rilis TypeScript dan Go, dan memakai Go 1.22 sebagai contoh
      Di setiap rilis, TypeScript makin kompleks demi power user, sedangkan Go memasukkan hal-hal yang sebelumnya kurang, seperti range untuk integer, sehingga lebih sederhana dipakai
      Ini mirip sekuel gim yang terus menambah latar dan mekanik sampai akhirnya perlu reset demi pengguna baru; bahasa pemrograman sulit melakukan itu, jadi bagus bahwa Go menyadarinya
    • Saya merasakan hal serupa. Yang membuat saya bertahan di Go adalah toolchain build yang sangat terpadu, dan hal-hal yang bisa dilakukan dengan go:embed dan go:generate selalu mengesankan setiap kali saya melihatnya di proyek lain
      Paket golang.org/x juga bagus karena implementasi untuk hampir semua RFC internet sudah siap pakai
    • Sampai map/filter/find untuk slice hadir, bisa memakai library lo yang terinspirasi lodash
      Ini alat serbaguna favorit saya di proyek Go: https://github.com/samber/lo
    • Justru karena fiturnya tidak terlalu banyak, keputusan-keputusan kecil berkurang, dan meski berlawanan dengan intuisi, hasilnya cukup produktif
    • Saya pernah cukup lama bekerja di klien yang memakai TypeScript, dan belakangan saya menyebutnya “Tricks Driven Development”
      Polanya berulang: saat membaca dokumentasi untuk melakukan sesuatu, tak lama kemudian seseorang memberi tahu trik yang bisa dipakai tetapi tidak ada di dokumentasi
  • Kalau catatan rilis resminya terasa agak kaku, saya sudah membuat versi interaktif: https://antonz.org/go-1-22

    • Masalah variabel for loop yang dibagi bersama awalnya tidak langsung saya pahami, tetapi melihat hasil yang tidak terduga dengan menjalankannya sendiri membantu
    • Contoh Compact dan Replace membingungkan; saya tidak yakin apakah itu benar
  • Saya memakai Go selama lebih dari 9 tahun, dan 4 tahun terakhir banyak memakai Dart karena Flutter; menurut saya kedua bahasa ini punya sikap terhadap kompleksitas yang benar-benar berlawanan. Dart ingin menambahkan semua fitur yang mungkin, sedangkan Go sebaliknya
    Pertama, di Dart ada terlalu banyak cara untuk menginisialisasi nilai di dalam class, sehingga banyak waktu terpakai. Bergantung pada prefiks final/const/static/late, lokasi inisialisasi bisa berbeda-beda: constructor, factory, initState() milik Flutter StatefulWidget, dan sebagainya; saat refactoring, inisialisasi harus banyak diubah. Getter yang membuat fungsi tampak seperti variabel juga menambah kebingungan di codebase baru
    Kedua, Dart punya banyak fitur yang cocok dijejalkan dalam satu baris, seperti map dan stream, sehingga kita tergoda cepat membuat kode satu baris yang sulit dipahami. Namun saat debugging, atau ketika developer junior bertemu hack seperti firstWhereOrNull dan parameter opsional seperti orElse: () => null, mereka menjadi sangat bingung. Null safety atau error tipe yang rumit juga sering membuat pekerjaan terhenti, dan ketika mengubahnya menjadi loop for sederhana ala Go, rasanya benar-benar lega

    • Sebagai tips Dart, sebaiknya jangan memakai initState untuk hal yang tidak langsung terkait UI. Misalnya, kalau bukan sekadar mengatur hint field teks, saya cenderung menghindarinya
      Sebagian besar halaman Flutter punya sangat sedikit pekerjaan, atau parent membuat objek MyPageController, menginisialisasinya sesuai kebutuhan, lalu child page berjalan mengikuti controller itu. Misalnya, di halaman daftar, ketika pengguna ingin mengedit item, parent membuat controller, memasukkan item ke dalamnya, lalu mengirimnya ke child page; setelah kembali, parent bisa melihat item, variabel, atau callback di controller untuk menentukan perubahan UI
      Dengan cara ini, interaksi antar-widget bisa dikontrol secara rinci tanpa menyentuh hal seperti InheritedWidget. Tentu lebih baik dipakai bersama library state management, tetapi dalam praktiknya sering juga tidak dipakai
    • Saya setuju bahwa kesederhanaan Go adalah keunggulan terbesarnya. range juga demikian; pada akhirnya jumlah karakter yang diketik mirip dengan comprehension seperti forEach(f), hanya saja tersebar menjadi tiga baris sehingga tampak lebih panjang, dan kalau ditulis eksplisit sebenarnya bukan hal besar
      Namun terkait inisialisasi, saya berharap Go punya cara idiomatis untuk menginisialisasi field struct dengan nilai tertentu. Tidak adanya constructor tidak masalah, tetapi kadang saya ingin bool secara default diinisialisasi sebagai true
    • initState adalah override dari StatefulWidget dan tidak berbeda dari event lifecycle di framework lain; itu konsep di sisi Flutter, jadi bukan sesuatu yang sifatnya membingungkan dengan constructor
      Memang bisa membingungkan harus memakai constructor biasa atau factory, tetapi sulit mengatakan Go lebih unggul karena initState
    • Yang harus dioptimalkan adalah kemampuan para ahli mahal untuk berkomunikasi secara ringkas satu sama lain. Merampas alat sintaksis yang kuat dari tangan pemula hanya akan menghalangi mereka membangun keahlian
  • Saat io.Copy menyalin dari TCPConn ke UnixConn, jika memungkinkan ia akan memakai system call splice(2) di Linux, dan menggunakan metode baru TCPConn.WriteTo
    Dengan upgrade interface ini, zero-copy I/O kembali bertambah secara transparan. Efek yang diperoleh dari pola ini di paket io benar-benar besar

    • Standard library Go memang punya banyak sekali penyesuaian semacam ini. Tidak selalu buruk, tetapi special-case seperti ini tidak scalable, sehingga integrasi dengan library non-standar menjadi kurang memuaskan
      Meski begitu, masih dalam batas yang bisa diharapkan
  • Pola routing yang ditingkatkan adalah perbaikan yang bagus, terutama saat masa depan Gorilla Mux sedang tidak pasti
    Namun perubahan ini memecah kompatibilitas mundur dalam beberapa cara kecil: ada bagian yang jelas seperti perubahan perilaku pola yang berisi { dan }, serta bagian yang kurang jelas seperti penanganan path yang di-escape. Ini dikendalikan lewat field httpmuxgo121 pada GODEBUG; dengan mengatur httpmuxgo121=1, perilaku lama bisa dipulihkan
    Namun saya penasaran mengapa ini tidak bertentangan dengan janji kompatibilitas Go 1 bahwa “program yang ditulis sesuai spesifikasi Go 1 akan terus dikompilasi dan berjalan dengan benar tanpa perubahan selama masa berlaku spesifikasi tersebut”

    • Cara untuk mengakali janji kompatibilitas Go 1 adalah menggantungkan perubahan yang tidak kompatibel ke belakang seperti ini pada nilai direktif go di go.mod
      Jika 1.22 atau lebih baru, Anda mendapat perilaku library baru; jika tidak, Anda mendapat perilaku lama. Seberapa baik ini bekerja dalam praktik masih perlu dilihat
    • Biasanya, sebelum memecahkan sesuatu, tim Go akan meng-crawl GitHub dan program open source untuk melihat bagaimana orang memakainya. Mungkin mereka melihat bahwa penggunaan { dan } pada path HTTP handler hampir tidak ada
      Mereka juga menyediakan cara untuk mematikan perilaku baru, jadi tidak memaksa perubahan kode, meski tetap harus mengatur environment variable baru
      Perubahan semantik loop for pada rilis ini juga contoh serupa; pada dasarnya itu perubahan yang memecahkan kompatibilitas. Meski begitu, semua program Go tetap dikompilasi dan berjalan, hanya sebagian perilakunya sedikit berubah. Menurut saya Go memilih pendekatan pragmatis, dan itu salah satu alasan keberhasilannya
    • Menurut saya ini kesalahan yang jarang terjadi di Go. Kalau mereka akan memecahkan kompatibilitas per versi menggunakan go.mod, setidaknya seharusnya pecahkan dengan cara yang lebih baik
      Daripada harus mencari isu runtime yang halus ketika mengubah go.mod ke 1.22, jauh lebih baik jika kodenya gagal dikompilasi saja
    • Kalau tidak, mereka kehilangan slogan iklan yang singkat dan kuat. Sekecil apa pun, ini tetap perubahan yang tidak kompatibel
  • Di Go 1.22, setiap iterasi loop akan membuat variabel baru
    Hal ini juga pernah dibahas di sini sebelumnya: https://news.ycombinator.com/item?id=33160236 - Go: Redefining For Loop Variable Semantics (2022)

  • Mungkin terdengar kuno, tapi saya tidak suka penambahan range untuk fungsi. Kenyamanannya tidak cukup besar untuk membenarkan kompleksitas tambahan pada bahasa, dan gaya fungsional terasa tidak selaras dengan gaya Go yang eksplisit, imperatif, verbose, tetapi fiturnya sedikit. Menurut saya itu salah satu keunggulan besar Go
    Dengan alasan yang sama, saya juga merasa range untuk integer adalah arah yang keliru. Kumpulan fitur Go yang tipis dan beban kognitifnya yang rendah selalu menjadi kekuatan utama sekaligus pembeda

    • Saat ini fitur ini opsional, eksperimental, dan harus diaktifkan secara eksplisit. Jika nanti diaktifkan sebagai standar, saya berharap ada mekanisme untuk mematikannya agar developer terdorong tidak menggunakannya ketika tidak umum dipakai
      Salah satu masalah besar dalam pengembangan software adalah mencegah developer menambahkan kompleksitas atau memamerkan kemampuan. Terutama developer di awal karier cenderung membuat solusi terlalu kompleks, alih-alih menyelesaikan masalah secara langsung meski kurang elegan dan lebih panjang
    • Fitur ini terasa masih terlalu dini. Idealnya fitur ini masuk setelah lambda dan generic parameter pack diperkenalkan
      Dukungan generics Go saat ini belum cukup canggih untuk menopangnya, sehingga muncul batasan-batasan yang terasa dipaksakan secara aneh
    • Saya juga melihatnya agak ambigu. Dibandingkan meneruskan fungsi inline, jumlah baris kode belum tentu berkurang
  • Penambahan sql.Null[T] bagus. Di proyek baru saya mungkin akan mulai memakainya
    Di pekerjaan saat ini, saya bergantung pada null [0] dari sqlboiler yang API-nya sangat mirip. Ia berperilaku seperti sql.Null, tetapi punya metode tambahan IsSet() bool yang memberi tahu apakah nilainya pernah di-set secara eksplisit, sehingga membantu membedakan “null yang disengaja” dan “null karena belum diinisialisasi”. Kelihatannya bagus, tetapi dalam praktiknya saya belum pernah menggunakannya

    • Saya penasaran kapan kita perlu tahu apakah null itu disengaja. Bukankah database tidak punya tipe yang ekuivalen untuk itu?
  • Saya menantikan untuk melihat lagi mux standard library dan apakah mungkin menghapus chi. Senang sekali fitur seperti ini masuk ke standard library

    • Saya datang untuk mengatakan hal yang sama. chi benar-benar hebat di beberapa proyek, bahkan terasa begitu natural sampai saya lupa keberadaannya
      Jika fitur seperti ini masuk standard library, ia akan selalu dipelihara dan memastikan banyak program Go memakai pendekatan yang sama
  • Saya penasaran, kalau memakai Go di production, apakah bisa cepat pindah ke versi terbaru, atau justru terikat pada rilis lama
    Dari proyek-proyek publik, terlihat banyak yang menghindari fitur yang relatif baru. Walau tidak memakai generics, saya ingin memakai any yang muncul di Go 1.18 alih-alih interface{} lama, dan saya juga pernah dengar bahwa yang terakhir lebih “idiomatis”

    • Di Square, biasanya kami menunggu rilis point pertama sebelum menaikkan versi default monorepo Go. Pemilik aplikasi individual boleh menaikkan lebih cepat
      Kali ini agak rumit: tim Go merilis 1.22 sebelum kami menaikkan default ke 1.21. Sekarang menunggu sudah hampir menjadi kebiasaan, dan jarang sekali rilis Go memecahkan sesuatu
    • Untuk fitur baru, saya cenderung menunggu bereksperimen sampai melihat masalah yang cocok, tetapi versi compiler saya naikkan hampir segera setelah rilis
      Misalnya untuk generics, kami menunggu sekitar 6 bulan sebelum benar-benar memakainya, sambil memastikan kegunaannya, developer experience, serta dampaknya terhadap kecepatan build dan test tidak besar
    • Di kantor, container yang berjalan di production, yaitu layanan SaaS/API, bisa dinaikkan bebas oleh developer ke build terbaru
      Namun kami juga menyediakan aplikasi end-user dengan Go, dan untuk yang ini kami harus tetap di 1.20 karena kompatibilitas dengan OS klien lama. Karena ada pemangkasan cukup besar di 1.21, kemungkinan kami akan tetap di 1.20 selama beberapa tahun
    • CI membangun dan menguji dengan container latest Go, dan test suite kami cukup solid, jadi pada dasarnya update terjadi otomatis. Jika ada yang tidak cocok, pipeline akan rusak, lalu kami memutuskan apakah akan mengunci ke versi terakhir yang berfungsi atau menunda update sampai perubahan yang memecahkan itu diperbaiki
      Sekali dalam beberapa tahun, kadang bug edge case yang halus antara versi baru dan package pihak ketiga muncul, tetapi bug seperti itu, menurut definisinya, lolos dari test suite, jadi kemungkinan besar tidak akan tertangkap meski upgrade dilakukan manual
    • Langsung pindah
      Jika khawatir soal dukungan compiler Go lama, Anda bisa menaruh build condition untuk versi lama dan mendefinisikan hal yang hilang. Misalnya, di bawah // +build !go1.7 Anda bisa menaruh type any = interface{}