Pure Functions dan Efek Samping — Paradigma Fungsional Praktis, Part 2

Bobby Priambodo
Jul 20, 2017 · 5 min read

Artikel ini adalah bagian dari sebuah seri artikel tentang Paradigma Fungsional Praktis. Silakan lompat ke akhir artikel untuk melihat navigasi keseluruhan seri ini.

Salah satu frasa yang sering muncul saat mempelajari paradigma pemrograman fungsional adalah pure functions, sambil sesekali dibarengi oleh side effect. Pada artikel ini, kita akan mencoba mengupas tentang mereka.

Kemurnian, dan efek yang mengubah dunia

Salah satu karakteristik lain yang ada pada pemrograman fungsional adalah membangun program menggunakan pure functions — fungsi murni. Berikut definisi fungsi murni yang saya suka:

Fungsi murni adalah fungsi yang melakukan suatu operasi yang hasilnya hanya bergantung dari input fungsi tersebut.

Mari menggunakan Java untuk mengilustrasikan ini.

public class Arithmetic {
public static int add(int a, int b) {
return a + b;
}
}
Arithmetic.add(1, 2); // => 3
Arithmetic.add(1, 2); // => 3

Di atas, kita mendefinisikan sebuah class bernama Arithmetic yang memiliki sebuah static method add. Dari buku teks pemrograman kita, kita bisa tahu bahwa pemanggilan Arithmetic.add(1, 2) akan selalu menghasilkan 3, tidak peduli apa pun yang terjadi pada bagian program yang lain. Ia hanya menghitung keluaran berdasarkan argumen masukan method tersebut.

Sekarang, mari lihat contoh lain.

public class Counter {
private int counter = 0;

public void increment() { counter++; }
public int get() { return counter; }
}
Counter c = new Counter();
c.get(); // => 0
c.increment();
c.increment();
c.get(); // => 2

Pada kali ini, method increment dan get bukan merupakan pure function, karena keduanya bergantung pada sebuah variabel global counter. Nilai yang dikembalikan dari method get akan bergantung pada berapa kali pemanggilan increment telah dilakukan sebelumnya. Dalam dunia pemrograman, kita biasa menyebut perilaku method increment yang mengubah “dunia” di luar scope dari fungsi/method tersebut (misalnya mengubah variabel global) sebagai sebuah side effect — efek samping.

Selain mengubah variabel global, contoh side effect lain adalah segala hal yang program Anda lakukan untuk berkomunikasi dengan dunia luar, misalnya mencetak teks ke layar, membuat request HTTP, menulis ke sebuah file, dan mengambil data dari database.

Ini membawa kita pada definisi lain dari pure functions:

Fungsi murni adalah fungsi-fungsi yang tidak menimbulkan efek samping.

Mudah, bukan?

“Tunggu sebentar!” saya dengar pikiran Anda berseru lagi. Kalau mengambil data dari database adalah efek samping dan paradigma fungsional dibangun tanpa menggunakan efek samping, lalu apa gunanya? Kita tidak mungkin membuat sesuatu yang berarti tanpa efek samping. Pada akhirnya, program yang kita buat pasti punya pengaruh terhadap dunia luar.

Sekali lagi, Anda benar. Melakukan pemrograman dalam paradigma fungsional bukan berarti melakukan pemrograman tanpa efek samping. Paradigma fungsional lebih menekankan pada bagaimana kita mengontrol efek samping pada program kita.

Kalau Anda pernah mencoba pemrograman dalam bahasa Haskell (saya sangat menyarankannya paling tidak sekali!), Anda tentu akan pernah melihat fungsi sebagai berikut.

main :: IO ()
main = putStrLn "Hello, World!"

Kalau kita lihat deklarasi dari fungsi main, kita akan lihat bahwa main memiliki tipe data IO (). Di Haskell, fungsi-fungsi yang melibatkan input-output (I/O), seperti putStrLn yang mencetak teks ke layar, harus berada di dalam tipe data IO. (Note: saya menyederhanakan banyak hal pada penjelasan ini; nantikan penjelasan tentang monad seperti IO pada Haskell di artikel-artikel selanjutnya.)

