Pendahuluan

Ahead Of Time (AOT) compiler adalah konsep yang sering kita temui di perkembangan teknologi belakangan ini.

Misalnya :

  • Kalau kita pakai Angular, maka ada Angular AOT compiler, yang akan mengubah code HTML Angular dan code dalam TypeScript kita menjadi code JavaScript native, sehingga waktu page dijalankan di browser sudah menggunakan code JavaScript native dan sudah dioptimasi.

  • Kalau pakai Flutter, maka code kita dalam bahasa Dart akan dicompile memakai AOT juga ke code native, spesifik terhadap library arsitektur prosesor ARM dan x86.

  • Kalau pakai aplikasi berbasis framework Micronaut, maka code bahasa Groovy atau Java bisa dicompile dengan AOT compiler, memakai frameork Micronaut AOT, yang akan membuat code/binary native spesifik terhadap environment tertentu, sehingga lebih kecil ukuran binary, mengkomsumsi memori lebih rendah, dan optimasi lainnya.

  • Kalau pakai framework Spring Native/Spring 3, maka kita bisa mendapatkan file native executable dari code Java/Kotlin kita menggunakan bantuan compiler AOT native-image dari GraalVM. Native executable ini nanti bisa kita masukkan dalam container, seperti Docker, Podman, containerc, atau LXD.

  • Kalau kita pakai framework Quarkus untuk mendevelop aplikasi Java kita, kita akan juga akan menghasilkan code executable dengan bantuan library GraalVM Native Executable .

Jadi..

Kita bisa lihat bahwa Ahead Of Time Compiler ini melakukan hal sbb :

melakukan proses compile dari bahasa pemrograman level atas ke bahasa level machine sebelum program tersebut dieksekusi.

Tujuannya biasanya untuk :

  • Optimasi Code, sesuai dengan platform dimana code tersebut dieksekusi.
  • Ukuran file/artifact yang lebih kecil.
  • Penggunaan memori yang lebih kecil.
  • Efisiensi dari code dan sumber daya lainnya.

Loh, bukannya dari dulu memang seperti itu ?

Setiap kita membuat aplikasi dengan bahasa pemrograman tertentu, ujung-ujungnya akan dicompile ke bahasa level machine kan ?

Apa yang baru dari konsep AOT ini ?

Oh ok, sekarang kita perjelas lagi :

AOT melakukan proses kompilasi diatas pada saat build time, bukan pada saat runtime.

Apa lagi ini ??

Ok, sekarang kita coba lihat proses build secara umum :

flowchart LR subgraph b [ ] subgraph b1 [Build] direction LR b11(compile)-->b12(linking) end subgraph b2 [Runtime] direction LR b21(executing)-->b22(native code) end b0(SourceCode)-->b1-->b2 end

Loh, bukannya juga dari dulu memang seperti itu ?

Semua code dicompile dulu sebelum dieksekusi.

Jadi di waktu eksekusi, semua code sudah dalam bentuk optimasi dan code native spesifik terhadap mesin, arsitektur, tipe sistem operasi, dll.

Iya, betul.. tapi itu dulu sebelum ada namanya Multiplatform atau Cross Platform, dan sebelum dimunculkannya Optimasi Runtime seperti untuk kasus rendering, partial compiling, dll.

Maksudnya gimana ?

Coba kita lihat :



1. Multiplatform/Cross Platform

Seiring pertumbuhan teknologi, arsitektur, bahasa pemrograman, dll, maka bermunculan pulalah teknologi yang mengakomodasi banyak hal tersebut.

Istilahnya teknologi MultiPlatform.

Contohnya :

  • Java yang terkenal dengan Write once, run anywhere (WORA), mengklaim bahwa cukup dengan memakai satu bahasa Java saja, maka programnya bisa dijalankan di banyak platform, seperti di Window, Linux, Unix, dll.

  • Flutter, yang memakai bahasa pemrograman Dart, mengklaim bahwa dengan cuma satu source , maka bisa dijalankan di Android ataupun IoS.

  • .NET MultiPlatform App UI juga mengklaim hal yang sama, cukup dengan menggunakan platform .NET MAUI , maka akan bisa dijalankan di MacOs, Android, IoS, Windows, dll. .NET MAUI ini kelanjutan dari teknologi multiplatform Xamarin yang sebelumnya ada.

  • dll.


