DEV Community

Cover image for Pemrograman Fungsional dan Platform Erlang
Muzhawir Amri
Muzhawir Amri

Posted on • Edited on • Originally published at muzhawir.com

Pemrograman Fungsional dan Platform Erlang

๐Ÿ“œ You can read the English version here!

Daftar Isi

Paradigma Pemrograman Fungsional

Setiap bahasa pemrograman dibangun di atas satu atau lebih paradigma pemrograman, yaitu cara berpikir yang memengaruhi bagaimana kita menulis kode, mengelola data, dan menyusun solusi. Memahami paradigma ini membantu kita memilih pendekatan yang paling efektif untuk menyelesaikan suatu masalah.

Mari kita bahas beberapa paradigma yang umum digunakan.

Imperative Programming

Paradigma imperative menggunakan pendekatan dengan memberikan instruksi langkah demi langkah kepada komputer tentang cara menyelesaikan suatu tugas. Kita mengatur urutan aksi secara eksplisit dan rinci, dari inisialisasi hingga eksekusi akhir.

Contoh dalam Python:

total = 0

for i in range(1, 6):
    total += i

print("Total:", total)
Enter fullscreen mode Exit fullscreen mode

Kode ini menjumlahkan angka dari 1 sampai 5. Semua prosesnya eksplisit: kita inisialisasi variabel, melakukan perulangan, menjumlahkan nilai, lalu mencetak hasil. Bahasa seperti Python, C, dan Java sangat mendukung paradigma ini.

Declarative Programming

Paradigma declarative menekankan pada apa yang ingin dicapai, bukan bagaimana langkah-langkah teknisnya. Kita menyatakan tujuan, dan compiler atau runtime yang mengurus detail prosesnya.

Contoh dalam SQL:

SELECT * FROM users WHERE is_active = 1;
Enter fullscreen mode Exit fullscreen mode

Di sini kita tidak menulis proses pengambilan data secara langkah demi langkah. Cukup nyatakan tujuannya, yaitu mengambil data pengguna yang aktif, dan SQL akan menangani detail implementasinya. Paradigma ini juga terlihat di HTML dan regular expressions, di mana kita mendeskripsikan hasil akhir tanpa menentukan alur proses secara eksplisit.

Object-Oriented Programming (OOP)

Paradigma object-oriented menyusun aplikasi sebagai kumpulan object. Masing-masing object menyimpan data (state) dan perilaku (method) untuk memproses data tersebut. Object-object ini saling berinteraksi membentuk logika aplikasi.

Contoh dalam Java:

class Car {
    String brand = "Toyota";

    void moveForward() {
        System.out.println(brand + " is moving forward -->");
    }

    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.moveForward();
    }
}
Enter fullscreen mode Exit fullscreen mode

Kita mendefinisikan class Car dengan atribut brand dan method moveForward(). Lalu kita membuat object myCar dan menjalankan method-nya. Bahasa seperti Java, Python, dan JavaScript mendukung paradigma ini dan mendorong modularitas serta penggunaan ulang kode (code reuse).

Functional Programming (FP)

Paradigma functional membangun program dari banyak function murni, yaitu function yang menerima input, menghasilkan output, dan tidak memiliki efek samping (no side effects). Artinya, hasil dari sebuah function hanya bergantung pada input yang diberikan, tanpa bergantung atau mengubah keadaan di luar dirinya. Data diproses melalui serangkaian function yang dapat dirangkai untuk membentuk logika yang lebih kompleks.

Contoh dalam Elixir:

numbers = [1, 2, 3, 4, 5]

numbers
|> Enum.filter(fn x -> rem(x, 2) == 0 end)
|> Enum.map(fn x -> x * 2 end)
Enter fullscreen mode Exit fullscreen mode

Kita mulai dengan list angka, lalu function filter mengambil elemen yang bernilai genap, dan hasilnya diteruskan ke function map untuk digandakan. Tidak ada variabel yang dimodifikasi, dan semua function bisa diuji secara independen. Bahasa seperti Elixir dan Erlang memang dirancang untuk mendukung gaya ini.

Paradigma yang Digunakan Erlang dan Elixir

Erlang dan Elixir menggabungkan dua paradigma utama:

  • Functional - Program disusun dari banyak function murni yang dapat dirangkai untuk membentuk logika yang kompleks.
  • Declarative - Kita fokus pada hasil akhir, bukan urutan instruksi. Detail eksekusi diserahkan kepada runtime.

Gabungan ini menciptakan kode yang ringkas, modular, dan mudah diuji. Cocok untuk membangun sistem berskala besar yang tangguh terhadap kesalahan (fault-tolerant), dapat berjalan secara terdistribusi di banyak mesin (distributed), dan tetap tersedia tanpa henti (high availability). Karena alasan ini, paradigma tersebut banyak digunakan dalam sistem telekomunikasi, aplikasi real-time, dan layanan backend yang menuntut reliabilitas tinggi.

Prinsip Dasar Pemrograman Fungsional

Pemrograman fungsional adalah pendekatan dalam menulis kode yang berbeda dari gaya imperatif. Dalam pendekatan imperatif, kita menulis perintah demi perintah: lakukan ini, lalu itu, ubah nilai ini, dan seterusnya. Sedangkan dalam pemrograman fungsional, kita fokus pada bagaimana data mengalir dan ditransformasikan melalui rangkaian function.

Kita membangun program dengan merangkai function kecil. Data dimasukkan ke dalam function, lalu function tersebut memproses dan menghasilkan nilai baru, yang kemudian bisa diteruskan ke function berikutnya. Pendekatan ini membuat alur program lebih jelas dan minim kejutan.

Agar model ini bekerja dengan baik, pemrograman fungsional menggunakan beberapa prinsip dasar berikut:

Immutability

Dalam pemrograman fungsional, data bersifat immutable. Artinya, sekali dibuat, nilai data tidak bisa diubah. Jika kita ingin โ€œmengubahโ€ sebuah nilai, sebenarnya yang terjadi adalah sistem membuat salinan baru yang sudah dimodifikasi, sementara data aslinya tetap utuh.

Pendekatan ini disebut data transformation, bukan modification, karena kita tidak mengubah data yang lama, melainkan membuat versi baru dari data tersebut.

Walaupun kita belum masuk ke materi Elixir, mari kita lihat sekilas contohnya. Di setiap contoh berikut, disertakan penjelasan ringkas tentang apa yang dilakukan oleh kodenya.

list = [1, 2, 3]
new_list = [0 | list]  # Hasil: [0, 1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

Variabel list tetap menyimpan [1, 2, 3], tidak berubah di memori. Sedangkan new_list adalah list baru hasil salinan yang menyisipkan 0 di awal. Nilai ini disimpan di lokasi memori yang berbeda.

Sifat immutability ini sangat bermanfaat:

  • Menghindari bug akibat data yang diam-diam berubah dari tempat lain
  • Alur data jadi lebih mudah dilacak dan dipahami
  • Tidak ada state tersembunyi yang sulit ditebak atau dikontrol

Pure Function

Pure function adalah function yang memiliki dua ciri utama:

  1. Output-nya selalu sama untuk input yang sama. Kapan pun dan di mana pun dipanggil, hasilnya pasti konsisten
  2. Tidak menimbulkan efek samping. Tidak mencetak ke layar tanpa perintah, tidak menulis file, tidak mengubah data di luar dirinya sendiri, dan tidak membaca nilai dari luar secara diam-diam

Contohnya dalam kode Elixir:

square = fn x -> x * x end
Enter fullscreen mode Exit fullscreen mode

Kode di atas adalah anonymous function yang disimpan dalam variabel square. Jika kita memanggil square.(4) beberapa kali, hasilnya akan selalu 16. Function ini tidak bergantung pada kondisi global dan tidak melakukan hal lain di luar perhitungan x * x.

Kenapa pure function penting?

  • Mudah diuji: cukup berikan input, lalu periksa hasil. Tidak ada pengaruh dari luar, jadi hasil selalu konsisten
  • Mudah dirangkai: karena tidak punya efek samping, kita bisa menggabungkannya tanpa takut terjadi gangguan antar function
  • Mudah dipahami: kita bisa membaca isi function tanpa harus tahu konteks global aplikasi

Tentu tidak semua function bisa murni. Menulis ke file, mengakses database, atau mengirim HTTP request semuanya memerlukan efek samping.

Di Elixir, dan banyak bahasa fungsional modern lainnya, kita tetap bisa menulis function yang melakukan efek samping. Tapi pendekatan yang dianjurkan adalah memisahkan efek samping dari logika inti program.

Artinya, sebanyak mungkin function kita buat tetap murni, hanya fokus mengolah data tanpa bergantung pada dunia luar atau mengubahnya. Sementara itu, function yang berhubungan dengan efek samping diletakkan di bagian yang secara khusus bertanggung jawab atas interaksi eksternal, contohnya seperti controller dalam aplikasi web yang menangani permintaan HTTP atau menulis ke file dan mengakses database.

Tujuannya agar sebagian besar kode tetap bersih, mudah diuji, dan bebas dari efek tak terduga. Kita tahu persis mana bagian kode yang bisa diuji secara murni, dan mana yang perlu dijalankan dalam konteks nyata seperti ketika berinteraksi dengan internet atau sistem berkas.

First-Class Function

Dalam paradigma fungsional, function diperlakukan seperti nilai biasa. Artinya, function bisa disimpan ke dalam variabel, dikirim sebagai argumen ke function lain, dan dikembalikan sebagai hasil dari function lain.

Contoh singkat dalam Elixir:

double = fn x -> x * 2 end

Enum.map([1, 2, 3], double)
Enter fullscreen mode Exit fullscreen mode

Di sini, double adalah anonymous function (function tanpa nama) yang disimpan dalam variabel. Lalu, pada function Enum.map, kita memanggil double sebagai argumen yang akan diterapkan ke setiap elemen list [1, 2, 3] ketika Enum.map dipanggil.

Platform Pengembangan Erlang

Sebelum kita belajar Elixir, penting untuk memahami platform tempat Elixir berjalan, yaitu Erlang. Tanpa Erlang, Elixir tidak akan bisa berfungsi.

Erlang adalah platform pengembangan yang dibuat oleh perusahaan telekomunikasi asal Swedia, Ericsson, pada pertengahan 1980-an. Tujuan awalnya adalah membangun sistem jaringan telepon yang mampu berjalan tanpa henti, bahkan dalam kondisi ekstrem seperti volume panggilan sangat tinggi, bug perangkat lunak, atau pembaruan perangkat keras dan lunak. Singkatnya, sistem harus tetap berjalan dan tersedia meskipun menghadapi berbagai gangguan.

Nama "Erlang" berasal dari singkatan Ericsson Language dan dikembangkan oleh tiga tokoh utama: Joe Armstrong, Robert Virding, dan Mike Williams. Awalnya hanya digunakan secara internal di Ericsson. Namun sejak dirilis sebagai perangkat lunak open source pada tahun 1998, Erlang mulai diadopsi secara luas di berbagai industri seperti telekomunikasi, perbankan, gim multiplayer, dan sistem real-time.

Seiring waktu, Erlang terbukti efektif dalam menangani sistem berskala besar yang membutuhkan ketersediaan tinggi dan toleransi kesalahan. Inilah mengapa Elixir memilih Erlang sebagai fondasi utamanya.

Sistem Yang Selalu Tersedia

Joe Armstrong pernah berkata dalam wawancaranya dengan Rackspace pada tahun 2013:

โ€œKalau Java itu tulis sekali, jalankan di mana saja. Erlang itu tulis sekali, jalankan selamanya.โ€

Pernyataan ini menggambarkan filosofi utama dari Erlang yaitu menciptakan sistem yang terus berjalan bahkan ketika sebagian komponennya mengalami gangguan.

Untuk mendukung hal tersebut, Erlang dirancang dengan prinsip-prinsip berikut:

  • Dapat menoleransi kesalahan (Fault Tolerant) - Sistem tetap berjalan meskipun ada proses yang gagal. Proses tersebut bisa digantikan atau dipulihkan secara otomatis.
  • Skalabilitas (Scalability) - Sistem dapat menangani lebih banyak beban tanpa perlu dihentikan, baik dengan menambah CPU, RAM, atau menjalankan node tambahan di mesin lainnya.
  • Sistem terdistribusi (Distributed System) - Erlang memungkinkan banyak node saling terhubung dan bekerja sebagai satu kesatuan. Ini memudahkan replikasi data, pembagian beban, dan juga mengantisipasi jika suatu saat terjadi single point of failure yaitu satu bagian sistem mengalami gangguan dan menjatuhkan seluruh layanan.
  • Responsif (Responsiveness) - Sistem Erlang dirancang untuk menangani beban berat dan permintaan tinggi dengan cepat, bahkan dalam situasi yang membutuhkan respons mendadak seperti lonjakan lalu lintas atau panggilan mendadak dalam jumlah besar.
  • Pembaruan langsung (Hot Code Swapping) - Erlang memungkinkan pembaruan kode secara langsung tanpa menghentikan layanan. Ini penting untuk sistem yang harus aktif terus menerus.

