Apakah Database dan Pemrograman Fungsional bertentangan?

122

Saya telah menjadi pengembang web selama beberapa waktu sekarang, dan baru-baru ini mulai mempelajari beberapa pemrograman fungsional. Seperti orang lain, saya mengalami kesulitan yang signifikan dalam menerapkan banyak konsep ini pada pekerjaan profesional saya. Bagi saya, alasan utama untuk ini adalah saya melihat konflik antara tujuan FP untuk tetap tanpa kewarganegaraan tampaknya cukup bertentangan dengan fakta bahwa sebagian besar pekerjaan pengembangan web yang saya lakukan sangat terkait dengan database, yang sangat berpusat pada data.

Satu hal yang membuat saya menjadi pengembang yang jauh lebih produktif di sisi OOP adalah penemuan pemeta objek-relasional seperti MyGeneration d00dads untuk .Net, Class :: DBI untuk perl, ActiveRecord untuk ruby, dll. Hal ini memungkinkan saya untuk menjauh dari menulis pernyataan sisipkan dan pilih sepanjang hari, dan untuk fokus pada bekerja dengan data dengan mudah sebagai objek. Tentu saja, saya masih bisa menulis kueri SQL saat kekuatannya dibutuhkan, tetapi jika tidak, kueri tersebut diabstraksi dengan baik di belakang layar.

Sekarang, beralih ke pemrograman fungsional, sepertinya dengan banyak kerangka kerja web FP seperti Tautan memerlukan banyak penulisan kode sql boilerplate, seperti dalam contoh ini . Weblocks tampaknya sedikit lebih baik, tetapi tampaknya menggunakan semacam model OOP untuk bekerja dengan data, dan masih membutuhkan kode yang harus ditulis secara manual untuk setiap tabel dalam database Anda seperti dalam contoh ini . Saya kira Anda menggunakan beberapa pembuatan kode untuk menulis fungsi pemetaan ini, tetapi tampaknya jelas tidak seperti cadel.

(Perhatikan bahwa saya belum melihat Weblocks atau Link dengan sangat dekat, saya mungkin hanya salah paham bagaimana penggunaannya).

Jadi pertanyaannya adalah, untuk bagian akses database (yang saya yakini cukup besar) dari aplikasi web, atau pengembangan lain yang membutuhkan antarmuka dengan database sql, kita tampaknya dipaksa turun dari salah satu jalur berikut:

  1. Jangan Gunakan Pemrograman Fungsional
  2. Mengakses Data dengan cara yang menjengkelkan dan tidak abstrak yang melibatkan penulisan banyak kode SQL atau SQL ala Links secara manual
  3. Paksa Bahasa fungsional kita menjadi paradigma pseudo-OOP, sehingga menghilangkan beberapa keanggunan dan stabilitas pemrograman fungsional yang sebenarnya.

Jelas, tidak ada dari opsi ini yang tampak ideal. Sudah menemukan cara untuk menghindari masalah ini? Apakah benar-benar ada masalah di sini?

Catatan: Saya pribadi paling akrab dengan LISP di bagian depan FP, jadi jika Anda ingin memberikan contoh apa pun dan mengetahui beberapa bahasa FP, cadel mungkin akan menjadi bahasa pilihan yang disukai

NB: Untuk Masalah khusus untuk aspek lain dari pengembangan web, lihat pertanyaan ini .

Tristan Havelick
sumber
4
Lihat ClojureQL dan HaskellDB. Mereka adalah lapisan abstraksi yang memanfaatkan aljabar relasional.
Misa
10
Anda memulai dengan premis yang salah. Pemrograman fungsional adalah tentang mengelola keadaan secara eksplisit dan masuk akal. Sebenarnya, mereka bekerja sangat baik dengan database.
Lucian
3
SQL adalah salah satu bahasa yang berfokus pada pemrograman fungsional yang paling sukses, saya rasa tidak ada kesulitan yang melekat.
Douglas
3
# 2 dan # 3 Anda adalah dikotomi yang salah. Menulis SQL mentah bukanlah sesuatu yang harus dihindari, dan abstraksi melalui database tidak perlu OOP-esque.
Dan Burton

Jawaban:

45

