Penulisan ulang Java ke Clojure

97

Saya baru saja diminta oleh perusahaan saya untuk menulis ulang aplikasi Java yang berukuran besar (50.000 baris kode) (aplikasi web menggunakan JSP dan servlet) di Clojure. Adakah orang lain yang mendapat tip tentang apa yang harus saya waspadai?

Harap diingat bahwa saya tahu Java DAN Clojure dengan cukup baik.

Memperbarui

Saya menulis ulang dan itu masuk ke produksi. Ini cukup aneh karena penulisan ulang berakhir begitu cepat sehingga selesai dalam waktu sekitar 6 minggu. Karena banyak fungsi yang tidak diperlukan, itu berakhir lebih seperti 3000 baris Clojure.

Saya mendengar mereka senang dengan sistem dan melakukan apa yang mereka inginkan. Satu-satunya downside adalah bahwa orang yang memelihara sistem harus mempelajari Clojure dari awal, dan dia diseret ke dalamnya sambil menendang dan menjerit. Saya memang mendapat telepon darinya beberapa hari yang lalu mengatakan dia mencintai Lisp sekarang .. lucu :)

Juga, saya harus memberi perhatian yang baik kepada Vaadin. Menggunakan Vaadin mungkin menyumbang sebanyak waktu yang dihemat dan sesingkat kode seperti yang dilakukan Clojure .. Vaadin masih merupakan kerangka kerja web teratas yang pernah saya gunakan, meskipun sekarang saya mempelajari ClojureScript dengan marah! (Perhatikan bahwa Vaadin dan ClojureScript menggunakan kerangka kerja GUI Google di bawah kap mesin.)

appshare.co
sumber
55
Saya ingin bekerja untuk perusahaan Anda.
mtyaka
4
Nah, beberapa perusahaan pertahanan di Eropa sudah mulai menggunakan Clojure (saya dengar). Tetapi tidak dapat mengingat nama apa pun :)
appshare.co
1
@Zubair: 50.000 LOC Java tidak mendekati "largish". Ini adalah proyek yang sangat kecil. Saya punya proyek Java 250KLOC hingga 300KLOC di sini dan itu berukuran sedang ... Paling banter.
SyntaxT3rr0r
5
Sebenarnya saya mungkin membuat kesalahan dengan menyebutkan ukuran basis kode karena pengurangan ukuran kode bukanlah tujuan penulisan ulang. Tujuannya ada dua: 1) agar basis kode lebih mudah dipahami dan dengan demikian lebih murah untuk memelihara kode 2) Memungkinkan pengguna alat untuk memperluas produk menggunakan editor Clojure di webbrowser (menggunakan eval dan kebaikan Clojure dinamis lainnya yang lebih mahal untuk lakukan di Java)
appshare.co
1
Hei ... baru saja melihat pertanyaan lama ini dan bertanya-tanya bagaimana penulisan ulangnya?
levand

Jawaban:

82

"Masalah translasi" terbesar mungkin akan beralih dari metodologi Java / OOP ke paradigma pemrograman Clojure / fungsional.

Secara khusus, alih-alih memiliki keadaan yang dapat berubah dalam objek, "Cara Clojure" adalah dengan jelas memisahkan keadaan yang dapat berubah dan mengembangkan fungsi murni (bebas efek samping). Anda mungkin sudah mengetahui semua ini :-)

