Pengantar Functional Programming

Pengantar Functional Programming

“Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.” - CTO Oculus VR, John Carmack

Kita sudah mencapai Roma dengan paradigma object-oriented programming. Banyak masalah yang dapat diselesaikan dengan konsep class, properti, method, dan konsep-konsep lain dalam OOP. Mungkin sampai sini, Anda mengira OOP menjadi satu-satunya solusi konkret yang mudah untuk menyelesaikan masalah? Tahan dahulu!

JavaScript adalah bahasa pemrograman yang bersifat multiparadigma. Banyak paradigma pemrograman yang bisa Anda ikuti untuk menyelesaikan masalah menggunakan JavaScript. Dalam modul kali ini, kami akan membawa Anda pada paradigma yang lebih tegas dan terprediksi. Jika mencintai matematika, mungkin Anda akan jatuh cinta dengan paradigma functional programming.

Berikut adalah objektif pembelajaran yang akan dicapai pada modul ini.

  • Menjelaskan paradigma functional programming serta konsep pure function, high-order function, recursive, dan immutability.
  • Membedakan fungsi yang bersifat pure dan impure.
  • Menjelaskan cara kerja “perulangan” dengan konsep recursive.
  • Memerinci JavaScript array dan object method yang bersifat immutable.
  • Mengombinasikan penggunaan array method yang bersifat immutable untuk menyelesaikan sebuah permasalahan.

Sudah siap berkenalan dengan functional programming? Yuk, kita mulai!

Berkenalan dengan Functional Programming

Functional programming (selanjutnya disingkat menjadi FP) adalah paradigma pemrograman yang didasarkan pada fungsi matematika murni, yakni fungsi harus menghindari perubahan data sehingga selalu menghasilkan nilai sama ketika diberikan argumen sama. Dalam FP, fungsi adalah elemen utama yang digunakan untuk memecah kode dan membangun keseluruhan program. Dengan menerapkan konsep-konsep dalam FP, kita dapat membangun aplikasi menggunakan kode yang deklaratif (lebih simpel, tegas, dan terprediksi).

Sebagai gambaran untuk Anda yang belum tahu deklaratif dan imperatif (kebalikan dari deklaratif), simak contoh kode di bawah ini. Tujuan kode ini adalah menghasilkan nilai string baru dari nilai string yang sudah ada sebelumnya.

Sebagai orang yang baru belajar pemrograman, kita sering menggunakan cara for-loop untuk menyelesaikan masalah tersebut. Ketahuilah bahwa kode di atas bersifat imperatif, yakni untuk mencapai suatu tujuan, kita perlu menulis instruksi yang sifatnya langkah demi langkah. Kita perlu mendefinisikan cara melakukan perulangan, waktu perulangannya harus berhenti, hingga mengisikan nilai ke array baru. Dampaknya, kode yang ditulis menjadi banyak. Gaya imperatif memang fokusnya pada “how to solve”, bukan “what to solve”.

Lantas, bagaimana dengan gaya deklaratif?

Berikut adalah kode untuk menyelesaikan masalah yang sama, tetapi menggunakan gaya deklaratif.

Inilah bentuk dari kode deklaratif. Coba bandingkan dengan kode sebelumnya, tentu ini jauh lebih ringkas dan terlihat simpel. Inilah salah satu benefit ketika kita memecahkan masalah dengan gaya deklaratif yang notabene dianut dalam paradigma FP. Fungsi .map() yang Anda lihat di atas merupakan salah satu implementasi dari konsep-konsep dalam FP. Konsep utama dalam FP meliputi pure function, high-order function, recursion, dan immutability. Pada modul ini, Anda akan memahami cara kerja fungsi map yang merupakan implementasi dari konsep-konsep dalam FP.

Tantangan terberat dalam mempelajari FP adalah menghilangkan kebiasaan berpikir dari paradigma imperatif yang sudah sering kita anut. Tentu hal ini membutuhkan waktu yang panjang agar Anda benar-benar terbiasa dengan cara berpikir functional programming. Belajar FP dalam JavaScript sebetulnya bisa dilakukan secara perlahan. Anda masih bisa menggunakan konsep-konsep FP bersama paradigma yang lain, sebelum memutuskan seluruh solusi diselesaikan dengan FP.

Fungsi Sejati (Pure Function)

FP menawarkan banyak manfaat, selain membuat kode jadi lebih ringkas, kode yang Anda tulis akan lebih mudah untuk diuji. Sebab, dengan menerapkan FP, fungsi yang kita buat hasilnya selalu terprediksi. Untuk mencapai manfaat tersebut, hal dasar yang perlu kita terapkan adalah konsep pure function.

Pure function merupakan istilah bagi sebuah fungsi yang memiliki dua sifat berikut.

  1. Menghasilkan nilai yang sama setiap kali dipanggil dengan argumen yang sama.
    Contoh, ketika fungsi diberikan argumen X, ia harus selalu mengembalikan nilai Y meski dipanggil dalam kondisi dan waktu yang beda. Jadi, nilai yang dihasilkan oleh fungsi selalu terprediksi. Untuk mencapai ini, fungsi tidak boleh mengakses nilai di luar argumen dan variabel cakupan global.

  2. Tidak memiliki efek samping yang dapat memengaruhi keadaan di luar fungsi tersebut.
    Dalam konteks ini, efek samping merujuk pada segala perubahan yang dilakukan oleh fungsi pada variabel atau keadaan di luar cakupannya, seperti mengubah variabel global, berinteraksi dengan input dan output.

Jika tidak memenuhi sifat tersebut, fungsi akan dikategorikan sebagai impure function.

Oke. Setelah mengetahui sifat dari pure function dan sebaliknya, kita lakukan sedikit pemanasan. Coba tebak, kira-kira fungsi addWith di bawah ini termasuk pure function atau impure function?

Jika menjawab impure function, jawaban Anda benar! Fungsi addWith dikategorikan sebagai impure karena sifat pure function tidak terpenuhi.

  1. (X) Menghasilkan nilai yang sama setiap kali dipanggil dengan argumen yang sama.Contoh kode di atas menunjukkan bahwa nilai yang dikembalikan oleh fungsi addWith yang diberikan argumen 1 selalu berbeda. Hal ini dipengaruhi oleh keadaan variabel value yang selalu berubah setiap kali pemanggilan terjadi. Ups! Ada efek sampingnya juga di sini.
  2. (X) Tidak memiliki efek samping yang dapat memengaruhi keadaan di luar fungsi tersebut.
    Pemanggilan fungsi addWith memiliki efek samping. Selain mengubah variabel value, fungsi ini juga menulis sesuatu ke I/O melalui pemanggilan console.log. Efek samping ini membuat hasil dari pemanggilan fungsi tidak hanya bergantung pada argumen yang diberikan, tetapi juga keadaan di luar fungsi tersebut.

Bagaimana bentuk versi pure function dari addWith? Berikut kodenya.

Sekarang fungsi addWith menjadi pure function karena seluruh sifatnya telah terpenuhi.

  1. (✓) Menghasilkan nilai yang sama setiap kali dipanggil dengan argumen yang sama.
    Saat ini, fungsi addWith menerima dua argumen, yaitu value dan addingValue. Selama kedua nilai argumen tersebut sama, addWith akan mengembalikan nilai yang sama, kapan pun dan saat kondisi apa pun. Ini karena fungsi addWith sudah tidak bergantung pada nilai di luar dari cakupannya.
  2. (✓) Tidak memiliki efek samping yang dapat memengaruhi keadaan di luar fungsi tersebut.
    Fungsi addWith sudah tidak mengubah nilai di luar cakupannya, tetapi ia menghasilkan nilai baru. Dengan dihapusnya kode console.log dari dalam fungsi, ia juga sudah tidak melakukan operasi I/O yang dapat menyebabkan efek samping.

Agar Anda semakin paham membedakan pure function dan impure function, simak beberapa contoh fungsi dalam masing-masing kategorinya.

  1. // Mengubah nilai variabel global
  2. let count = 0;
  3. function increment() {
  4.   count++;
  5. }
  6.  
  7. // Mengakses waktu sistem
  8. function getCurrentTime() {
  9.   return new Date().toLocaleTimeString();
  10. }
  11.  
  12. // Mengubah status objek yang diterima sebagai parameter
  13. function updateUser(user) {
  14.   user.name = "Updated Name";
  15. }
  16.  
  17. // Menulis ke berkas
  18. const fs = require('fs');
  19.  
  20. function writeToFile(data) {
  21.   fs.writeFileSync('data.txt', data);
  22. }