Haskell mengontrol efek samping dengan memastikan bahwa fungsi-fungsi yang melibatkan efek samping mendapatkan perlakuan khusus. Hal ini memungkinkan kita mengetahui dengan cepat mana-mana saja fungsi yang memiliki efek samping ketika menyusuri sebuah codebase Haskell.

Namun apakah semua bahasa pemrograman “fungsional” sekeras Haskell untuk mengontrol efek samping program kita? Nyatanya tidak; bahasa seperti OCaml dan Elixir masih mengizinkan kita mencampur kode murni dan efek samping. Ini mendukung klaim saya, bahwa paradigma fungsional bukan tentang bahasa.

Pengontrolan efek samping pada bahasa-bahasa yang tidak menyediakan fitur seperti Haskell membutuhkan disiplin dari programmer. Tentukan pada level abstraksi mana Anda memperbolehkan adanya efek samping, dan mana yang dapat Anda representasikan hanya dalam fungsi murni.

Kenapa harus murni?

Jadi, kenapa kita harus mengontrol efek samping dan menggunakan fungsi murni? Ada tiga alasan yang sangat saya rasakan selama mengembangkan program dengan paradigma ini.

Mengurangi beban kognitif. Beban kognitif adalah banyaknya usaha mental yang kita keluarkan untuk memahami suatu hal. Penggunaan pure function berarti kita hanya butuh melihat scope suatu fungsi untuk bisa melihat apa yang ia lakukan. Bayangkan jika suatu fungsi sangat bergantung pada state dari berbagai macam tempat (misalnya instance variable, singleton, System.getCurrentTimeMillis(), dan sebagainya), kita harus tahu bagaimana kondisi mereka pada suatu waktu. Kita bahkan tak bisa yakin bahwa hanya fungsi kita yang menggunakan state tersebut! Ini akan membuat fungsi tersebut sulit untuk dimengerti (harder to reason about).

Memungkinkannya komputasi konkuren dan paralel. Tidak ada ketergantungan terhadap shared global state (dengan kata lain: stateless) memungkinkan program berjalan secara bersamaan pada lebih dari satu core atau mesin tanpa harus melakukan sinkronisasi atau locking — karena tidak ada yang harus disinkronisasi!

Memudahkan testing. Melakukan testing terhadap pure function hanya butuh mendefinisikan argumen-argumen fungsi tersebut dan melakukan assertion terhadap kembaliannya. Kita tidak butuh jungkir balik melakukan setup state seperti kondisi database, global variable, dan sebagainya untuk dapat melakukan test terhadap fungsi kita. Anda melakukan testing terhadap program Anda, kan? :D

Dengan penjelasan tersebut, kita telah membahas mengenai karakteristik kedua paradigma fungsional: kontrol efek samping program Anda. Buat fungsi murni sebanyak mungkin.

Latihan menyenangkan: coba lihat kode proyek yang sedang Anda kerjakan sekarang dan identifikasi mana saja fungsi atau method yang memiliki efek samping! Anda kemungkinan besar akan terkejut.

Apakah Anda menyukai yang Anda baca? Apa saya melewatkan sesuatu? Beritahu saya melalui kolom komentar!

Paradigma Fungsional adalah sebuah blog tentang berbagai hal yang berkaitan dengan paradigma pemrograman fungsional (functional programming) di dunia pengembangan software. Tulisan-tulisan di blog ini akan dimuat dalam Bahasa Indonesia, karena menurut saya resource untuk belajar paradigma fungsional dalam bahasa kita masih sangat kurang.

Apabila Anda tertarik untuk mengetahui lebih lanjut tentang dunia paradigma fungsional, silakan ikuti blog ini!

Paradigma Fungsional

Tentang paradigma pemrograman fungsional dalam Bahasa Indonesia.

)

Bobby Priambodo

Written by

Software Engineer at Traveloka. Functional programming and distributed systems enthusiast. Java, JavaScript, Elixir, OCaml, Haskell.

Paradigma Fungsional

Tentang paradigma pemrograman fungsional dalam Bahasa Indonesia.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade