Sekilas tentang Web Assembly

Long-short story about .wasm

Sekarang hampir hidup kita dikelilingi oleh aplikasi. Beberapa barang yang biasa disimpan di workdesk pun perlahan tergantikan oleh aplikasi: Buku catatan menjadi Bear, bingkai foto menjadi iCloud Photos, Post-it menjadi Trello, dan sebagainya.

Karena penggunaan aplikasi terkesan lebih efektif & efisien.

Tidak perlu membeli buku baru ketika kertas sudah habis, tidak perlu melakukan komputasi manual ketika menulis sesuatu yang berhubungan dengan angka, dan tidak lupa pula: Data di aplikasi relatif sulit rusak, beda dengan bingkai foto yang akan hancur ketika jatuh & akan basah ketika ditambah masalah tertumpah kopi.

Bagaimanapun, zaman berubah. Hadapi dan jangan mendorong kemunduran™.

Sebelum kita benar-benar membahas Web Assembly, izinkan gue untuk bercerita seputar aplikasi terlebih dahulu — dari kacamata seorang developer.

Desktop & Mobile

Pada dasarnya komputer dibuat untuk memudahkan pekerjaan manusia. Komputer hanyalah sebuah "medium", untuk bisa berinteraksi dengan "sesuatu" sehingga pekerjaan manusia menjadi lebih mudah.

Dan sesuatu tersebut adalah Software; Aplikasi, peranti lunak.

Setiap komputer memiliki sistem operasi, sebuah "roh" untuk bisa menggerakan tubuh-tubuh (hardware) yang ada di komputer. Sistem operasi yang ada sekarang antara lain: Keluarga Apple, Keluarga Microsoft, Keluarga Google, Keluarga BSD, dan Keluarga GNU/Linux.

Sistem operasi yang ada memiliki fitur, sifat, dan tingkah laku yang berbeda-beda alias unik, sama seperti kita sebagai seorang manusia.

Karena keunikan ini, developers perlu menyesuaikan aplikasi yang mereka buat dengan sistem operasi yang mereka targetkan. Contohnya didunia nyata, mungkin seperti proses lokalisasi buku asing ke bahasa Indonesia, agar bisa lebih mudah dimengerti oleh orang Indonesia, secara konsep.

Sistem operasi berada di komputer, dan komputer hanyalah sebuah "medium". Medium tersebut bisa berbentuk Desktop, Laptop, Mobile dan lain-lain yang intinya melakukan proses komputasi.

Masalah klasik dalam membuat software adalah kompatibilitas. Sederhananya, software yang dibuat untuk Windows tentu tidak bisa simsalabim bisa berjalan di GNU/Linux juga, karena kode yang ditulis spesifik untuk berinteraksi dengan "organ" yang ada di Windows. Apalagi di Android.

Jadi, developer perlu membedakan kode yang khusus untuk Windows, Linux, dll.

Atau, membuat versi khusus untuk mendistribusikan softwarenya, yang pastinya tidak efektif.

Cross-platform (1)

Ada bahasa program yang memang kompatibel di berbagai sistem operasi, berkat bantuan "VM". Singkatnya, program tersebut bisa dijalankan di berbagai sistem operasi, dengan catatan pengguna akhir harus memiliki "Virtual Machine" di sistem operasinya.

Bahasa program tersebut bernama Java. Java bukanlah bahasa program yang meng-kompilasi kodenya menjadi executable file. Melainkan, dia akan mengkompilasinya menjadi byte code yang mana nanti akan dieksekusi oleh Java Virtual Machine di runtime.

Yang intinya, cross-platform di aplikasi yang menggunakan bahasa program Java bekerja karena adanya JVM tersebut. Java adalah bahasa program High Level (yang memiliki syntax yang mudah dipahami oleh manusia), menggunakan static typing, dan bahasa program yang cukup mature.

Berkat itu, Java menjadi bahasa program favorit untuk developers & bisnis. Yang sayangnya, pengguna akhir perlu memasang Java (a.k.a. Java VM, Java Runtime Environment, dll).

Cross-platform (2)