Keuntungan menggunakan pure function termasuk kemampuan untuk mengoptimalkan kode melalui memoization, yakni hasil dari fungsi disimpan dan digunakan kembali jika input yang sama ditemukan. Teknik memoization termasuk praktik advance yang tidak akan kami jelaskan rinci di kelas ini. Sebagai informasi saja, dalam beberapa kasus, teknik memoization ini bisa meningkatkan performa secara signifikan. Jika Anda tertarik untuk mendalami teknik ini, artikel “Functional Programming: Understanding Memoization” menarik untuk dibaca.

Anyway, …

“Tidak memiliki efek samping” menjadi salah satu syarat yang menantang dari pure function. Nyatanya, dalam membuat aplikasi, interaksi dengan I/O selalu tidak bisa dihindari. Jika memang ada operasi yang perlu menghasilkan efek samping, menggunakan teknik advance bernama monad adalah solusi yang ditawarkan dalam FP. Namun, kita tidak akan membahas teknik tersebut secara detail, Anda bisa membaca artikel “What Are Monads in JavaScript” untuk memahami monad.

Tidak masalah jika kita belum 100% menulis kode yang pure dalam membuat fungsi. Sekali lagi, JavaScript termasuk bahasa multiparadigma. Tidak ada keharusan untuk mengikuti paradigma tertentu seutuhnya. Namun, setidaknya, dengan memahami prinsip FP dan benefit di dalamnya, kita membuat sebuah batasan untuk menjaga sebagian besar kode yang ditulis agar tetap pure.

Potensi Tersembunyi Sebuah Fungsi (High-Order Function)

Kita sudah memahami bahwa fungsi dalam JavaScript bersifat first-class citizen. Fungsi dapat diperlakukan sebagai expression yang dapat disimpan dalam sebuah variabel atau dikirim sebagai argumen fungsi lain. Hal ini membuka banyak potensi menarik karena kita bisa menggunakan fungsi secara leluasa.

Ada konsep dalam FP yang sangat mengandalkan kemampuan function expression. Konsep tersebut adalah high-order function (selanjutnya akan disingkat menjadi HOF). HOF adalah fungsi yang menerima fungsi lainnya sebagai argumen dan/atau mengembalikan sebuah fungsi lain. Umumnya, teknik HOF digunakan untuk berbagai hal berikut.

  • Mengabstraksi fungsi aksi dari sebuah proses asynchronous (kita akan belajar asynchronous dalam modul selanjutnya) dalam bentuk callback.
  • Membuat utility function, yaitu fungsi Array.map, Array.filter, Array.reduce, dan sebagainya.
  • Menerapkan teknik matematika, seperti currying dan function composition.

HOF memungkinkan kita untuk membuat fungsi yang fleksibel. Misalnya, kita bisa membuat fungsi apply yang menerima fungsi operation sebagai argumen untuk melakukan sebuah operasi pada dua nilai argumen lain.

Dengan HOF, kita bisa dengan mudah mengubah logika operasi tanpa harus mengubah struktur fungsi apply. Selain itu, kita juga bisa menambahkan kode lain di dalam fungsi apply sebelum sebuah operasi dipanggil jika dibutuhkan. Menarik, kan?

Oh iya, implementasi memoization pure function juga dilakukan dengan teknik HOF. Caranya adalah fungsi memoize menerima fungsi pure function sebagai argumen dan menyimpan hasil dari pemanggilan pure function untuk digunakan ketika terjadi pemanggilan ulang dengan argumen yang sama. Jadi, jika terjadi pemanggilan dengan argumen yang sama, cukup mengembalikan nilai dari yang sudah tersimpan.

Anda bisa jalankan kode di atas. Lihat perbedaan yang sangat signifikan dari waktu yang dibutuhkan untuk memanggil fungsi memoizedSumArray pertama kali dan kedua kalinya. Berikut adalah salah satu contoh output dari menjalankan kode di atas.

  1. Total: 12502500
  2. Memoized Sum First Call: 127.57ms
  3.  
  4. Total: 12502500
  5. Memoized Sum Second Call (Cached): 0.357ms

Hal lain yang umum dilakukan dengan HOF adalah membuat fungsi yang menerapkan teknik currying. Dengan teknik currying, sebuah fungsi biasanya tidak mengambil semua argumen secara langsung. Ia mengambil satu argumen dulu, lalu mengembalikan sebuah fungsi baru yang menerima argumen kedua, begitu seterusnya hingga seluruh argumen dimanfaatkan dan melakukan operasi secara utuh.