Pertama-tama, saya tidak akan mengatakan bahwa CLOS (Common Lisp Object System) adalah "pseudo-OO". Ini adalah kelas satu OO.

Kedua, saya yakin Anda harus menggunakan paradigma yang sesuai dengan kebutuhan Anda.

Anda tidak dapat menyimpan data tanpa kewarganegaraan, sementara suatu fungsi adalah aliran data dan tidak benar-benar membutuhkan status.

Jika Anda memiliki beberapa kebutuhan yang bercampur, gabungkan paradigma Anda. Jangan membatasi diri Anda hanya dengan menggunakan sudut kanan bawah kotak peralatan Anda.

Svante
sumber
3
hanya untuk bersenang-senang, saya pikir saya akan menyebutkan datalog yang mencoba menjadi database yang lebih tanpa kewarganegaraan. itu mencatat semua tindakan, seperti "pengguna suka posting 1233." Tindakan ini menyelesaikan ke status sebenarnya dari database. Kuncinya adalah bahwa pertanyaan hanyalah fakta daripada mutasi ...
Chet
80

Datang dari perspektif orang database, saya menemukan bahwa pengembang front end berusaha terlalu keras untuk menemukan cara untuk membuat database sesuai dengan model mereka daripada mempertimbangkan cara paling efektif untuk menggunakan database yang tidak berorientasi objek atau fungsional tetapi relasional dan menggunakan teori-set. Saya telah melihat ini umumnya menghasilkan kode yang berkinerja buruk. Dan selanjutnya itu menciptakan kode yang sulit untuk disetel kinerja.

Saat mempertimbangkan akses database, ada tiga pertimbangan utama - integritas data (mengapa semua aturan bisnis harus ditegakkan di tingkat database bukan melalui antarmuka pengguna), kinerja, dan keamanan. SQL ditulis untuk mengelola dua pertimbangan pertama secara lebih efektif daripada bahasa front end mana pun. Karena memang dirancang khusus untuk melakukan itu. Tugas database jauh berbeda dengan tugas antarmuka pengguna. Apakah mengherankan jika jenis kode yang paling efektif dalam mengelola tugas berbeda secara konseptual?

Dan database menyimpan informasi penting untuk kelangsungan hidup perusahaan. Adalah mengherankan bahwa bisnis tidak mau bereksperimen dengan metode baru ketika kelangsungan hidup mereka dipertaruhkan. Banyak bisnis yang tidak mau mengupgrade ke versi baru dari database mereka yang sudah ada. Jadi ada konservatisme yang melekat dalam desain database. Dan memang sengaja seperti itu.

Saya tidak akan mencoba menulis T-SQL atau menggunakan konsep desain database untuk membuat antarmuka pengguna Anda, mengapa Anda mencoba menggunakan bahasa antarmuka dan konsep desain untuk mengakses database saya? Karena menurut Anda SQL tidak cukup mewah (atau baru)? Atau Anda tidak merasa nyaman dengannya? Hanya karena ada sesuatu yang tidak sesuai dengan model yang Anda rasa paling nyaman, tidak berarti itu buruk atau salah. Ini berarti bahwa itu berbeda dan mungkin berbeda untuk alasan yang sah. Anda menggunakan alat yang berbeda untuk tugas yang berbeda.

HLGEM
sumber
"SQL ditulis untuk mengelola dua pertimbangan pertama secara lebih efektif daripada bahasa front end mana pun." Oh benarkah? Lalu, mengapa kendala SQL masih tidak dapat melakukan hal-hal seperti ini ?
Robin Green
Tetapi pemicu bisa, itulah salah satu tujuan utama pemicu untuk dapat menangani kendala yang kompleks.
HLGEM
2
Saya akan memindahkan paragraf terakhir Anda sehingga menjadi paragraf utama. Poin yang sangat bagus, yang menggemakan apa yang juga didesak oleh orang lain, yaitu pendekatan multi-paradigma (bukan satu ukuran untuk semua).
pestophagous
31

Anda harus melihat kertas "Out of the Tar Pit" oleh Ben Moseley dan Peter Marks, tersedia di sini: "Out of the Tar Pit" (6 Februari 2006)