Jika Java bergantung dengan JVM, ada bahasa program yang mendukung "cross-platform" dengan bantuan compiler. Salah duanya adalah C dan C++.

Singkatnya, kode ter-kompilasi menjadi executable file plus dengan (low-level) runtime untuk menjalankan kode tersebut.

2 Bahasa program yang disebut diatas adalah bahasa program lower-level. Selain karena syntax nya yang kurang mudah dimengerti, juga karena bahasa tersebut di-optimasi untuk mesin.

Kita sedang tidak membahas mata kuliah tentang Low-level vs High-level language disini, namun intinya, cross-platform disini berhasil dari proses kompilasi yang dilakukan oleh mesin/komputer.

Cross-platform (3)

Sekarang mari kita bertanya: "Apakah ada bahasa program yang tidak bergantung dengan spesifik VM, namun memiliki syntax yang mudah dimengerti oleh manusia?".

Singkatnya, ada.

Yakni teknologi web.

Aplikasi web (secara prinsip) bisa berjalan disemua peramban dan ditulis menggunakan "bahasa program" yang mudah dimengerti (secara semantik), yakni JavaScript. Menjawab pertanyaan diatas, bukan?

Sekarang, hampir semua pengguna yang menggunakan komputer pasti memiliki peramban/browser. Ini menjadi potensi untuk membuat sesuatu yang bisa memudahkan pekerjaan manusia, tanpa harus ambil pusing masalah kompatibilitas per-sistem operasi.

Pengguna memasang peramban untuk kebutuhan sehari-hari, bukan seperti JVM yang harus dipasang hanya untuk bisa menjalankan program yang ditulis menggunakan bahasa Java.

Yang artinya, entah pengguna tersebut seorang developer atau pengguna biasa, aplikasi yang dibuat diatas teknologi web bisa digunakan oleh siapapun.

Apakah pepaduan yang terlalu sempurna? Tentu tidak.

Setiap kelebihan pasti ada kekurangan, so here we go.

Web app drawbacks

Singkatnya: di Performa. Web pada dasarnya dibuat untuk menampilkan informasi (dalam bentuk dokumen html), bukan untuk melakukan proses komputasi yang berat.

Performa pada komputasi biasanya bergantung dengan mesin yang dimiliki oleh pengguna. Kita tidak akan membahas tentang How Browsers Works, tapi salah satunya, ada biaya khusus untuk bisa "menggambar" di Web, salah satunya.

Mungkin jika kamu membuat aplikasi sistem informasi sederhana—yang mana pengguna akhir hanya melakukan CRUD dasar di aplikasi mu—performa disini bukanlah masalah yang besar.

Beda ketika aplikasi yang kamu buat membutuhkan komputasi berat; Seperti yang berhubungan dengan kripto, "menggambar", dan lain sebagainya.

Contoh kasus: Figma

Figma singkatnya adalah aplikasi untuk membuat desain berdasarkan vector.

Fitur andalan Figma adalah kolaborasi secara real-time (thanks to internet), cross-platform (thanks to web technologies), dan data disimpan di cloud (should I say thanks here?).

Beda dengan Sketch yang serupa dengan Figma namun hanya untuk sistem operasi Mac, Adobe Illustrator namun tidak mendukung kolaborasi secara real-time, dan Affinity Designer yang menyimpan file nya di lokal.

Dimana letak kasus performa nya? Salah satunya di load time.

Ketika kamu membuka sebuah file — entah file di AI, Sketch, dsb — aplikasi membaca file tersebut, dan menampilkan "gambar" di layar.

Figma menggunakan Canvas + WebGL untuk me-render/menggambar data tersebut ke browser, pertanyaan pertama: Bagaimana gambar yang ditampilkan bisa konsisten disemua browser & OS?

Pertanyaan kedua: Berapa lama aplikasi tersebut bisa membuka & menampilkan file tersebut?

Figma menggunakan C++, dan untuk bisa menjalankannya di browser, sebelumnya Figma melakukan cross-compile via Asm.js.