Berikut adalah contoh teknik currying pada fungsi adjectivfy dan multipleBy.

HOF juga bisa digunakan untuk komposisi fungsi, yaitu kita menggabungkan beberapa fungsi kecil menjadi satu fungsi yang lebih kompleks. Berikut adalah contoh praktik dari komposisi fungsi.

Contoh di atas menunjukkan bahwa compose adalah HOF yang menggabungkan dua fungsi menjadi satu fungsi baru yang menjalankan g terlebih dahulu dan kemudian f.

Sudah paham dengan HOF?

Secara tidak sadar, mungkin Anda juga sebetulnya sudah pernah memanfaatkan teknik HOF, tetapi belum mengenal namanya saja. Beberapa contoh HOF yang umum digunakan dalam JavaScript adalah penggunaan fungsi Array.map. Fungsi Array.map menerima sebuah fungsi sebagai argumen yang digunakan untuk memproses setiap elemen array. Fungsi Array.map mengembalikan array baru yang hasilnya adalah nilai dari pemanggilan fungsi pada setiap elemen array asli.

Aku Memanggil Diriku (Recursive)

Fakta menarik dari FP yang mungkin dapat mencengangkan Anda! Jadi, di dunia FP tidak ada yang namanya perulangan dengan menggunakan sintaks for atau while. Dalam bahasa pemrograman yang menerapkan functional seutuhnya, seperti Haskell, bahkan tidak tersedia sintaks semacam itu. Alasannya, ketika melakukan perulangan, seperti for dan while, dibutuhkan perubahan data yang biasanya dilakukan pada variabel semacam counter. Hal itu bertolak belakang dengan prinsip immutability (atau tidak boleh berubahnya data) yang harus diutamakan dalam FP. Lantas, apa yang ditawarkan FP jika memang butuh melakukan perulangan? Jawabannya adalah rekursi.

Rekursi (recursive) banyak digunakan dalam pemrograman fungsional karena merupakan cara yang alami dan satu-satunya untuk melakukan perulangan atau mengiterasi data. Rekursi dapat menghasilkan solusi yang lebih elegan untuk menyelesaikan banyak masalah. Bagaimana sebetulnya rekursi?

Rekursi adalah teknik sebuah fungsi memanggil dirinya sendiri sehingga operasi dalam fungsi tersebut terus berulang sampai mencapai kondisi tertentu untuk ia keluar dari perulangannya.

Mari kita ambil contoh, anggaplah kita ingin membuat fungsi yang dapat menghasilkan array berisi elemen deret angka dari 0 hingga n. Berikut adalah contoh implementasi jika kita menerapkan for loop.

Dengan cara di atas, masalah memang dapat terselesaikan, tetapi sekali lagi dalam FP tidak ada memperbolehkan perubahan data sehingga kita tidak bisa mengubah nilai dari variabel counter.

Lalu, bagaimana solusi yang ditawarkan dengan rekursi? Berikut jawabannya.

Pada contoh di atas, fungsi generateArray memanggil dirinya sendiri dengan argumen yang dikurangi satu dan operasi dalam fungsi tersebut terus berjalan hingga argumen n bernilai kurang dari 0. Perhatikan bahwa dalam fungsi ini tidak ada sama sekali proses mengubah data, tetapi hanya ada expression yang menghasilkan nilai baru pada setiap iterasi pemanggilan fungsinya.

Ketika menerapkan rekursi, penting menetapkan kondisi untuk ia berhenti memanggil dirinya sendiri. Jika tidak, iterasi tidak akan pernah berhenti dan dampaknya program akan error karena call stack dalam JavaScript runtime akan mencapai batasnya. Ini bisa diibaratkan Anda berada di tengah sebuah cermin yang merefleksikan bayangan Anda tanpa batas.

dos-3ffa696cc54ac457ed0210e84223df6520240730162855.jpeg

