Kemarin-kemarin sudah menulis tentang ini dengan judul yang hampir sama namun menggunakan perspektif pengguna akhir, sekarang mari kita menggunakan perspektif dari seorang backend developer.

Website adalah tentang menampilkan konten, yang mana konten tersebut disimpan di server yang akan dikirimkan ke si klien yang meminta. Konten tersebut bermacam-macam tipe nya, ada teks; aplikasi, gambar, dsb.

Setiap pengguna/klien memiliki bandwidth yang beragam, begitupula dengan server. Karena bandwidth tidak gratis, kita perlu "memikirkan" tentang penghematan bandwidth ini agar si pemilik konten tidak perlu membeli bandwidth tambahan dan si klien tidak cepat kehabisan kuota akan paket internet yang mereka sewa.

Jadi, di tulisan ini kita akan membahas seputar cara pengehematan bandwidth yang biasanya dilakukan oleh seorang backend developer!

Kompresi teks

Dalam format UTF-8, 1 karakter sama dengan 1 byte. yang singkatnya, bila konten tersebut memiliki 100k karakter, berarti konten tersebut memiliki ukuran 100KB.

Begitupula bila memiliki total karakter 1jt, berarti ~1MB.

Sebagai contoh, berkas jQuery versi 3.5.1 memiliki total karakter sebanyak 287,630 yang kurang lebih berarti berukuran ~280KB. Tentu saja 280KB bukanlah angka yang kecil untuk 1 berkas, terlebih bertipe JavaScript yang mana akan di proses lagi oleh browser (bukan hanya sekadar menampilkan sebagai teks).

Ukuran tersebut bisa dikurangi dengan melakukan kompresi (untuk seputar minify akan dibahas selanjutnya!) terhadap teks yang ada. Kompresi yang umum digunakan adalah gzip karena sudah banyak klien yang mendukung kompresi tersebut.

Jadi, misal berkas jQuery tersebut (yang bertipe application/javascript) di kompresi terlebih dahulu on the fly menggunakan gzip, dan akan dikirimkan dalam bentuk gzip yang bisa dikonsumsi oleh klien.

Lihat perbandingan nya, dari ~280KB menjadi ~80KB yang meskipun masih lumayan besar juga. Tapi peningkatan tetaplah peningkatan, bukan?

Sekarang mari kita bandingkan kedua format tersebut:

Di contoh diatas coba mengambil 3 baris terakhir dari keseluruhan konten.

Lihat perbedaan antara kedua nya, yang tentu nya memiliki jumlah baris & karakter yang berbeda juga. Lalu, bagaimana si klien bisa mengerti teks yang sudah di compress tersebut?

Dengan melakukan decompress!

Bagian Accept-encoding: gzip memberitahukan ke server bahwa si klien mendukung & mengerti cara memproses gzip, maka dari itu si server mengirim konten (data) tersebut dalam bentuk gzip.

Sekarang, mari kita lakukan decompress.

Konten yang sama!

Beda nya, ketika transfer konten (data), data yang dikirim & diterima dalam bentuk yang sudah ter-kompresi, sehingga ukuran nya relatif lebih kecil dari yang asli which is good.

Brotli

Selain gzip, kita bisa melakukan kompresi juga menggunakan brotli yang mana memiliki ukurang yang lebih kecil dari gzip.

Tapi salah satu kekurangan dari brotli ini adalah belum didukung oleh semua peramban (meskipun evergreen browser sudah!) dan mungkin belum didukung oleh semua web server yang umum kamu gunakan.

Sekarang, mari kita coba bandingkan brotli dengan gzip.

Untuk klien yang mendukung & mengerti kompresi brotli, ditandakan dengan header Accept-encoding: br.

Dan karena si code.jquery enggak mendukung brotli, jadi kita menggunakan JSDelivr untuk contoh.

Disitu bisa dilihat ukuran yang menggunakan gzip adalah 84,805 bytes dan brotli sekitar 80,471. Hemat ~4KB! Penghematan yang lumayan untuk berkas teks bertipe JavaScript.

Minify teks

Mungkin ini spesifiknya bukan tugas orang backend kali ya, tapi gak papa siapa tau orang frontend nya lupa ngurusin build pipeline untuk frontend.

Minify ini sederhananya menghapus hal-hal yang sekira nya kurang berguna untuk pengguna akhir (komentar, spasi, tab, dsb), menamai (am I right?) ulang terkait penamaan (e.g: dari getMoneyFromUserWallet() menjadi xCd3()), dan masih banyak lagi.

Mengapa? Because every bytes count.

Biaya dari melakukan minify ini hanya sekali, umum nya ketika build time kecuali lo adalah CDN. Berbeda dengan proses kompresi diatas yang dilakukan ketika request masuk.

Sekarang, kita lihat perbedaan dari versi yang tidak di minify (tapi sudah di compress) dengan yang sudah.

Dengan menggunakan kompresi brotli, ukuran jQuery tersebut menjadi ~30KB untuk versi minified + compressed, penghematan yang sangat besar dari yang sebelumnya ~280KB, menjadi ~80KB, dan sekarang ~30KB alias -250KB dari bentuk asli.