Teknologi multiplatform diatas , sangat memudahkan dari sisi Software Engineer.

Cukup satu repository code untuk banyak platform.

Tetapi tentunya ada proses tambahan yang harus dilakukan oleh framework-framework diatas agar bisa dijalankan di masing-masing platform.

Misalnya :

  • Harus ada Virtual Machine yang berfungsi sebagai broker/ program tambahan untuk menterjemahkan code yang umum tersebut ke code spesifik terhadap platform dibawahnya. Inilah yang biasanya kita lihat di Java Virtual Machine

  • Platform diatas tidak bisa langsung melakukan kompilasi terhadap kode sumber, sampai code tersebut siap untuk dijalankan atau sudah ditentukan platform yang akan digunakan. Istilahnya, proses kompilasinya paling efektif di waktu runtime.

  • Harus dilakukan pembedaan perlakuan antara aplikasi dijalankan di waktu development, dibandingkan dengan aplikasi sudah ready untuk dideploy ke production. Ketika development, perlu proses kompilasi code yang cepat dan hanya sebagian, sementara kalau sudah ready to production, diperlukan kompilasi code secara keseluruhan dan lengkap.

Oleh karena itu, maka proses kompilasi code akan diperlukan di 3 tempat :

  • Kompilasi code dari sintak bahasa awal, ke bahasa intermediary.
  • Kompilasi code dari bahasa Intermediary, ke bahasa Native, di waktu runtime, dan sebagian saja.
  • Kompilasi code dari bahasa awal/intermediary, ke bahasa Native, di waktu buildtime, dan lengkap.

Contoh :

  • Program .java dicompile menjadi .class
  • File-file .class di jalankan di Windows memakai Java Virtual Machine untuk Windows, dan secara otomatis akan dilakukan kompilasi lagi oleh JIT (Just In Time) compiler untuk class yang sedang di load pada saat itu.
  • Ketika kita ingin deploy ke production, dan perlu optimasi, maka kita bisa menggunakan fasilitas kompilasi AOT (Ahead Of Time) compiler, midalnya memakai GraalVM AOT compliler di saat build artifact dari file-file .java yang kita buat.


2. Optimasi di waktu development dan production

Seperti yang kita jelaskan diatas, bahwa proses development sebenarnya membutuhkan kompilasi source code yang cepat.

Hal ini karena pada proses Software Development masih banyak dilakukan perubahan, percobaan, dan modifikasi code sesuai dengan kebutuhan.

Walaupun semua source code perlu di-compile secara keseluruhan nantinya ketika akan naik ke production, akan tetapi pada waktu sebuah program dijalankan, sebenarnya hanya bagian tertentu dari aplikasi yang dibutuhkan.

Sementara bagian aplikasi yang lain sebenarnya ngganggur dan tidak digunakan.

Dan bisa jadi optimasi memang perlu dilakukan di waktu runtime tersebut, karena tergantung dari analisa code pada waktu itu, dicocokkan dengan platform dimana code tersebut dijalankan.

Sehingga muncullah konsep JIT (Just In Time) compiler, dan AOT (Ahead Of Time) compiler untuk kasus ini.

JIT (Just In Time) compiler, akan melakukan proses compile secara on the fly , atau ketika dibutuhkan saja, secara sebagian dari code kita.

Kalau kita mau lihat lagi bagan diatas, maka akan kita lihat sbb :

flowchart LR subgraph b [ ] subgraph b1 [Build Biasa] direction LR b11(compile)-->b12(linking) end subgraph b2 [Runtime] direction LR b21(executing)-->b22(native code) end subgraph c1 [Run Dengan JIT] direction LR c10(JIT compiler)-->c11(executing)-->c12(native code) end subgraph d1 [Build dengan AOT Compiler] direction LR d11(AOT compile) end b0(SourceCode)-->b1-->b2 b0(SourceCode)-->b1-->c1 b0(SourceCode)-->d1-->b2 end

Kita lanjut ke Part 2