Rekursi adalah teknik yang manjur untuk menyelesaikan berbagai masalah. Tantangannya adalah dibutuhkan cara berpikir yang berbeda. Terutama jika terbiasa dengan menulis kode secara imperatif, kemungkinan Anda belum terbiasa dan menyampingkan rekursi sebagai solusi. Namun, untungnya JavaScript telah menyediakan banyak fungsi bawaan yang dapat digunakan untuk masalah iterasi data, seperti Array.mapArray.filter, atau Array.forEach sehingga kita tidak perlu membuat fungsi rekursi secara mandiri. Fungsi-fungsi tersebut juga di balik layar menerapkan prinsip-prinsip FP, salah satunya perihal immutability yang sudah kami singgung tadi.

Selanjutnya, mari kita bahas lebih detail immutability pada materi selanjutnya.

Yang Sudah Tercipta, Tak Bisa Diubah Lagi (Immutability)

Kita sudah mengetahui bahwa banyak benefit yang didapatkan ketika bisa menjaga kesucian sebuah fungsi (pure function). Menghasilkan efek samping, seperti mengubah sebuah data yang bersumber dari luar bisa menyebabkan fungsi menjadi impure. Untuk selalu menjaga bahwa fungsi selalu pure, dalam FP juga terdapat sebuah konsep bahwa segala yang sudah dibuat, tidak bisa diubah nilainya. Konsep ini disebut sebagai immutability.

Walau terdengar sedikit menyeramkan bagi kita yang sudah terbiasa mengubah data sesuka hati, sebenarnya konsep ini memiliki tujuan yang baik. Tujuannya adalah memastikan sebuah nilai tidak dapat diubah dengan mudah (atau bahkan tidak bisa). Tujuannya tentu untuk menghindari segala perubahan yang tidak terduga dan biasanya menjadi akar permasalahan, seperti bug.

Dalam JavaScript, kita dapat menerapkan prinsip immutability dengan menggunakan fungsi yang mengembalikan salinan baru, alih-alih mengubah data asli. Biasanya ini dilakukan ketika kita perlu mengubah data dari objek ataupun array. Namun, sebelum mengetahui berbagai fungsi yang dapat mendukung prinsip immutability, kita perlu tahu dulu fungsi-fungsi “bahaya” yang perlu diperhatikan kembali.

Fungsi yang Mengubah Data (Mutator Function)

Secara umum, perubahan data secara tidak sadar terjadi karena penggunaan beberapa fungsi bawaan JavaScript yang bersifat mengubah atau biasa disebut mutator function. Berikut adalah beberapa fungsi yang sering kita gunakan dan harus diperhatikan kembali ketika menerapkan prinsip immutability.

  1. Array.push: menambahkan elemen di akhir dari sebuah array.
  2. Array.pop: menghapus elemen terakhir dari sebuah array.
  3. Array.shift: menghapus elemen pertama dari sebuah array.
  4. Array.unshift: menambahkan elemen di awal dari sebuah array.
  5. Array.splice: menambahkan atau menghapus elemen di posisi tertentu dari sebuah array.
  6. Array.reverse: membalikkan urutan elemen dari sebuah array.
  7. Array.sort: mengurutkan elemen dari sebuah array.
  8. Object.assign: memodifikasi properti dari object.

Daftar fungsi di atas bersifat mutate, alias mengubah langsung data array asli. Tentu penggunaan method tersebut di dalam fungsi akan membuat fungsi menghasilkan efek samping.

Perhatikan contoh kode di bawah ini.

Fungsi max adalah fungsi yang mengembalikan elemen bernilai terbesar dari array yang dikirimkan melalui argumen. Sepintas, fungsi max terlihat pure karena tidak mengakses nilai selain dalam argumennya. Namun, karena dalam implementasinya kita menggunakan fungsi sort dan pop, fungsi max jadi memiliki efek samping, yaitu mengubah nilai array numbers yang diberikan melalui argumen. Efek samping ini mungkin saja tidak terduga karena tujuan fungsi tersebut hanya mengembalikan elemen yang paling besar.

Selain pada array, perubahan data juga banyak terjadi dalam object. Salah satunya adalah penggunaan fungsi Object.assign yang dapat mengubah nilai pada sebuah objek yang sudah terbentuk sebelumnya.

Anda bisa lihat bahwa fungsi registerEmail menambahkan properti email, baik pada personWithEmail maupun person.

Duplikasi alih-alih Mengubah Aslinya

Lalu, solusinya seperti apa? Untuk membuat kedua fungsi di atas kembali pure, kita tidak boleh memodifikasi nilai yang diberikan melalui argumen. Umumnya, hal ini dilakukan dengan menduplikasi nilai array atau objek dan menambahkan data baru, lalu kembalikan fungsi menggunakan nilai baru tersebut.