Bagaimanapun, filosofi ini cenderung mengarah pada sesuatu dari gaya pengembangan "bottom up" di mana Anda memfokuskan upaya awal pada membangun seperangkat alat yang tepat untuk memecahkan masalah Anda, lalu akhirnya menyatukannya di akhir. Ini mungkin terlihat seperti ini

  1. Identifikasi struktur data utama dan ubah menjadi peta Clojure yang tidak dapat diubah atau definisi rekaman. Jangan takut untuk membuat banyak peta yang tidak dapat diubah - peta ini sangat efisien berkat struktur data yang persisten dari Clojure. Layak untuk menonton video ini untuk mempelajari lebih lanjut.

  2. Kembangkan pustaka kecil yang murni, fungsi berorientasi logika bisnis yang beroperasi pada struktur yang tidak dapat diubah ini (misalnya "menambahkan item ke keranjang belanja"). Anda tidak perlu melakukan semua ini sekaligus karena mudah untuk menambahkan lebih banyak nanti, tetapi akan membantu jika melakukan beberapa di awal untuk memfasilitasi pengujian dan membuktikan bahwa struktur data Anda berfungsi ..... dengan cara apa pun dalam hal ini titik Anda benar-benar dapat mulai menulis hal-hal yang berguna secara interaktif di REPL

  3. Kembangkan rutinitas akses data yang dapat mempertahankan struktur ini ke / dari database atau jaringan atau kode Java lama secara terpisah sesuai kebutuhan. Alasan untuk menjaga ini sangat terpisah adalah karena Anda tidak ingin logika ketekunan terikat dengan fungsi "logika bisnis" Anda. Anda mungkin ingin melihat ClojureQL untuk ini, meskipun juga cukup mudah untuk membungkus kode persistensi Java yang Anda suka.

  4. Tulis tes unit (misalnya dengan clojure.test ) yang mencakup semua hal di atas. Hal ini sangat penting dalam bahasa dinamis seperti Clojure karena a) Anda tidak memiliki banyak jaring pengaman dari pemeriksaan tipe statis dan b) ini membantu untuk memastikan bahwa konstruksi tingkat yang lebih rendah berfungsi dengan baik sebelum Anda membangun terlalu banyak di atasnya. di atas mereka

  5. Putuskan bagaimana Anda ingin menggunakan jenis referensi Clojure (vars, ref, agen, dan atom) untuk mengelola setiap bagian status tingkat aplikasi yang dapat berubah. Mereka semua bekerja dengan cara yang serupa tetapi memiliki semantik transaksional / konkurensi yang berbeda tergantung pada apa yang Anda coba lakukan. Referensi mungkin akan menjadi pilihan default Anda - mereka mengizinkan Anda untuk mengimplementasikan perilaku transaksional STM "normal" dengan membungkus kode apa pun dalam blok (dosync ...).

  6. Pilih keseluruhan kerangka kerja web yang tepat - Clojure sudah memiliki cukup banyak, tetapi saya sangat menyarankan Ring - lihat video yang luar biasa ini " One Ring To Bind Them " plus Fleet atau Enlive atau Hiccup tergantung pada filosofi templating Anda. Kemudian gunakan ini untuk menulis lapisan presentasi Anda (dengan fungsi seperti "terjemahkan keranjang belanja ini ke dalam fragmen HTML yang sesuai")

  7. Terakhir, tulis aplikasi Anda menggunakan alat di atas. Jika Anda telah melakukan langkah-langkah di atas dengan benar, maka ini akan menjadi sedikit yang mudah karena Anda akan dapat membangun seluruh aplikasi dengan komposisi yang sesuai dari berbagai komponen dengan boilerplate yang sangat sedikit.

Ini kira-kira urutan yang saya akan menyerang masalah karena secara luas mewakili urutan dependensi dalam kode Anda, dan karenanya cocok untuk upaya pengembangan "bottom up". Meskipun tentu saja dalam gaya gesit / iteratif yang baik Anda mungkin akan menemukan diri Anda mendorong lebih awal ke produk akhir yang dapat dibuktikan dan kemudian melompat kembali ke langkah sebelumnya cukup sering untuk memperluas fungsionalitas atau refactor sesuai kebutuhan.

ps Jika Anda mengikuti pendekatan di atas, saya akan terpesona mendengar berapa banyak baris Clojure yang diperlukan untuk mencocokkan fungsionalitas 50.000 baris Java

Pembaruan : Sejak posting ini awalnya ditulis, beberapa alat / perpustakaan tambahan telah muncul yang berada dalam kategori "harus diperiksa":

  • Noir - kerangka kerja web yang dibangun di atas Ring.
  • Korma - DSL yang sangat bagus untuk mengakses database SQL.
