Buang JPA/Hibernate
(stemlaur.com)Ringkasan
JPA/Hibernate telah menjadi framework yang banyak digunakan karena membuat SQL seolah tidak lagi perlu ditulis langsung di kode Java. Namun, saya ingin berpendapat bahwa kita sebaiknya tidak menggunakannya pada proyek baru.
Alasan
Dokumentasi resmi yang sangat panjang
Jika dokumentasi resmi diubah ke PDF, panjangnya mencapai 406 halaman, lebih tebal daripada The Lord of the Rings (231 halaman) dan dokumen standar SQL (288 halaman). Seharusnya tidak perlu menempuh program magister hanya untuk mempelajari query database.
Mutabilitas
- Walaupun sebuah entitas membutuhkan elemen tertentu, ia tetap memaksa adanya konstruktor tanpa argumen.
- Dengan menaruh kata kunci
finalatauabstractpada kelas entitas, kita tidak bisa mencegah pewarisan. - Reflection/Introspection mengabaikan prinsip enkapsulasi dalam OOP.
- Seseorang bisa menyisipkan kode berbahaya dan menghapus data sepenuhnya.
Lazy loading dan cache
- Anotasi
@Lazyadalah salah satu teknik terburuk bagi pemula. Namun, sulit menghindarinya ketika desain domain tidak cocok dengan Hibernate atau saat query tidak bisa ditulis. - Mekanisme cache sulit dipahami. Bahkan jika sudah dipahami, yang harus disimpan di cache bukan hasil query melainkan entitas itu sendiri.
Sinkronisasi memori-database (Flush)
Teknik bernama Flush menyinkronkan objek yang disimpan di memori dengan database. Ini menimbulkan dua masalah.
- Saat Flush berjalan, perubahan di memori dianggap selesai, sehingga hampir mustahil memakai alat persistensi selain Hibernate, dan
- Jika terjadi konflik selama Flush, bisa muncul error Stack Trace yang tidak terkait langsung dengan kode.
Mengambil hanya kolom tertentu dari satu tabel
Jika Anda hanya ingin mengakses satu kolom dari suatu entitas, pendekatan SQL sesederhana ini.
select url from image
where id = 'F462E8D9-9DF7-4A58-9112-EDE0434B4ACE';
Namun Hibernate akan selalu mengambil semua kolom entitas. Untuk menghindarinya, Anda harus melalui proses yang rumit.
Mendefinisikan constraint pada kolom
Untuk mendefinisikan constraint pada satu kolom, Anda harus menempelkan beberapa anotasi seperti di bawah ini.
...
@NotNull
@NotEmpty
@Email
private String email;
...
Pendekatan ini menimbulkan masalah berikut.
- Kondisi ini tidak bisa diuji dengan unit test.
- Saat proses Flush berlangsung, sudah terlambat untuk memahami bagaimana proses ini ditangani.
- Pengecualian yang muncul bersifat umum dan tidak berguna.
- Aturan bisnis diperlakukan hanya sebagai aturan teknis.
Masalah strategis
- Update framework sangat buruk, mengabaikan kompatibilitas ke belakang, dan membuat kita bergantung sepenuhnya padanya. Perusahaan pembuatnya membuat penggunaan framework mereka sendiri terasa wajar demi monopoli. Lingkaran setan ini harus dihentikan.
- Mendapatkan Proof of Concept hanya melalui framework akan mempersempit cara pandang Anda, dan dalam kasus JPA/Hibernate hal ini lebih parah lagi. Tidak boleh diberi toleransi sedikit pun.
Lalu apa yang harus dilakukan?
Gunakan SQL
Semua bisa dilakukan hanya dengan SQL. Semua programmer mengetahuinya, query bersifat intuitif, dan tidak memerlukan framework.
Manajer menyuruh saya memakai Hibernate
Resign saja, atau kerjakan pemisahan kode dari framework.
Jika sudah terlanjur menggunakannya...
- Jangan buat tingkat akses konstruktor default dan setter menjadi
public. - Gunakan string seperti UUID alih-alih ID yang dihasilkan SQL.
- Gunakan nama
XXXDaoalih-alihXXXRepository. - Jangan gunakan anotasi
@SequenceGenerator. - Pisahkan kelas domain dan kelas DAO dengan
interface. - Jangan gunakan relasi banyak (*-many seperti
@OneToMany), dan kalau bisa hindari mapping entitas sama sekali.
Kesimpulan
JPA/Hibernate, buang saja.
- Ada dokumentasi yang lebih singkat dan lebih baik untuk menyelesaikan masalah bisnis.
- Jangan terpaku hanya pada cara desain yang terlalu terburu-buru.
- Berikan sedikit kemurahan hati kepada pengembang berikutnya yang akan memelihara kode Anda.
Apa yang kalian gunakan?
- JPA/Hibernate
- Teknologi ORM lain
22 komentar
Saya tidak setuju dengan pendapat yang mengatakan JPA/Hibernate harus ditinggalkan.
Bagian "dokumentasi resmi yang sangat panjang"
SQL juga sulit saat pertama kali dipelajari. Apakah mudah memahami join yang kompleks, subquery, serta fungsi prosedur dengan sempurna?
Untuk mulai menggunakan JPA, cukup memahami konsep intinya terlebih dahulu. Untuk hal yang lebih mendalam, bisa dicari saat memang dibutuhkan.
Dan ada LLM.
"Masalah mutabilitas dan Reflection"
Kekhawatiran seperti ini muncul karena tidak memahami cara kerja framework.
Dalam praktik kerja nyata, hampir tidak pernah muncul masalah yang benar-benar signifikan akibat hal ini.
Sebaliknya, berkat Reflection, pemetaan objek dapat diotomatisasi sehingga produktivitas meningkat secara signifikan.
"Lazy loading dan cache"
@Lazy adalah "teknologi terburuk"? Justru ini fitur yang sangat berguna untuk menyelesaikan masalah N+1 dan mengoptimalkan performa.
Mekanisme cache malah sangat membantu meningkatkan performa.
"Hanya mengambil kolom tertentu dari satu tabel"
Dengan menggunakan JPQL atau Projection, kita bisa dengan mudah mengambil hanya kolom yang dibutuhkan.
Dan bisa digunakan bersama QueryDSL.
Saya rasa tujuan ORM bukan untuk sepenuhnya menggantikan SQL, melainkan membantu pengembang agar bisa lebih fokus pada business logic..
Saya memang agak pesimistis terhadap ORM, tapi rasanya di sini juga belum berhasil menawarkan alternatif yang cukup memadai.
Kalau terlalu berat ke ORM, ujungnya memang bisa terasa tidak ada habisnya, dan seperti yang disebut di atas, kita bisa saja tenggelam lalu kehabisan tenaga di dalam dokumentasi yang cakupannya bahkan lebih luas daripada dokumentasi SQL.
Belakangan ini saya sedang mengerjakan proyek pribadi tanpa memakai ORM, tapi saat mencoba membuat desain yang mempertimbangkan reusability, kadang arah pengembangannya malah terasa seperti saya sedang membuat ORM sendiri. haha
Karena menggunakan framework, kita bisa membawa paradigma yang sama dengan pengembang lain yang juga menggunakan framework yang sama; rasanya poin ini selalu diabaikan dalam tulisan-tulisan yang menyuruh agar hal-hal seperti ini tidak dipakai.
Kalau tabelnya banyak dan kolomnya juga banyak (misalnya ada 50 tabel, dengan lebih dari 100 kolom per tabel), kalau pakai SQL mentah rasanya benar-benar seperti neraka.
Namun, saya rasa memakai JPA/Hibernate untuk membuat layanan kecil adalah pemborosan yang sangat besar.
Seperti biasa, pendapat seperti ini memang sangat tergantung kasusnya.
(Yang dijadikan contoh di sini juga cuma yang kolomnya 3~4 buah...)
Menurut saya, pertanyaan terakhir pada artikel di atas perlu sedikit diperbaiki.
Di ekosistem Java, ini bisa diringkas menjadi 1. ORM vs 2. non-ORM.
Baik 1 maupun 2 sama-sama punya kelebihan dan kekurangan yang jelas, jadi kurang tepat jika menarik kesimpulan yang ekstrem seperti pada artikel di atas.
Dalam kasus kami,
kami menggunakan MyBatis sekaligus sambil memakai ORM seperti JPA/Hibernate/QueryDSL.
Sambil memaksimalkan produktivitas dengan ORM,
untuk query yang sulit dicakup oleh ORM kami menggunakan MyBatis.
Dan apa pun yang dipilih antara 1 atau 2 di atas, Anda tetap harus memahami SQL dengan baik.
Saya juga sebenarnya ingin mengeditnya, tapi situsnya tidak punya fitur seperti itu...
Sepertinya Anda pura-pura tidak tahu alasan ORM bisa menjadi populer sejak awal.
Memang ada biaya belajar, tetapi setelah terbiasa, peningkatan produktivitasnya jelas ada.
SQL memang terlihat sederhana, tetapi rasa lelah saat harus menulis SQL satu per satu itu... ditambah lagi kalau tabel berubah, semua query terkait juga harus diubah satu per satu, jadi pemeliharaan SQL sama sekali bukan pekerjaan yang enteng. Semakin kecil dan sederhana, justru beban kerjanya makin besar (itulah sebabnya pembicaraan soal produktivitas terus muncul).
Selain itu, error yang terjadi di SQL meledak saat runtime sehingga sulit ditangani, dan ketika Anda satu per satu menambahkan pertahanan terhadap serangan seperti SQL injection, pada akhirnya kode untuk membangkitkan query akan ikut ditambahkan (biasanya dimulai dari bentuk template sederhana...). Kalau diteruskan, ujung-ujungnya akan muncul lagi sesuatu yang mirip ORM, jadi kalau begitu bukankah lebih baik langsung memakai ORM saja?
Ini mengingatkan saya pada tulisan yang sempat naik beberapa hari lalu
https://id.news.hada.io/topic?id=17955
Saya setuju.
Sepertinya cukup sering ada yang belum benar-benar memahami alasan menggunakan ORM dan kelebihannya.
Selain itu, tampaknya juga tidak banyak orang yang mencoba menganalisis atau memahami SQL yang benar-benar dieksekusi melalui ORM.
Akan lebih baik jika semakin banyak yang mengetahui bahwa ini bisa membantu bukan hanya dari sisi kenyamanan, tetapi juga untuk memahami optimasi SQL dan cara kerja database secara lebih mendalam.
Menurut saya, tidak perlu condong ke salah satu dari dua ekstrem: harus dipakai atau sama sekali tidak boleh dipakai haha;;
Kalau saya butuh produktivitas, saya memanfaatkan ORM,
tetapi untuk query kompleks yang tidak bisa dicakup oleh ORM atau query yang membutuhkan optimasi lebih, saya menanganinya dengan raw query.
Menurut saya, apakah memakai ORM atau raw query sebaiknya dipilih secara tepat sesuai situasi, tergantung apa yang ingin dibuat dan bagaimana cara membuatnya.
Secara umum, saya rasa itu bisa berlaku untuk data yang basis normalisasi DB-nya sudah baik dan tidak terlalu perlu banyak
join,tetapi jika mulai dari normalisasi DB sampai pengelolaan semua hal secara benar lewat DBA tidak memungkinkan, saya rasa ORM juga bisa menjadi pilihan yang baik. Terutama, manfaat yang muncul saat mengambil data melalui
relationshipdi sisi yang semula diambil lewatjoinmenurut saya adalah contoh yang sangat baik untuk menunjukkan mengapa orang akhirnya memakai ORM.Tentu saja saya setuju dengan pendapat bahwa framework membatasi pertumbuhan developer, dan karena itu ketergantungan pada framework perlu dikurangi,
namun saya tidak bisa dengan mudah setuju dengan pendapat yang mengatakan kita sama sekali tidak boleh memakai ORM.
Rasanya seperti berangkat dari asumsi bahwa semua perusahaan punya DBA dan dikembangkan dengan metodologi yang benar seperti DDD atau TDD,
kalau di praktik kerja nyata benar-benar dilakukan seperti itu, saya malah tidak tahu seberapa berantakan kodenya nanti.
Saat membuat backend dengan PYTHON, saya hampir selalu memakai SQLALCHEMY atau DJANGO ORM.
Entah menulis SQL secara langsung atau memakai ORM, setelah terbiasa rasanya tidak ada perbedaan besar, jadi saya tidak terlalu memikirkannya. Ternyata ada juga pendapat yang menyarankan untuk tidak menggunakan ORM.
Saya setuju dengan pendapat untuk mengurangi ketergantungan pada framework. Jangan sampai hanya bisa memakai DJANGO ORM tetapi tidak bisa menangani SQL...
Hmm, entahlah, saya tidak setuju. Saat ini saya mengelola layanan dengan sekitar 3.000 tabel, dan karena domainnya sangat kompleks, untuk membuat satu query saja pada dasarnya saya harus menulis puluhan baris. Kalau memikirkan query dinamis juga, itu benar-benar bikin pusing. Karena kompleks, bug juga sering muncul dan pemeliharaannya pun sulit. Saya rasa dalam domain yang kompleks, ORM lebih menguntungkan.
Dalam kasus saya, saya pernah punya pengalaman memelihara db yang tidak ternormalisasi.
Saat itu saya menulis kueri dinamis dengan SQL biasa tanpa memakai ORM,
dan akibatnya ada kalanya kode jadi lebih sulit dipahami.
Menurut saya, bukan hanya domain yang kompleks, tetapi domain yang kurang ternormalisasi juga cukup layak dipertimbangkan untuk diadopsi.
Oh, sepertinya tidak perlu memandangnya secara negatif.
Saya sendiri secara pribadi ingin merekomendasikan untuk langsung menggunakan SQL. Di dunia JS, banyak yang memakai alat seperti Prisma, tetapi SQL bukan bahasa yang sampai sesulit itu, dan saya agak enggan karena rasanya menuntut abstraksi yang terlalu tidak perlu hanya untuk I/O database.
Mungkin juga karena ORM di ekosistem js/ts memang banyak yang produknya terasa agak kurang matang.
Yang seperti
Jdbcsaja sudah cukup, kan? Saya jadi teringat seseorang yang pernah bekerja bersama saya dulu berkata, "JPA lambat, jadi pakailah yang lain."Terasa seperti cerita legenda.
Sepertinya tren sekarang memang kembali ke fundamental, bukan ke framework.
HTMX, SQL, dan lain-lain..
Meski ada kekurangannya karena harus membuat ulang roda dari nol.
Ada juga kelebihannya sih..
2. MyBatis (meski bukan ORM, hehe)
Harusnya saya ganti ke DAO, bukan ORM.