Secara umum, proses duplikasi data dapat dilakukan dengan mudah menggunakan sintaksis spread operator. Berikut adalah versi perbaikan dari fungsi max dan registerEmail agar bersifat immutate.


Immutable Array Methods

JavaScript telah menyediakan banyak fungsi bawaan yang dapat digunakan dan bersifat immutable. Untuk kasus umum, seperti pengelolaan data array, Anda dapat memanfaatkan beberapa fungsi berikut dan menjamin bahwa tidak timbul efek samping.

Array Map

Fungsi Array.map() adalah bawaan dari array yang sangat berguna dan banyak sekali digunakan. Fungsi ini dapat dipanggil dari sebuah data bertipe array dan menerima satu buah callback function.

  1. ['Harry', 'Ron', 'Jeff', 'Thomas'].map(() => { });

Callback function tersebut akan dipanggil sebanyak jumlah panjang array dan akan memiliki akses pada index array sesuai dengan iterasinya.

  1. ['Harry', 'Ron', 'Jeff', 'Thomas'].map((name) => { });

Fungsi map akan mengembalikan array baru. Nilai tiap item pada array yang dikembalikan dihasilkan dari kembalian callback function-nya.


Array Filter

Fungsi ini sangat berguna untuk melakukan proses penyaringan (filtering) terhadap nilai array yang ada. Bila Anda memiliki kasus ingin menghilangkan beberapa item dalam array berdasarkan spesifikasi tertentu, fungsi ini sangatlah cocok digunakan.

Cara kerja fungsi ini mirip seperti Array.map(). Namun, callback function dari fungsi ini harus mengembalikan boolean. Nilai boolean ini digunakan untuk menentukan item array lolos saring atau tidak.

Sama seperti fungsi map(), fungsi filter() juga akan mengembalikan array yang telah disaring dalam bentuk array baru.

Inilah contoh penggunaan ketika Anda ingin menghilangkan seluruh nilai false pada array sebagai berikut.

Contoh lain, penggunaan filter untuk menyaring array dari objek siswa yang layak mendapatkan beasiswa berdasarkan nilai skor yang didapat.


Array Reduce

Array.reduce digunakan untuk mengeksekusi fungsi reducer pada setiap elemen array dan hanya mengembalikan output satu nilai saja. Berikut adalah struktur dari penggunaan fungsi Array.reduce.

  1. array.reduce(callback(accumulator, currentValue, [currentIndex], [array]), [initialValue])
  2.  
  3. // [...] adalah opsional parameter

Callback function dari fungsi ini dapat diolah untuk manipulasi data currentValue dan menyimpannya pada accumulator. Selain itu, fungsi reduce juga memiliki nilai awal yang dapat didefinisikan pada bagian initialValue.

Inilah contoh penggunaan ketika kita ingin menjumlahkan total nilai siswa seperti di bawah ini.


Immutable Object

JavaScript menyediakan fungsi Object.freeze untuk membekukan objek sehingga tidak dapat diubah setelah dibuat. Melalui fungsi ini, kita bisa memastikan bahwa tidak ada perubahan yang dapat dilakukan pada objek tersebut.

Pada contoh di atas, kita menggunakan Object.freeze untuk membekukan objek user. Setelah objek dibekukan, setiap upaya untuk mengubah properti akan diabaikan (atau menghasilkan error jika mengaktifkan mode strict). Dengan demikian, kita dapat memastikan bahwa objek tidak akan bisa diubah secara tidak sengaja.

Namun, perlu diingat bahwa Object.freeze hanya membekukan tingkat pertama dari objek. Jika objek tersebut memiliki properti yang merupakan objek lain, properti tersebut masih dapat diubah. Untuk membuat objek benar-benar immutable, kita perlu membekukan setiap objek yang menjadi properti secara rekursi.

Rangkuman Functional Programming


Berkenalan dengan Functional Programming

Functional programming (selanjutnya disingkat menjadi FP) adalah paradigma pemrograman yang didasarkan pada fungsi matematika murni, yakni fungsi harus menghindari perubahan data sehingga selalu menghasilkan nilai sama ketika diberikan argumen sama. Dalam FP, fungsi adalah elemen utama yang digunakan untuk memecah kode dan membangun keseluruhan program. Dengan menerapkan konsep-konsep dalam FP, kita dapat membangun aplikasi menggunakan kode yang deklaratif (lebih simpel, tegas, dan terprediksi).