Proses minify ini bisa dilakukan dengan webpack, gulp, ataupun awk kalau kamu anak nya sysadmin garis keras tapi ga mau rename variable dan fungsi.

Kompresi gambar

Selain teks, yang memenuhi isi website adalah gambar.

Namun gambar (dan media lain) berbeda dengan teks yang bertipe HTML, JavaScript, dan CSS bila dimuat: Peramban tidak perlu melakukan hal-hal lain seperti membuat struktur DOM, CSSOM, dsb.

Sangat jarang gambar memiliki ukuran yang kecil, untuk screenshot terakhir diatas saja memiliki ukuran ~106KB dan gambar yang diambil dari kamera iPhone saja berukuran ~2MB atau ~2jt bytes.

Tapi sekali lagi, memuat gambar tidak memblokir proses rendering yang dilakukan oleh peramban, jadi, mungkin, tidak terlalu menjadi masalah.

Sedangkan yang sedang kita bicarakan adalah tentang penghematan bandwidth, dan gambar 2MB bila dimuat oleh 2000 pengguna yang berbeda berarti server sudah mentransfer sekitar 4GB dan 1 pengguna sudah menghabiskan kuota paket internet ~2MB. Bayangkan bila 1 halaman memiliki 5 gambar berukuran segitu, hanya dalam 10 hari, pengguna bisa menghabiskan ~100MB untuk mengakses halaman tersebut.

Itupun bila halaman tersebut hanya menampilkan gambar, kan?

Proses kompresi gambar ini lumayan effort dan kompleks, bisa dilakukan hanya ketika build time ataupun on the fly bila kamu adalah CDN yang selalu sensitif dengan caching.

Berbeda dengan kompresi teks, tidak ada "hal visual" yang diubah. Di gambar, bila gambar tersebut memiliki 666px, bagaimana cara agar gambar berukuran 666px tersebut memiliki ukuran yang lebih kecil namun tanpa menghilangkan "esensi" dari gambar asli?

Dan karena programming adalah tentang tradeoff, dan yang biasanya dikorbankan adalah kualitas.

https://squoosh.app

Diatas adalah contoh gue melakukan kompresi terkait screenshot yang sebelumnya itu (yang berukuran ~110KB) dengan gambar hasil kompresi (yang dibagian kanan) yang mana sekarang berukuran ~29KB dengan menggunakan OxiPNG dan sedikit setting yang gue lakukan.

Sekilas, gambar diatas tidak ada yang berbeda, bukan?

Namun, memiliki ukuran 73% lebih kecil alias berkurang ~81KB!

Ini gambar hasil kompresi nya:

Sekilas tidak ada yang berubah, sampai sadar bahwa memiliki warna background yang berbeda. Dan menurut gue, dalam konteks ini tidak ada masalah karena esensi dari gambar tersebut tidak hilang.

Cache

Ini yang paling menantang, karena bisa fatal bila "salah" melakukan strategi untuk caching.

Ada banyak strategi untuk melakukan caching di peramban ini.

Yang paling sederhana adalah dengan mengirim header bernilai Cache-control: public, max-age=<s> yang mana s tersebut adalah nilai maksimal sampai kapan request tersebut di cache yang umum nya dilakukan oleh proxy server.

Yang lumayan sederhana untuk melakukan caching ke browser ini adalah dengan mengirimkan header Etag yang biasanya bernilai dari checksum terkait berkas yang di request tersebut.

Jika server kita memberikan Etag (dan peramban sudah memiliki cache akan request tersebut), ketika peramban melakukan request lagi (ke berkas yang sama), peramban akan mengirim request header If-None-Match yang bernilai etag tersebut.

Jika sama dengan nilai Etag, maka peramban akan mendapatkan response 304 (Not Modified) sehingga peramban tidak perlu mengganti cache yang sudah ada dan konten yang ditampilkan adalah yang sudah ada di cache (peramban) tersebut.

Jika (lagi?) tidak ingin terlalu mempusingkan bagaimana peramban melakukan caching akan konten yang ada di server "asli", silahkan gunakan CDN.

Atau di waktu selanjutnya—bila sempat—kita akan membahas tentang bagaimana membuat layanan "CDN scale" sendiri :))

Penutup

Sejauh ini, yang gue tau, hal yang bisa dilakukan oleh backend developer untuk membantu frontend developer salah satu nya adalah dengan membuat cara untuk melakukan penghematan bandwidth yang akan di konsumsi oleh klien (pengguna) ini.

Tentu saja hal-hal terkait sekuritas pun membantu yang salah satunya memberikan header seperti terkait content security policy, referer policy, hsts, xss filter, dsb.

Bila berpikir lebih dalam dengan menggunakan jiwa SJW, bandwidth juga berpengaruh akan terbuat nya emisi karbon (dan industri IT salah satu penyumbang yang besar (2019)).

Karena, bayangkan, berapa (dan apa saja) energi yang dihabiskan untuk mengirim data dari data center, ke ISP, lalu ke pengguna akhir.

Dan seperti nya situs ini menarik, begitupula dengan tulisan ini.

Menghemat konsumsi bandwidth ternyata tidak hanya menguntungkan untuk pengguna akhir saja, namun ke bumi kita tercinta ini juga!