Ini adalah klasik modern yang merinci paradigma / sistem pemrograman yang disebut Pemrograman Relasional-Fungsional. Meskipun tidak secara langsung berkaitan dengan database, ia membahas bagaimana mengisolasi interaksi dengan dunia luar (database, misalnya) dari inti fungsional suatu sistem.

Makalah ini juga membahas bagaimana mengimplementasikan sistem di mana status internal aplikasi didefinisikan dan dimodifikasi menggunakan aljabar relasional, yang jelas terkait dengan database relasional.

Makalah ini tidak akan memberikan jawaban pasti tentang bagaimana mengintegrasikan database dan pemrograman fungsional, tetapi akan membantu Anda merancang sistem untuk meminimalkan masalah.

Kevin Albrecht
sumber
4
Kertas yang bagus. Tautan yang Anda berikan rusak (sementara?), Tetapi saya menemukan kertasnya juga di shaffner.us/cs/papers/tarpit.pdf
pestophagous
2
@queque Link asli masih mati. Saya memasukkan tautan baru ke dalam jawaban Kevin.
David Tonhofer
25
  1. Bahasa fungsional tidak memiliki tujuan untuk tetap tanpa kewarganegaraan, mereka memiliki tujuan untuk membuat pengelolaan negara menjadi eksplisit. Misalnya, di Haskell, Anda dapat menganggap monad State sebagai jantung dari status "normal" dan monad IO sebagai representasi dari status yang harus ada di luar program. Kedua monad ini memungkinkan Anda untuk (a) secara eksplisit mewakili tindakan berstatus dan (b) membuat tindakan berstatus dengan menyusunnya menggunakan alat transparan referensial.

  2. Anda mereferensikan sejumlah ORM, yang, sesuai namanya, database abstrak sebagai kumpulan objek. Sungguh, ini bukanlah yang diwakili oleh informasi dalam database relasional! Sesuai namanya, ini mewakili data relasional. SQL adalah aljabar (bahasa) untuk menangani hubungan pada kumpulan data relasional dan sebenarnya cukup "fungsional". Saya mengemukakan hal ini untuk mempertimbangkan bahwa (a) ORM bukan satu-satunya cara untuk memetakan informasi database, (b) SQL sebenarnya adalah bahasa yang cukup bagus untuk beberapa desain database, dan (c) bahwa bahasa fungsional sering memiliki aljabar relasional pemetaan yang mengekspos kekuatan SQL dalam mode idiomatik (dan dalam kasus Haskell, dicek typechnya).

Saya akan mengatakan kebanyakan lisps adalah bahasa fungsional orang miskin. Ini sepenuhnya mampu digunakan sesuai dengan praktik fungsional modern, tetapi karena tidak memerlukannya, komunitas cenderung menggunakannya. Hal ini mengarah pada campuran metode yang bisa sangat berguna tetapi jelas mengaburkan bagaimana antarmuka fungsional murni masih dapat menggunakan database secara bermakna.

J. Abrahamson
sumber
15

Saya tidak berpikir sifat stateless dari bahasa fp adalah masalah dengan koneksi ke database. Lisp adalah bahasa pemrograman fungsional non-murni sehingga seharusnya tidak ada masalah dalam menangani status. Dan bahasa pemrograman fungsional murni seperti Haskell memiliki cara untuk menangani input dan output yang dapat diterapkan menggunakan database.

Dari pertanyaan Anda, sepertinya masalah utama Anda terletak pada menemukan cara yang baik untuk mengabstraksi data berbasis record yang Anda dapatkan kembali dari database Anda menjadi sesuatu yang lisp-y (lisp-ish?) Tanpa harus menulis banyak SQL kode. Ini tampaknya lebih seperti masalah dengan perkakas / perpustakaan daripada masalah dengan paradigma bahasa. Jika Anda ingin melakukan FP murni, mungkin cadel bukan bahasa yang tepat untuk Anda. Cadel umum tampaknya lebih tentang mengintegrasikan ide-ide bagus dari oo, fp, dan paradigma lain daripada tentang fp murni. Mungkin Anda harus menggunakan Erlang atau Haskell jika Anda ingin mengikuti jalur FP murni.