Konsep utama dalam FP meliputi pure function, high-order function, recursion, dan immutability.


Fungsi Sejati (Pure Function)

FP menawarkan banyak manfaat, selain membuat kode jadi lebih ringkas, kode yang Anda tulis akan lebih mudah untuk diuji. Sebab, dengan menerapkan FP, fungsi yang kita buat hasilnya selalu terprediksi. Untuk mencapai manfaat tersebut, hal dasar yang perlu kita terapkan adalah konsep pure function.

Pure function merupakan istilah bagi sebuah fungsi yang memiliki dua sifat berikut.

  1. Menghasilkan nilai yang sama setiap kali dipanggil dengan argumen yang sama.
    Contoh, ketika fungsi diberikan argumen X, ia harus selalu mengembalikan nilai Y meski dipanggil dalam kondisi dan waktu yang beda. Jadi, nilai yang dihasilkan oleh fungsi selalu terprediksi. Untuk mencapai ini, fungsi tidak boleh mengakses nilai di luar argumen dan variabel cakupan global.
  2. Tidak memiliki efek samping yang dapat memengaruhi keadaan di luar fungsi tersebut.
    Dalam konteks ini, efek samping merujuk pada segala perubahan yang dilakukan oleh fungsi pada variabel atau keadaan di luar cakupannya, seperti mengubah variabel global, berinteraksi dengan input dan output.


Potensi Tersembunyi Sebuah Fungsi (High-Order Function)

Fungsi dalam JavaScript bersifat first-class citizen. Fungsi dapat diperlakukan sebagai expression yang dapat disimpan dalam sebuah variabel atau dikirim sebagai argumen fungsi lain. Hal ini membuka banyak potensi menarik karena kita bisa menggunakan fungsi secara leluasa.

Ada konsep dalam FP yang sangat mengandalkan kemampuan function expression. Konsep tersebut adalah high-order function (selanjutnya akan disingkat menjadi HOF). HOF adalah fungsi yang menerima fungsi lainnya sebagai argumen dan/atau mengembalikan sebuah fungsi lain. Umumnya, teknik HOF digunakan untuk berbagai hal berikut.

  • Mengabstraksi fungsi aksi dari sebuah proses asynchronous (kita akan belajar asynchronous dalam modul selanjutnya) dalam bentuk callback.
  • Membuat utility function, yaitu fungsi Array.map, Array.filter, Array.reduce, dan sebagainya.
  • Menerapkan teknik matematika, seperti currying dan function composition.


Aku Memanggil Diriku (Recursive)

Rekursi (recursive) banyak digunakan dalam pemrograman fungsional karena merupakan cara yang alami dan satu-satunya untuk melakukan perulangan atau mengiterasi data. Rekursi adalah teknik sebuah fungsi memanggil dirinya sendiri sehingga operasi dalam fungsi tersebut terus berulang sampai mencapai kondisi tertentu untuk ia keluar dari perulangannya.


Yang Sudah Tercipta, Tak Bisa Diubah Lagi (Immutability)

Menghasilkan efek samping, seperti mengubah sebuah data yang bersumber dari luar bisa menyebabkan fungsi menjadi impure. Untuk selalu menjaga bahwa fungsi selalu pure, dalam FP juga terdapat sebuah konsep bahwa segala yang sudah dibuat, tidak bisa diubah nilainya. Konsep ini disebut sebagai immutability.

Walau terdengar sedikit menyeramkan bagi kita yang sudah terbiasa mengubah data sesuka hati, sebenarnya konsep ini memiliki tujuan yang baik. Tujuannya adalah memastikan sebuah nilai tidak dapat diubah dengan mudah (atau bahkan tidak bisa). Tujuannya tentu untuk menghindari segala perubahan yang tidak terduga dan biasanya menjadi akar permasalahan, seperti bug.


Video Functional Programming

Untuk memperdalam dan mempermudah pemahaman pada materi ini, Anda dapat menyimak video pembahasan berikut.

https://youtu.be/5z4RjiACs4Y?si=gorVA3e3BHn1TzKr



Bersambung ke:KUIS FUNGSIONAL PROGRAMMING

Comments