Agar data yang ada digambar secara konsisten disemua browser & OS, Figma membuat rendering engine nya sendiri diatas WebGL.

Yang artinya, akan ada biaya tambahan khususnya di load time. Karena untuk me-render, Figma menggunakan cara nya sendiri daripada langsung menggunakan apa yang browser tawarkan.

Load time disini adalah dari inisialisasi aplikasi, mengunduh file desain, dan merendernya untuk pertama kali.

Dan setelah Figma menggunakan Web Assembly, load time mereka lebih cepat 3x dari yang sebelumnya. Salah satu alasannya adalah karena sekarang load time tidak sangat bergantung dengan aplikasi.

Karena kode-kode yang berhubungan dengan "native implementation" sudah ter-cache sebelumnya (File wasm di Figma yang bernama compiled_wasm.wasm berukuran 7.4MB (uncompressed) dan 1.67MB (compressed with Brotli) yang mana bukanlah ukuran yang kecil.

Ya, meskipun kita bisa juga meng-cache file JS (yang di compile via Asm.js), namun file JS tetaplah file JS.

Dengan menggunakan Wasm, kode di-compile menjadi low-level assembly-like yang mana secara singkatnya, proses eksekusinya hampir sama dengan performa native.

Dan ya, berada di browser thread yang berbeda.

Demo?

Slow down, satan.

Aku sengaja menjelaskan hal-hal yang gak berkaitan "langsung" dengan Wasm sebelumnya biar tau kapan kita menggunakan Wasm.

Jika kamu memiliki pertanyaan seperti "App gue lambat, kek nya harus pakai native-implementation nih", kemungkinan kamu sudah mengerti sedikit tentang kapan menggunakan Wasm.

Mari kita ambil contoh yang sederhana: MD5.

Singkatnya, MD5 adalah sebuah alogirtma untuk membuat hash.

Banyak contoh penggunaan nya, namun dalam konteks disini adalah untuk melakukan checksum.

Karena tentang hash, berarti kita berbicara tentang kriptografi juga.

Sedangkan, kriptografi adalah hal yang kompleks (dan berkaitan dengan yang kompleks). Dan seperti yang kita bahas sebelumnya, web (JavaScript secara spesifiknya) tidak dirancang untuk melakukan hal-hal kompleks.

Dan seperti yang kita tau juga, "native-implementation" memiliki performa yang cepat, gambaran contohnya mungkin seperti seberapa cepat orang sunda memahami bahasa sunda dengan orang jawa (yang baru belajar bahasa sunda).

Sebelum kita menyelam lebih lanjut, mari kita coba melihat perbedaan diantara keduanya (js vs "native"):

Untuk bisa meng-hash 123,916 huruf (247,832 B) implementasi menggunakan JavaScript memakan waktu 20ms dan yang menggunakan native (via Rust) hanya 1ms.

Sekarang, mari kita coba untuk melakukannya terhadap file berukuran 21MB yang memiliki format beragam dengan total baris 75,941 dan total huruf 1,939,922 yakni file access.log ku.

Dan inilah hasilnya:

Implementasi JS memakan 3,766ms (3.7 detik) dan Native memakan 402ms (< 1 detik).

Silahkan coba lakukan client-side checksum untuk file berukuran 666MB :)

Berikut file JS nya:

import { LitElement, html, css } from 'lit-element'
import { raw_to_md5 } from 'hell-rust'

import md5 from 'blueimp-md5'

class App extends LitElement {
  static get styles() {
    return css`
      textarea {
        box-sizing: border-box;
        height: 100px;
        padding: 0.5rem;
        width: 100%;
        font-family: inherit;
      }
    `
  }

  static get properties() {
    return {
      text: { type: String },
      jsTime: { type: String },
      wasmTime: { type: String }
    }
  }

  constructor() {
    super()
    this.text = ''
    this.jsTime = ''
    this.wasmTime = ''
  }

  handleInput(e) {
    this.text = e.target.value
  }

  md5Js(text) {
    const a = performance.now()
    const generate = md5(text)
    const b = performance.now()
    this.jsTime = b - a + 'ms'
    return generate
  }

