diff options
| author | Shulhan <m.shulhan@gmail.com> | 2020-03-05 00:41:25 +0700 |
|---|---|---|
| committer | Shulhan <m.shulhan@gmail.com> | 2020-03-05 21:13:38 +0700 |
| commit | 754352bbd2ff67ab705875ddd2c06232187e5474 (patch) | |
| tree | b7287fec87bea00c1f692380d04f833c7f606d3b | |
| parent | a0d960c862228730ee58504889322e09aca8f328 (diff) | |
| download | golang-id-web-754352bbd2ff67ab705875ddd2c06232187e5474.tar.xz | |
blog: terjemahkan "A new Go API for Protocol Buffers"
| -rw-r--r-- | content/blog/a-new-go-api-for-protocol-buffers/index.adoc | 327 | ||||
| -rw-r--r-- | content/blog/index.adoc | 4 | ||||
| -rw-r--r-- | content/index.adoc | 7 |
3 files changed, 335 insertions, 3 deletions
diff --git a/content/blog/a-new-go-api-for-protocol-buffers/index.adoc b/content/blog/a-new-go-api-for-protocol-buffers/index.adoc new file mode 100644 index 0000000..c82720e --- /dev/null +++ b/content/blog/a-new-go-api-for-protocol-buffers/index.adoc @@ -0,0 +1,327 @@ += Go API baru untuk Protocol Buffers +:author: Joe Tsai, Damien Neil, dan Herbie Ong +:date: 2 Maret 2020 + +== Pendahuluan + +Dengan suka cita kami merilis revisi mayor dari Go API untuk +https://developers.google.com/protocol-buffers[protocol buffers], format +pertukaran data yang mendukung banyak bahasa pemrograman dari Google. + + +== Motivasi bagi API yang baru + +_Protocol buffers_ yang pertama untuk Go +https://blog.golang.org/third-party-libraries-goprotobuf-and[diumumkan oleh +Rob Pike] +pada bulan Maret 2010. +Go 1 belum dirilis sampai dua tahun kemudian. + +Satu dekade sejak rilis yang pertama, paket tersebut teluh tumbuh dan +berkembang bersama dengan Go. +Kebutuhan pengguna pun semakin besar juga. + +Banyak orang ingin menulis program yang menggunakan refleksi untuk memeriksa +_message_ dalam _protocol buffer_. +Paket +https://pkg.go.dev/reflect[reflect] +menyediakan tipe dan nilai untuk Go, tetapi mengindahkan informasi dari sistem +tipe _protocol buffer_. +Misalnya, kita ingin memiliki sebuah fungsi yang memeriksa isi sebuah pesan +_log_ dan menghapus setiap field yang berisi data sensitif yang sebelumnya +telah diberi anotasi. +Anotasi tersebut bukan bagian dari sistem tipe Go. + +Salah satu kebutuhan umum lainnya yaitu menggunakan struktur data yang bukan +dihasilkan oleh _compiler_ protocol buffer, seperti tipe _message_ yang +dinamis yang dapat merepresentasikan _message_ yang tipenya tidak diketahui +saat di-kompilasi. + +Kami juga menelaah bahwa sebuah sumber permasalahan yang sering ditemukan +yaitu interface +https://pkg.go.dev/github.com/golang/protobuf/proto?tab=doc#Message[proto.Message], +yang mengidentifikasi nilai dari tipe _Message_ yang dibangkitkan +(_generated_), memiliki manfaat yang sedikit dalam menjelaskan perilaku dari +tipe-tipe tersebut. +Saat pengguna membuat tipe yang mengimplementasikan interface tersebut (sering +kali dengan menanam _Message_ di dalam struct yang lain) dan mengirim +nilai dari tipe tersebut ke fungsi yang mengharapkan nilai _message_ yang +hasil pembangkitan, program menjadi _crash_ atau tidak terprediksi. + +Ketiga permasalahan ini punya penyebab yang sama, dan sebuah solusi yang sama: +interface `Message` seharusnya secara penuh menspesifikasikan perilaku dari +sebuah _message_, dan fungsi-fungsi yang mengoperasikan nilai dari `Message` +seharusnya dapat menerima tipe apa pun yang secara benar mengimplementasikan +interface tersebut. + +Secara kita tidak bisa mengubah definisi dari tipe `Message` yang sekarang dan +tetap menjaga kompatibilitas dari paket API, kami memutuskan untuk mulai +membuat versi mayor yang baru yang tidak kompatibel dengan modul `protobuf`. + +Hari ini, kita merilis modul baru tersebut. +Kami harap Anda menyukainya. + + +== Refleksi + +Refleksi adalah fitur andalan dari implementasi yang baru. +Mirip dengan bagaimana paket `reflect` menyediakan sebuah tipe dan nilai pada +Go, paket +https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect?tab=doc[`google.golang.org/protobuf/reflect/protoreflect`] +menyediakan sebuah nilai menurut sistem tipe _protocol buffer_. + +Deskripsi lengkap dari paket `protoreflect` akan terlalu panjang bila +dijelaskan di sini, tetapi mari kita lihat bagaimana kita dapat menulis fungsi +yang membersihkan pesan _log_ seperti yang kita sebut sebelumnya. + +Pertama, kita tulis berkas `.proto` mendefinisikan ekstensi dari tipe +https://github.com/protocolbuffers/protobuf/blob/b96241b1b716781f5bc4dc25e1ebb0003dfaba6a/src/google/protobuf/descriptor.proto#L509[`google.protobuf.FieldOptions`] +supaya kita dapat menambahkan anotasi pada field-field yang berisi informasi +yang sensitif atau tidak. + +---- +syntax = "proto3"; +import "google/protobuf/descriptor.proto"; +package golang.example.policy; +extend google.protobuf.FieldOptions { + bool non_sensitive = 50000; +} +---- + +Kita kemudian menggunakan opsi ini untuk menandai field-field tertentu +yang tidak sensitif. + +---- +message MyMessage { + string public_name = 1 [(golang.example.policy.non_sensitive) = true]; +} +---- + +Selanjutnya, kita tulis sebuah fungsi Go yang menerima nilai `Message` apa pun +dan menghapus semua field-field yang sensitif. + +---- +// Redact clears every sensitive field in pb. +func Redact(pb proto.Message) { + // ... +} +---- + +Fungsi ini menerima sebuah +https://pkg.go.dev/google.golang.org/protobuf/proto?tab=doc#Message[`proto.Message`], +tipe interface yang diimplementasikan oleh semua tipe message hasil +pembangkitan. +Tipe tersebut adalah alias dari yang tipe yang didefinisikan dalam paket +`protoreflect`: + +---- +type ProtoMessage interface { + ProtoReflect() Message +} +---- + +Untuk menghindari penuhnya _namespace_ dari `Message` hasil pembangkitan, +interface tersebut hanya berisi sebuah method yang mengembalikan +https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect?tab=doc#Message[`protoreflect.Message`], +yang menyediakan akses ke isi `message`. + +Kenapa alias? +Karena `protoreflect.Message` memiliki method yang mengembalikan +`proto.Message` yang asli, dan kita harus menghindari pengulangan impor +(_import cycle_) antara kedua paket tersebut. + +Method +https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect?tab=doc#Message.Range[`protoreflect.Message.Range`] +memanggil sebuah fungsi untuk setiap field dalam sebuah `Message`. + +---- +m := pb.ProtoReflect() +m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { + // ... + return true +}) +---- + +Fungsi `Range` dipanggil dengan sebuah +https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect?tab=doc#FieldDescriptor[`protoreflect.FieldDescriptor`] +yang mendeskripsikan tipe _protocol buffer_ dari field, dan sebuah +https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect?tab=doc#Value[`protoreflect.Value`] +yang berisi nilai dari field. + +Method +https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect?tab=doc#Descriptor.Options[`protoreflect.FieldDescriptor.Options`] +mengembalikan field sebagai sebuah `google.protobuf.FieldOptions`. + +---- +opts := fd.Options().(*descriptorpb.FieldOptions) +---- + +(Kenapa pakai asersi tipe? +Karena paket `descriptorpb` bergantung pada `protoreflect`, paket +`protoreflect` tidak dapat mengembalikan tipe konkrit dari `Options` tanpa +mengakibatkan pengulangan impor.) + +Kemudian kita dapat memeriksa `opts` untuk melihat nilai dari ekstensi +boolean kita sebelumnya: + +---- +if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) { + return true // don't redact non-sensitive fields +} +---- + +Ingatlah bahwa yang perlu diperhatikan di sini yaitu field _descriptor_. +Informasi yang ingin kita ketahui berada dalam sistem tipe _protocol buffer_, +bukan dalam sistem tipe Go. + +Hal ini juga merupakan contoh wilayah di mana kita telah menyederhanakan API +dari paket `proto`. +https://pkg.go.dev/github.com/golang/protobuf/proto?tab=doc#GetExtension[`proto.GetExtension`] +yang aslinya mengembalikan sebuah nilai dan sebuah error. +Fungsi +https://pkg.go.dev/google.golang.org/protobuf/proto?tab=doc#GetExtension[`proto.GetExtension`] +yang baru mengembalikan hanya nilai, atau nilai baku dari field bila tidak +ada. +Kesalahan dekode dari ekstensi dilaporkan saat `Unmarshal`. + +Saat kita mengetahui field mana yang perlu dihilangkan, kode untuk menghapus +field tersebut cukup dengan: + +---- +m.Clear(fd) +---- + +Bila semua kode di atas digabung, fungsi `Redact` kita menjadi: + +---- +// Redact clears every sensitive field in pb. +func Redact(pb proto.Message) { + m := pb.ProtoReflect() + m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { + opts := fd.Options().(*descriptorpb.FieldOptions) + if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) { + return true + } + m.Clear(fd) + return true + }) +} +---- + +Implementasi yang komplit bisa secara rekursif sampai ke field-field dalam +`Message`. +Kami berharap dengan contoh sederhana ini dapat memberi Anda bayangan terhadap +penggunaan refleksi pada _protocol buffer_. + + +== Versi + +Kami menyebut versi asli dari Go _protocol buffer_ sebagai APIv1, dan yang +baru APIv2. +Karena APIv2 tidak kompatibel dengan APIv1, kita membutuhkan path modul yang +berbeda. + +(Versi API ini tidak sama dengan versi dari bahasa _protocol buffer_: +`proto1`, `proto2`, dan `proto3`. +APIv1 dan APIv2 adalah implementasi dalam Go yang mendukung versi bahasa +`proto2` dan `proto3`.) + +Modul +https://pkg.go.dev/github.com/golang/protobuf?tab=overview[`github.com/golang/protobuf`] +adalah APIv1. + +Modul +https://pkg.go.dev/google.golang.org/protobuf?tab=overview[`google.golang.org/protobuf`] +adalah APIv2. +Kami telah mengambil mengubah path impor dengan beralih ke tempat yang tidak +bergantung pada penyedia layanan hosting. +(Kami juga mempertimbangkan `google.golang.org/protobuf/v2`, untuk memperjelas +bahwa ini adalah versi mayor kedua dari API, tetapi kemudian memutuskan untuk +memilih path yang pendek untuk keuntungan jangka panjang.) + +Kami tahu bahwa tidak semua pengguna akan pindah ke versi mayor yang baru pada +saat bersamaan. +Beberapa akan langsung pindah; +yang lain bisa jadi tetap menggunakan versi lama seterusnya. +Bahkan dalam sebuah program, beberapa bagian bisa jadi pakai API yang lama dan +bagian lain menggunakan yang baru. +Sangat penting bahwa kami terus mendukung program yang menggunakan APIv1. + +* `github.com/golang/protobuf@v1.3.4` adalah versi paling terbaru pra-APIv2 + dari APIv1. + +* `github.com/golang/protobuf@v1.4.0` adalah versi APIv1 yang + diimplementasikan dengan APIv2. + API-nya tetap sama, tetapi implementasi dibelakangnya menggunakan yang + baru. + Versi ini berisi fungsi-fungsi untuk mengonversi interface `proto.Message` + antara APIv1 dan APIv2 untuk memudahkan transisi antara keduanya. + +* `google.golang.org/protobuf@v1.20.0` adalah APIv2. + Modul ini bergantung pada `github.com/golang/protobuf@v1.4.0`, sehingga + program apa pun yang menggunakan APIv2 akan secara otomatis mengambil versi + APIv1 yang terintegrasi dengannya. + +(Kenapa mulai dengan versi `v1.20.0`? +Supaya lebih jelas. +Kami tidak berharap APIv1 akan sampai ke `v1.12.0`, sehingga nomor versi +itu sendiri sudah cukup untuk membedakan antara APIv1 dan APIv2.) + +Kami tetap mendukung APIv1 selamanya. + +Pengorganisasian ini memastikan supaya semua program akan menggunakan +implementasi tunggal dari _protocol buffer_, tanpa memperhatikan versi API +mana yang digunakan. +Ia membolehkan program untuk mengadopsi API baru secara gradual, atau tidak +sama sekali, namun tetap mendapatkan keuntungan dari implementasi yang baru. +Prinsip dari pemilihan versi minimum (_minimum version selection_) yaitu bahwa +sebuah program bisa terus menggunakan implementasi yang lama sampai pengelola +memilih untuk memperbarui ke yang baru (baik secara langsung, atau lewat +pembaruan dependensi). + + +== Catatan fitur tambahan + +Paket +https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson[`google.golang.org/protobuf/encoding/protojson`] +mengonversi _protocol buffer_ `Message` dari dan ke JSON menggunakan +https://developers.google.com/protocol-buffers/docs/proto3#json[pemetaan JSON +kanonis], +dan memperbaiki sejumlah isu dengan paket `jsonpb` yang lama yang sulit diubah +tanpa menyebabkan masalah bagi pengguna yang ada. + +Paket +https://pkg.go.dev/google.golang.org/protobuf/types/dynamicpb[`google.golang.org/protobuf/types/dynamicpb`] +menyediakan sebuah implementasi dari `proto.Message` untuk `message` yang tipe +_protocol buffer_-nya dibangkitkan saat _runtime_. + +Paket +https://pkg.go.dev/google.golang.org/protobuf/testing/protocmp[`google.golang.org/protobuf/testing/protocmp`] +menyediakan fungsi-fungsi untuk membandingkan `Message` _protocol buffer_ +dengan paket +https://pkg.go.dev/github.com/google/go-cmp/cmp[`github.com/google/go-cmp/cmp`]. + +Paket +https://pkg.go.dev/google.golang.org/protobuf/compiler/protogen?tab=doc[`google.golang.org/protobuf/compiler/protogen`] +menyediakan dukungan untuk menulis _plugin_ untuk _compiler protocol buffer_. + + +== Kesimpulan + +Modul `google.golang.org/protobuf` adalah perbaikan mayor dari dukungan Go +terhadap _protocol buffer_, menyediakan dukungan kelas-satu untuk refleksi, +implementasi kustomisasi `Message`, dan pembersihan API. +Kami ingin memelihara API yang lama selamanya sebagai pembungkus dari yang +baru, membolehkan pengguna mengadopsi API baru secara inkremental. + +Tujuan dari pembaruan ini yaitu untuk meningkatkan API yang lama dan +membereskan masalah-masalah mereka yang terdahulu. +Saat kita menyelesaikan setiap komponen dari implementasi yang baru, kami +langsung gunakan dalam basis kode Google. +Rilis secara inkremental memberikan kita sebuah kepercayaan diri terhadap +penggunaan dari API baru berikut dengan kinerja dan ketepatan dari +implementasi yang baru. +Kami percaya ia siap untuk digunakan untuk lingkungan _production_. + +Kami sangat senang dengan rilis ini dan berharap ia dapat melayani ekosistem +Go untuk sepuluh tahun ke depan dan seterusnya! diff --git a/content/blog/index.adoc b/content/blog/index.adoc index 58ad7e7..2395829 100644 --- a/content/blog/index.adoc +++ b/content/blog/index.adoc @@ -2,6 +2,10 @@ == Indeks +* link:/blog/a-new-go-api-for-protocol-buffers[Go API baru untuk Protocol + Buffers], + 2 Maret 2020. Joe Tsai, Damien Neil, dan Herbie Ong + * link:/blog/go1.14[Go 1.14 telah dirilis], 25 Februari 2020. _Alex Rakoczy_ diff --git a/content/index.adoc b/content/index.adoc index 56536b6..ed3433c 100644 --- a/content/index.adoc +++ b/content/index.adoc @@ -35,6 +35,10 @@ lebih lanjut, silakan buka halaman link:/doc[dokumentasi]. Halaman ini berisi daftar terjemahan blog dari proyek Go resmi dan blog dari komunitas Go Indonesia. +* link:/blog/a-new-go-api-for-protocol-buffers[Go API baru untuk Protocol + Buffers], + 2 Maret 2020. Joe Tsai, Damien Neil, dan Herbie Ong + * link:/blog/go1.14[Go 1.14 telah dirilis], 25 Februari 2020. _Alex Rakoczy_ @@ -47,9 +51,6 @@ komunitas Go Indonesia. * link:/blog/survey2019[Mengumumkan Survei Pengembang Go 2019], 20 November 2019. _Todd Kulesza_ -* link:/blog/go.dev[Go.dev: pusat kegiatan baru untuk pengembang Go], - 13 November 2019. _Steve Francia dan Julie Qiu_ - baca artikel blog link:/blog[lainnya]. |
