Manajemen ketergantungan adalah masalah besar dalam OOP karena dua alasan berikut:
- Kopling ketat antara data dan kode.
- Penggunaan efek samping di mana-mana.
Sebagian besar programmer OO menganggap penggabungan ketat antara data dan kode sepenuhnya menguntungkan, tetapi ada biaya. Mengelola aliran data melalui lapisan adalah bagian yang tidak dapat dihindari dari pemrograman dalam paradigma apa pun. Menggabungkan data dan kode Anda menambah masalah tambahan bahwa jika Anda ingin menggunakan fungsi pada titik tertentu, Anda harus menemukan cara untuk mendapatkan objeknya ke titik itu.
Penggunaan efek samping menciptakan kesulitan yang serupa. Jika Anda menggunakan efek samping untuk beberapa fungsionalitas, tetapi ingin dapat menukar implementasinya, Anda tidak punya pilihan lain selain menyuntikkan ketergantungan itu.
Pertimbangkan sebagai contoh program spammer yang mengikis halaman web untuk alamat email lalu mengirimnya melalui email. Jika Anda memiliki pola pikir DI, saat ini Anda sedang memikirkan layanan yang akan Anda enkapsulasi di belakang antarmuka, dan layanan mana yang akan disuntikkan di mana. Saya akan meninggalkan desain itu sebagai latihan untuk pembaca. Jika Anda memiliki pola pikir FP, saat ini Anda sedang memikirkan input dan output untuk lapisan fungsi terendah, seperti:
- Masukkan alamat halaman web, keluarkan teks dari halaman itu.
- Masukkan teks halaman, tampilkan daftar tautan dari halaman itu.
- Masukkan teks halaman, tampilkan daftar alamat email pada halaman itu.
- Masukkan daftar alamat email, buat daftar alamat email dengan duplikat yang dihapus.
- Masukkan alamat email, buat email spam untuk alamat itu.
- Masukkan email spam, output perintah SMTP untuk mengirim email itu.
Ketika Anda berpikir dalam hal input dan output, tidak ada dependensi fungsi, hanya dependensi data. Itulah yang membuat mereka begitu mudah disatukan. Layer up berikutnya mengatur untuk output dari satu fungsi untuk dimasukkan ke input berikutnya, dan dapat dengan mudah menukar berbagai implementasi sesuai kebutuhan.
Dalam arti yang sangat nyata, pemrograman fungsional secara alami mendorong Anda untuk selalu membalikkan dependensi fungsi Anda, dan karena itu Anda biasanya tidak perlu mengambil tindakan khusus untuk melakukannya setelah fakta. Ketika Anda melakukannya, alat-alat seperti fungsi tingkat tinggi, penutup, dan aplikasi parsial membuatnya lebih mudah dicapai dengan pelat ketel yang lebih sedikit.
Perhatikan bahwa bukan dependensi itu sendiri yang bermasalah. Ketergantungan itu menunjuk ke arah yang salah. Lapisan berikutnya mungkin memiliki fungsi seperti:
processText = spamToSMTP . emailAddressToSpam . removeEmailDups . textToEmailAddresses
Tidak apa-apa untuk lapisan ini untuk memiliki dependensi yang dikodekan secara keras seperti ini, karena tujuan utamanya adalah untuk merekatkan fungsi-fungsi lapisan bawah bersama-sama. Mengganti implementasi sama mudahnya dengan membuat komposisi yang berbeda:
processTextFancy = spamToSMTP . emailAddressToFancySpam . removeEmailDups . textToEmailAddresses
Komposisi ulang yang mudah ini dimungkinkan oleh kurangnya efek samping. Fungsi lapisan bawah sepenuhnya independen satu sama lain. Lapisan berikutnya dapat memilih yang processText
sebenarnya digunakan berdasarkan beberapa konfigurasi pengguna:
actuallyUsedProcessText = if (config == "Fancy") then processTextFancy else processText
Sekali lagi, bukan masalah karena semua dependensi menunjukkan satu arah. Kita tidak perlu membalikkan beberapa dependensi agar semuanya menunjuk dengan cara yang sama, karena fungsi murni sudah memaksa kita untuk melakukannya.
Perhatikan bahwa Anda dapat membuat ini lebih banyak digabungkan dengan melewati config
lapisan paling bawah daripada memeriksanya di atas. FP tidak mencegah Anda dari melakukan ini, tetapi cenderung membuatnya lebih menyebalkan jika Anda mencoba.