mikera
sumber
4
Nitpick re: "Putuskan jenis referensi STM Clojure mana yang ingin Anda gunakan untuk mengelola setiap bagian status tingkat aplikasi yang dapat berubah": Hanya ada satu jenis referensi STM. IRef lainnya tidak melibatkan STM. Jika tidak, sepertinya nasihat yang solid.
hmmm ... Kurasa aku menghitung ref, agen, dan atom sebagai bagian dari sistem konkurensi / STM Clojure. Misalnya mereka semua mendukung validator, dan agen terkoordinasi dengan komit transaksi. tapi saya mengerti maksud Anda, referensi adalah model transaksional "utama". akan membuat perubahan cepat.
mikera
2
Kalau saja saya bisa memberikan lebih banyak +1 ini. Saya menonton kedua video yang Anda referensikan, dan itu bagus. Terima kasih.
jdl
1
Sekarang noir sudah tidak digunakan lagi. Saya kira Anda harus menyebutkan tentang compojure, bukan noir.
hsestupin
Tautan Satu Cincin Untuk Mengikat Mereka rusak!
Adam Arold
5

Aspek apa dari Java yang termasuk dalam proyek Anda saat ini? Logging, Transaksi database, Transaksi deklaratif / EJB, lapisan web (Anda menyebutkan JSP, servlet) dll. Saya telah memperhatikan ekosistem Clojure memiliki berbagai kerangka kerja mikro dan perpustakaan dengan tujuan untuk melakukan satu tugas, dan melakukannya dengan baik. Saya menyarankan untuk mengevaluasi perpustakaan berdasarkan kebutuhan Anda (dan apakah itu akan meningkatkan skala dalam proyek-proyek besar) dan membuat keputusan yang tepat. (Disclaimer: Saya penulis bitumenframework ) Satu hal yang perlu diperhatikan adalah proses membangun - jika Anda memerlukan setup yang kompleks (dev, pengujian, pementasan, prod) Anda mungkin harus membagi proyek ke dalam modul dan memiliki proses membangun scripted untuk meredakan.

Shantanu Kumar
sumber
Servlets, JSP, kerangka kerja persistensi homebuilt (10 tahun) dan pojos, tetapi tidak ada EJB
appshare.co
4
Servlet dapat dengan mudah diganti dengan Ring + Compojure IMHO, dan JSP dapat diganti dengan mungkin StringTemplate (atau template FreeMarker / Velocity.) Kegigihan di Clojure akan berbeda dari Java. Jika Anda membutuhkan pemetaan relasional, Anda dapat melihat Clj-Record dan SQLRat (belum terlalu matang). ClojureQL hanya mendukung MySQL dan PostgreSQL saat ini AFAICT. Batasan saat ini di ccsql untuk melarang garis bawah dalam nama kolom mungkin mengejutkan. Saya pikir membahas aspek pengembangan pada daftar Clojure sebagaimana-dan-kapan-diperlukan akan berguna. Semoga berhasil dalam proyek ini!
Shantanu Kumar
Sejak proyek itu saya membuat aplikasi lain dengan Clojure dan Clojurescript (nemcv.com) dan saya menggunakan Ring sekarang, mencoba ClojureQL, tetapi beralih ke Korma untuk akses database. Anda dapat melihat karya terbaru di github.com/zubairq/coils
appshare.co
4

Saya menemukan bagian tersulit adalah memikirkan tentang database. Lakukan beberapa pengujian untuk menemukan alat yang tepat yang ingin Anda gunakan di sana.

LenW
sumber
1
Saya sudah mencoba clojureql untuk akses data, tetapi ini sama sekali berbeda dari akses database gaya Java yang semuanya berbasis objek. Hanya karena tertarik, akses database apa yang Anda gunakan untuk Java dan apa yang Anda gunakan dengan Clojure?
appshare.co
1
Kami akhirnya memikirkan kembali banyak hal dan menggunakan mongodb karena keteguhan struktur data clojure sangat alami
LenW