Saya pikir ide 'pseudo-oo' di cadel memiliki kelebihannya juga. Anda mungkin ingin mencobanya. Jika mereka tidak sesuai dengan cara Anda ingin bekerja dengan data Anda, Anda dapat mencoba membuat lapisan di atas Weblocks yang memungkinkan Anda untuk bekerja dengan data Anda seperti yang Anda inginkan. Ini mungkin lebih mudah daripada menulis semuanya sendiri.

Penafian: Saya bukan ahli Lisp. Saya sangat tertarik dengan bahasa pemrograman dan telah bermain dengan Lisp / CLOS, Scheme, Erlang, Python dan sedikit Ruby. Dalam kehidupan pemrograman sehari-hari saya masih terpaksa menggunakan C #.

Mendelt
sumber
3
FP Erlang bukan murni menurut definisi kata apa pun. Anda menulis erlang dengan membuat banyak proses (semua berjalan secara paralel) yang mengirim pesan satu sama lain, seperti objek di, katakanlah, obrolan kecil. Jadi dari perspektif tingkat tinggi, ini bahkan mungkin tampak agak OO-ish, dan pasti memiliki status. Jika Anda memperbesar (ke dalam kode yang berjalan di dalam suatu proses) tampilannya lebih fungsional, tetapi masih belum sepenuhnya berfungsi, karena Anda dapat mengirim pesan (dan karenanya melakukan I / O dll) dari mana pun yang Anda inginkan, serta menyimpan " variabel global "(global ke proses, di dalam sesuatu yang disebut"
dikt
@Amadiro "pasti punya status". Tentu saja. Kami selalu memiliki negara bagian. Masalahnya bukanlah status, ini adalah status yang bisa berubah . Bagian yang baik dari "pemrograman fungsional" adalah tentang menyingkirkan representasi keadaan yang rapuh (misalnya contoh objek yang diubah oleh proses lain sementara kita memegang referensi ke sana, dengan cara non-transaksional untuk menambah penghinaan pada cedera). Erlang memiliki status non-mutable dan begitu memenuhi kriteria pemrograman fungsional ini. Dan dengan demikian: Database apapun jenisnya tidak pernah menjadi masalah. Database update adalah masalah (lihat juga jahat menegaskan dalam Prolog).
David Tonhofer
15

Jika database Anda tidak merusak informasi, maka Anda dapat bekerja dengannya secara fungsional sesuai dengan nilai pemrograman "fungsional murni" dengan bekerja dalam fungsi seluruh database sebagai nilai.

Jika pada saat T database menyatakan bahwa "Bob menyukai Suzie", dan Anda memiliki fungsi suka yang menerima database dan liker, maka selama Anda dapat memulihkan database pada saat T Anda memiliki program fungsional murni yang melibatkan database . misalnya

# Start: Time T
likes(db, "Bob")
=> "Suzie"
# Change who bob likes
...
likes(db "Bob")
=> "Alice"
# Recover the database from T
db = getDb(T)
likes(db, "Bob")
=> "Suzie"

Untuk melakukan ini, Anda tidak dapat membuang informasi yang mungkin Anda gunakan (yang dalam semua kepraktisannya berarti Anda tidak dapat membuang informasi), sehingga kebutuhan penyimpanan Anda akan meningkat secara monoton. Tapi Anda bisa mulai bekerja dengan database Anda sebagai rangkaian linear nilai diskrit, di mana nilai selanjutnya terkait dengan nilai sebelumnya melalui transaksi.

Ini adalah ide utama di balik Datomic , misalnya.

satwa
sumber
Bagus. Saya bahkan tidak tahu tentang Datomic. Lihat juga: alasan untuk Datomic .
David Tonhofer
12

Tidak semuanya. Ada genre database yang dikenal sebagai 'Database Fungsional', di mana Mnesia mungkin adalah contoh yang paling mudah diakses. Prinsip dasarnya adalah pemrograman fungsional bersifat deklaratif, sehingga dapat dioptimalkan. Anda dapat menerapkan gabungan menggunakan Pemahaman Daftar pada koleksi persisten dan pengoptimal kueri dapat secara otomatis mengetahui cara mengimplementasikan akses disk.

Mnesia ditulis dalam Erlang dan setidaknya ada satu kerangka kerja web ( Erlyweb ) yang tersedia untuk platform itu. Erlang secara inheren paralel dengan model threading yang tidak digunakan bersama, jadi dengan cara tertentu Erlang cocok untuk arsitektur yang dapat diskalakan.

ConcernedOfTunbridgeWells
sumber
1
Saya tidak berpikir itu adalah solusi yang bagus. Ada juga database berorientasi objek, tetapi biasanya, Anda ingin menyambungkan ke database SQL relasional biasa yang lama.
jalf
4
Anda masih memiliki ketidakcocokan impedansi dengan bahasa dan database OO dengan cara yang hampir sama seperti Anda memiliki ketidakcocokan impedansi SQL fungsional.
ConcernedOfTunbridgeWells
1
@ConcernedOfTunbridgeWells Saya akan dengan sewenang-wenang menyatakan bahwa ketidakcocokan impedansi ini adalah isapan jempol dari imajinasi orang-orang dengan palu yang membutuhkan segalanya untuk menjadi paku. Lapisan yang sangat tipis dan pengetahuan tentang SQL bisa sangat bermanfaat, karenanya jOOQ dan shims serupa.
David Tonhofer
6

Database adalah cara sempurna untuk melacak status dalam API tanpa negara. Jika Anda berlangganan REST, maka tujuan Anda adalah menulis kode stateless yang berinteraksi dengan datastore (atau backend lain) yang melacak informasi negara secara transparan sehingga klien Anda tidak perlu melakukannya.

Ide dari Object-Relational Mapper, di mana Anda mengimpor record database sebagai objek dan kemudian memodifikasinya, sama berlaku dan berguna untuk pemrograman fungsional seperti pada pemrograman berorientasi objek. Satu-satunya peringatan adalah bahwa pemrograman fungsional tidak mengubah objek pada tempatnya, tetapi API basis data dapat memungkinkan Anda untuk mengubah rekaman pada tempatnya. Alur kendali klien Anda akan terlihat seperti ini:

  • Impor catatan sebagai objek (API database dapat mengunci catatan pada saat ini),
  • Baca objek dan cabang berdasarkan isinya sesuka Anda,
  • Kemas objek baru dengan modifikasi yang Anda inginkan,
  • Teruskan objek baru ke panggilan API yang sesuai yang memperbarui record pada database.

Basis data akan memperbarui catatan dengan perubahan Anda. Pemrograman fungsional murni mungkin melarang penugasan ulang variabel dalam cakupan program Anda , tetapi API database Anda masih dapat mengizinkan pembaruan di tempat.

Brice Goreng
sumber
5

Saya paling nyaman dengan Haskell. Kerangka web Haskell yang paling menonjol (sebanding dengan Rails dan Django) disebut Yesod. Tampaknya memiliki ORM multi-backend yang cukup keren, aman untuk tipe, dan multi-backend. Lihat bab Ketekunan di buku mereka.

Honza Pokorny
sumber
0

Database dan Pemrograman Fungsional dapat digabungkan.

sebagai contoh:

Clojure adalah bahasa pemrograman fungsional berdasarkan teori database relasional.

               Clojure -> DBMS, Super Foxpro
                   STM -> TransactionMVCC
Persistent Collections -> db, table, col
              hash-map -> indexed data
                 Watch -> trigger, log
                  Spec -> constraint
              Core API -> SQL, Built-in function
              function -> Stored Procedure
             Meta Data -> System Table

Catatan: Di spec2 terbaru, spec lebih seperti RMDB. lihat: wiki spec-alpha2: Skema-dan-pilih

Saya menganjurkan: Membangun model data relasional di atas peta hash untuk mencapai kombinasi keunggulan NoSQL dan RMDB. Ini sebenarnya adalah implementasi kebalikan dari posgtresql.

Mengetik Bebek: Jika terlihat seperti bebek dan dukun seperti bebek, itu pasti bebek.

Jika model data clojure seperti RMDB, fasilitas clojure seperti RMDB, dan manipulasi data clojure seperti RMDB, clojure harus berupa RMDB.

Clojure adalah bahasa pemrograman fungsional berdasarkan teori database relasional

Semuanya RMDB

Menerapkan model data relasional dan pemrograman berdasarkan hash-map (NoSQL)

Lin Pengcheng
sumber