108. Studi Kasus: Generate Protobuf Secara Otomatis untuk Banyak Bahasa
Selama satu dekade terakhir, microservices telah mendominasi arsitektur sistem backend. Salah satu kunci suksesnya adalah kemampuan berbagai layanan untuk saling berkomunikasi melalui protokol yang konsisten, cepat, namun mudah dikembangkan. Salah satu format yang populer untuk kebutuhan ini adalah Protocol Buffers (Protobuf) yang diperkenalkan oleh Google.
Dalam artikel ini, saya akan berbagi pengalaman nyata mengenai bagaimana tim kami mengotomasi proses generate Protobuf menjadi kode untuk berbagai bahasa secara konsisten dan efisien. Studi kasus ini memadukan best practice, penggunaan alat otomatis, CI/CD, dan bagaimana hasil akhirnya mampu mengurangi human error serta mempercepat proses pengembangan layanan.
1. Permasalahan Awal pada Tim Lintas Stack
Tim kami terdiri dari engineer Go, Node.js, dan Java. Setiap perubahan skema Protobuf, harus diikuti dengan regenerate kode hasil dari file .proto ke masing-masing language binding. Pertama-tama, proses ini dilakukan manual:
- Developer submit perubahan pada file
.proto - Tim backend lain menarik perubahan main branch
- Membuka terminal, generate kode sesuai bahasa (protoc-gen-go, protoc-gen-grpc-java, dsb)
- Commit kode hasil generate ke repository service masing-masing
Sayangnya, alur manual ini membawa berbagai masalah:
- Sering terjadi ketidaksesuaian versi: Satu tim lupa melakukan generate, tim lain mendapat kode yang sudah berbeda.
- Potensi merge conflict tinggi: File hasil generate sering berbenturan.
- Menyita waktu: Terutama untuk layanan yang memakai banyak bahasa.
- Susah mengontrol tools dan plugin: Versi generator dan plugin sering berbeda-beda di mesin developer.
Ilustrasi Alur Manual
flowchart LR
A[Update .proto files] --> B{Manual generate}
B -- "Go" --> C[protoc-gen-go]
B -- "Java" --> D[protoc-gen-grpc-java]
B -- "Node.js" --> E[protoc-gen-ts]
C --> F[Push ke repo Go]
D --> G[Push ke repo Java]
E --> H[Push ke repo Node.js]
2. Solusi: Otomatisasi Generate Protobuf Multibahasa
Untuk menanggulangi masalah di atas, kami memutuskan mengotomasi seluruh proses code generation di sistem CI/CD (GitHub Actions), serta membuat sebuah repository shared proto. Alur barunya:
- Semua file
.protodisimpan di satu repo - Setiap commit atau PR, GitHub Actions otomatis meng-generate language bindings sembari mengecek compatibility
- File hasil generate di-commit ke branch terpisah, atau di-upload sebagai artifacts
- Layanan Go, Node.js, dan Java tinggal mengambil release terbaru atau package kode hasil generate
Skema High Level
flowchart TD
RepoProto["Shared Proto Repo (.proto)"]
CI["CI/CD Workflow (GitHub Actions)"]
GoPkg["Go SDK Artifacts / Package"]
JavaPkg["Java SDK Artifacts / Package"]
NodePkg["Node.js SDK Artifacts / Package"]
ServiceA["Go Service (import paket)"]
ServiceB["Node.js Service (import paket)"]
ServiceC["Java Service (import paket)"]
RepoProto --> CI
CI --> GoPkg
CI --> JavaPkg
CI --> NodePkg
GoPkg --> ServiceA
JavaPkg --> ServiceC
NodePkg --> ServiceB
3. Step-by-Step: Membangun Pipeline Protobuf Otomatis
Mari kita bedah tiap tahapnya, lengkap dengan contoh konfigurasinya.
3.1 Struktur Folder Repository
proto-shared/
├── protos/
│ ├── example/
│ │ ├── hello.proto
├── build/
│ ├── go/
│ ├── java/
│ ├── node/
├── .github/
│ └── workflows/
│ └── generate.yml
3.2. Contoh File .proto
// protos/example/hello.proto
syntax = "proto3";
package example;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
3.3. Definisi Workflow CI/CD (GitHub Actions)
Di dalam .github/workflows/generate.yml:
name: Generate Protobuf for Multiple Languages
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.21.0'
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18.x'
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Install Protobuf Compiler
run: sudo apt-get install -y protobuf-compiler
- name: Install protoc plugins
run: |
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
npm install -g protoc-gen-ts
- name: Generate Go code
run: |
mkdir -p build/go
protoc -I=protos --go_out=build/go --go-grpc_out=build/go protos/example/*.proto
- name: Generate Node.js code
run: |
mkdir -p build/node
protoc -I=protos --js_out=import_style=commonjs:build/node --grpc_out=build/node protos/example/*.proto
- name: Generate Java code
run: |
mkdir -p build/java
protoc -I=protos --java_out=build/java --grpc-java_out=build/java protos/example/*.proto
- name: Upload Build Artifacts
uses: actions/upload-artifact@v3
with:
name: generated-protobuf
path: build/
Penjelasan Singkat:
- Setup environment tiga bahasa dalam satu workflow
- Install protokol compiler & plugin sesuai kebutuhan multi-bahasa
- Generate source code untuk Go, Node.js, dan Java ke folder build terpisah
- Upload artifact yang bisa diambil setiap tim/service
4. Konsumsi Hasil Generate: Simulasi Service Go
Untuk tim Go, mereka tinggal mendownload artifacts dari CI/CD atau fetching dari sebuah release/package. Simulasi cara pemakaiannya:
import (
"context"
"log"
pb "github.com/org/proto-shared/build/go/example"
)
func main() {
conn, err := grpc.Dial("greeter-service:50051", grpc.WithInsecure())
if err != nil {
log.Fatal(err)
}
defer conn.Close()
client := pb.NewGreeterClient(conn)
resp, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "Budi"})
if err != nil {
log.Fatal(err)
}
log.Println("Received:", resp.Message)
}
5. Tabel Perbandingan: Sebelum vs Sesudah Otomasi
| Kriteria | Sebelum Otomasi | Sesudah Otomasi |
|---|---|---|
| Konsistensi versi | Sering bermasalah | Sangat terjaga |
| Start service | Sering error | Hampir tidak pernah error |
| Workflow developer | Manual, repetitif | Hanya perlu update .proto |
| Integrasi CI/CD | Tidak ada | Full otomatis |
| Waktu sinkronisasi | Sering telat | Otomatis (hitungan menit) |
| Ketergantungan lokal | Tinggi | Sangat minim |
6. Lessons Learned & Saran Implementasi
Lessons Learned:
- Repository terpusat untuk
.protosangat memudahkan versioning - CI/CD wajib terotomasi agar tidak ada langkah manual
- Build artifact lebih baik daripada langsung commit hasil generate untuk menghindari merge conflict
Saran Implementasi:
- Jika sudah punya monorepo, gunakan submodule untuk tim yang punya repo sendiri.
- Gunakan semantic versioning pada release
.proto - Build juga docker image yang berisi result, jika perlu dipakai di container lain.
7. Penutup
Otomatisasi generate Protobuf untuk banyak bahasa telah membawa game-changer bagi proses pengembangan di tim kami. Proses yang tadinya rawan kesalahan dan memakan waktu kini menjadi elegan, scalable, dan mudah diintegrasikan ke pipeline manapun.
Jika Anda bekerja di tim multi-stack, jangan ragu menginvestasikan waktu untuk membangun fondasi ini! Keuntungan jangka panjangnya nyata — lebih cepat merilis fitur, sedikit error, dan integrasi antar tim yang jauh lebih seamless.
Silakan diskusi lebih lanjut jika ingin tahu detail setup atau butuh script lebih advance!