  md5Wasm(text) {
    const a = performance.now()
    const generate = raw_to_md5(text)
    const b = performance.now()
    this.wasmTime = b - a + 'ms'
    return generate
  }

  render() {
    return html`
      <h2>Text to md5</h2>
      <p>
        Generate plain text to md5 hash powered by wasm (and js for benchmark)
      </p>
      <p>
        MD5 (js, blueimp-md5): ${this.text === '' ? '' : this.md5Js(this.text)}
        ${this.jsTime}
      </p>
      <p>
        MD5 (wasm, rust): ${this.text === '' ? '' : this.md5Wasm(this.text)}
        ${this.wasmTime}
      </p>
      <strong>Total words: ${this.text.length}</strong>
      <textarea
        placeholder="input here"
        @input="${this.handleInput}"
      ></textarea>
    `
  }
}

window.customElements.define('my-app', App)

Ini file Rust nya:

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn raw_to_md5(string: &str) -> String {
    let digest = md5::compute(string);
    format!("{:?}", digest)
}

#[test]
fn test_raw_to_md5() {
    let expected = "5eb63bbbe01eeed093cb22bb8f5acdc3";
    let actual = raw_to_md5("hello world");
    assert_eq!(actual, expected);
}

Di Rust, menggunakan dependensi md5 dan di JS menggunakan dependensi blueimp-md5.

Demo nya ada disini (namun gak ada perbandingan js vs wasm, males deploy lagi).

Dan sumber kode nya ada disini.

Penutup

Tulisan ini bukanlah "perkenalan" dengan Wasm, melainkan hanya sebatas "pratinjau" sedikit tentang Wasm. Web Assembly bukanlah silverbullet untuk semua masalah performa di web & juga bukan untuk mengganti JavaScript.

Banyak contoh penggunaan Wasm yang bisa kita terapkan di dunia web, bila kita bukan membuat "aplikasi" sistem informasi. Yang gue tau, kebanyakan aplikasi web "besar" di Indonesia adalah sebuah sistem informasi.

Kita membuat komponen-komponen yang berhubungan untuk membentuk sebuah informasi: E-commerce, situs media, dll.

Belum ada aplikasi-aplikasi (web) seperti the next Quip (collaborative document editing platform), the next Signal (e2e encryption messaging platform), the next Sketchfab (3D/AR/VR on the web), dsb.

Entah karena tidak ada pasarnya ataupun karena kapabilitas kita belum sampai situ.

Baik, bila pasar kita di E-commerce & situs media, mungkin penggunaan Wasm bisa berandil disini (tell your R&D departement!):

  • What if E-commerce use AR?
  • What if news site use interactive rich-interactive media?
  • What if (UGC) news site has reliable image & video editor?
  • Indonesia Podcast™ platform with built-in audio editor, anyone?

Kita bisa sedikit ber-inovasi, meskipun pasar nya gak ada. Yaa karena kita dominan lebih suka menggunakan produk luar yang kualitasnya terjamin, bukan?

Jika situs besar yang ada disini adalah E-commerce lagi, On-demand service lagi, berita lagi, mungkin kita sedikit sulit untuk ber-inovasi.

Kecuali untuk "implementasi inovasi" yang sudah dilakukan oleh orang luar :p

Gak akan ada inovasi, kita alergi sesuatu yang baru.

Tapi sesuatu yang (relatif) baru bernama Wasm ini menarik untuk kami, dan aku tertarik untuk penerapannya di negara kita.

Mungkin kita berfikir terlalu jauh, tapi gpp gak ada ruginya juga, toh?

Ditulisan selanjutnya kita akan membahas tentang Berkenalan dengan Web Assembly, bila Wasm menjadi topik yang menarik untukmu, probably join us?

Menikmati tulisan ini?

Blog ini tidak menampilkan iklan, yang berarti blog ini didanai oleh pembaca seperti kamu. Gabung bersama yang telah membantu blog ini agar terus bisa mencakup tulisan yang lebih berkualitas dan bermanfaat!

Pendukung

Kamu?