Konkurensi pada Erlang

Sejak awal, Erlang dirancang untuk menangani konkurensi dalam skala besar. Sistem seperti jaringan telepon, layanan perbankan, hingga platform komunikasi real-time harus mampu menjalankan banyak unit kerja secara bersamaan tanpa saling mengganggu.

Berbeda dari thread atau process sistem operasi yang kompleks dan berat, Erlang menggunakan entitas ringan yang disebut Erlang process. Proses ini bukan thread atau process dari OS, tapi unit kerja ringan yang dijalankan dan dijadwalkan oleh mesin virtual Erlang bernama BEAM.

Ukurannya sangat kecil dan bisa dibuat dalam jumlah sangat banyak bahkan jutaan, sehingga cocok untuk konkurensi masif. Kita bisa menjalankan banyak proses sekaligus secara efisien, dengan latensi rendah dan isolasi tinggi.

Beberapa keunggulan Erlang process:

  • Isolasi penuh antar proses - Setiap proses memiliki memori dan alur eksekusinya sendiri. Jika satu proses gagal, proses lain tetap berjalan seperti biasa. Karena tidak ada penggunaan memori secara bersama, tidak akan muncul efek samping atau intervensi antar proses.
  • Komunikasi asinkron berbasis pesan (Message Passing) - Semua proses berkomunikasi dengan cara mengirim pesan satu sama lain. Karena pesan dikirim sebagai salinan (bukan referensi ke data bersama), setiap proses bekerja dengan salinan datanya sendiri. Ini membuat kita tidak perlu repot mengatur kunci atau sinkronisasi seperti pada sistem berbasis thread. Tidak akan ada dua proses yang berebut data atau saling menunggu giliran, sehingga bebas dari kondisi balapan (race condition).
  • Garbage collection per proses - Setiap process punya manajemen memori sendiri, termasuk garbage collection (pengumpulan sampah memori). Artinya, ketika sebuah process sedang membebaskan memori yang tidak terpakai, proses lain tetap berjalan tanpa terganggu. Tidak ada situasi di mana semua proses harus berhenti hanya karena satu proses sedang merapikan memori.
  • Ringan dan efisien - BEAM bisa menjalankan jutaan process secara efisien. Erlang process sangat ringan dalam konsumsi memori dan CPU. Penjadwal internal BEAM akan mengatur waktu eksekusi secara adil di antara semua process.

Platform Pengembangan yang Lengkap

Erlang bukan sekadar bahasa pemrograman. Ia adalah platform pengembangan penuh yang mencakup empat komponen utama:

  1. Bahasa Erlang - bahasa pemrograman fungsional di platform ini. Kode Erlang dikompilasi menjadi bytecode yang dijalankan di atas mesin virtual BEAM.
  2. Mesin Virtual BEAM - mesin virtual yang menjalankan semua process Erlang (dan Elixir). BEAM menangani penjadwalan process, manajemen memori, komunikasi pesan, dan isolasi antar process.
  3. OTP (Open Telecom Platform) - sekumpulan pustaka dan abstraksi yang siap pakai untuk membangun sistem yang tangguh dan terstruktur. OTP adalah bagian tak terpisahkan dari Erlang, sehingga kombinasi keduanya sering disebut Erlang/OTP.
  4. Alat pengembangan - Erlang menyediakan alat seperti interactive shell (erl), debugger, profiler, dan masih banyak lagi. Semua alat ini membantu kita mengembangkan, menguji, dan merilis aplikasi di platform ini.

Erlang adalah proyek open source yang dikembangkan secara aktif dan dirilis secara berkala. Source code-nya tersedia di GitHub Erlang/OTP dan Ericsson masih terlibat langsung dalam pengembangannya.

Referensi

Top comments (0)