20 puan yazan carnoxen 2024-12-05 | 22 yorum | WhatsApp'ta paylaş

Özet

JPA/Hibernate, artık Java kodunda SQL yazmaya gerek bırakmadığı gerekçesiyle yaygın olarak kullanılan bir framework haline geldi. Ancak ben, yeni projelerde bunun kullanılmaması gerektiğini savunmak istiyorum.

Nedenler

Aşırı uzun resmî dokümantasyon

Resmî dokümantasyon PDF'e dönüştürüldüğünde tam 406 sayfa ediyor; bu da Yüzüklerin Efendisi'nden (231 sayfa) ve SQL standart dokümanından (288 sayfa) daha uzun. Veritabanı sorgularını öğrenmek için yüksek lisans yapmaya gerek yok.

Değiştirilebilirlik

  1. Bir entity belirli bir öğeye ihtiyaç duysa bile, parametresiz bir constructor zorunlu tutulur.
  2. Entity sınıfına final, abstract anahtar sözcüklerini ekleyerek kalıtımı engelleyemezsiniz.
  3. Reflection/Introspection, OOP'nin kapsülleme ilkesini yok sayar.
  4. Birisi kötü niyetli kod enjekte ederek verileri tamamen silebilir.

Lazy loading ve cache

  1. @Lazy anotasyonu, yeni başlayanlar için olabilecek en kötü tekniklerden biridir. Ancak domain tasarımı Hibernate ile uyuşmadığında ya da sorgu yazamadığınızda bundan kaçınmak zordur.
  2. Cache mekanizmasını anlamak zordur. Üstelik anlasanız bile, sorgu sonucunu değil entity'nin kendisini cache'e koymanız gerekir.

Bellek-veritabanı senkronizasyonu (Flush)

Flush adlı teknik, bellekte tutulan nesneler ile veritabanını senkronize eder. Bu da iki soruna yol açar.

  • Flush devreye girdiğinde bellekteki düzenlemeler tamamlanmış sayıldığı için, Hibernate dışındaki başka bir kalıcılık aracı kullanmak fiilen imkânsız hale gelir,
  • Flush sırasında çakışma olursa, kodla ilgisiz Stack Trace hataları ortaya çıkabilir.

Tek bir tablodan belirli sütunları almak

Bir entity içinden yalnızca tek bir sütuna erişmek istiyorsanız, SQL yaklaşımı şu kadar basittir.

select url from image   
where id = 'F462E8D9-9DF7-4A58-9112-EDE0434B4ACE';  

Ama Hibernate, varsayılan olarak entity'nin tüm sütunlarını getirir. Bunu önlemek için karmaşık süreçlerden geçmek gerekir.

Sütun constraint'lerini tanımlama

Bir sütun üzerindeki constraint'leri tanımlamak için aşağıdaki gibi birden çok anotasyon eklemek gerekir.

...  
    @NotNull  
    @NotEmpty  
    @Email  
    private String email;  
...  

Bu yaklaşım şu sorunlara yol açar.

  • Bu koşullar için unit test yazamazsınız.
  • Flush işlemi sırasında bu süreci anlamak için artık çok geçtir.
  • Ortaya çıkabilecek exception'lar geneldir ve pek işe yaramaz.
  • İş kurallarını yalnızca teknik kurallar olarak ele alır.

Stratejiyle ilgili sorunlar

  1. Framework güncellemeleri berbat olabilir, geriye dönük uyumluluğu göz ardı eder ve sizi koşulsuz bağımlı hale getirir. Bunu üreten şirket, tekelleşmek için kendi framework'ünü kullanmanın doğal olduğunu düşünmeye başlar. Bu kısır döngü durdurulmalıdır.
  2. Proof of Concept elde etmek için ille de framework'e dayanmak, yalnızca bakış açınızı daraltır; özellikle de JPA/Hibernate söz konusuysa. Buna zerre kadar tolerans gösterilmemelidir.

Ne yapmalı?

SQL kullanın

Yalnızca SQL ile her şey yapılabilir. Tüm programcılar bunu bilir, sorgular sezgiseldir ve framework gerekmez.

Yönetici Hibernate kullanın diyorsa?

İstifa edin ya da kodu framework'ten ayıracak bir çalışma yapın.

Zaten kullanıyorsanız...

  1. Varsayılan constructor ve setter'ların erişim düzeyini public yapmayın.
  2. SQL'in ürettiği kimlikler yerine UUID gibi string'ler kullanın.
  3. XXXRepository yerine XXXDao adını kullanın.
  4. @SequenceGenerator anotasyonunu kullanmayın.
  5. Domain sınıfları ile DAO sınıflarını interface ile ayırın.
  6. Çokluk ilişkilerini (@OneToMany vb.) kullanmayın; hatta mümkünse entity mapping'den kaçının.

Sonuç

JPA/Hibernate'ı bırakın.

  • İş problemlerini çözmek için daha kısa ve daha iyi dokümanlar var.
  • Tasarıma gereğinden fazla hızlı yöntemlerle saplanıp kalmayın.
  • Kodunuzu devralacak bir sonraki geliştiriciye karşı cömert olun.

Siz ne kullanıyorsunuz?

  1. JPA/Hibernate
  2. Başka bir ORM teknolojisi

22 yorum

 
askaskm 2024-12-16

JPA/Hibernate’ı bırakma görüşüne katılmıyorum.

"Çok uzun resmi dokümantasyon" kısmı
SQL de ilk öğrenildiğinde zordur. Karmaşık join’leri, alt sorguları, prosedür fonksiyonlarını vb. eksiksiz anlamak kolay mı?
JPA’de başlangıçta yalnızca temel kavramları anlayarak başlamak da yeterlidir. Daha derin konulara ihtiyaç olduğunda bakılabilir.
Ayrıca LLM’ler var.

"Değişkenlik ve Reflection sorunu"
Bu, framework’ün nasıl çalıştığını anlamamaktan kaynaklanan bir endişedir.
Pratikte bunun yüzünden gerçek bir sorun çıkması neredeyse hiç olmaz.
Aksine, Reflection sayesinde nesne eşleme otomatikleştirilir ve üretkenlik büyük ölçüde artar.

"Lazy loading ve cache"
@Lazy’nin "en kötü teknoloji" olduğunu mu söylüyorsunuz? N+1 sorununu çözmek ve performansı optimize etmek için çok faydalı bir özelliktir.
Cache mekanizması da aksine performans iyileştirmesine büyük katkı sağlar.

"Bir tablodan yalnızca belirli sütunları almak"
JPQL veya Projection kullanılırsa yalnızca gerekli sütunlar kolayca sorgulanabilir.
Ve QueryDSL ile birlikte kullanılabilir.

ORM’nin amacının SQL’in yerini tamamen almak değil, geliştiricinin iş mantığına daha fazla odaklanmasına yardımcı olmak olduğunu düşünüyorum..

 
bbulbum 2024-12-09

ORM konusunda karamsarım ama yeterince alternatif sunduğunu sanmıyorum.

İş ORM-yoğun ilerleyince gerçekten sonu gelmiyor; yukarıda da dendiği gibi, SQL dokümantasyonundan bile daha geniş bir doküman yığını içinde debelenirken tükenip gidebilirsiniz.

Son zamanlarda kişisel bir projede ORM kullanmadan geliştiriyorum ama yeniden kullanılabilirliği gözeten bir tasarım yapmaya çalışınca, bir noktada sanki kendi ORM’imi yapıyormuşum gibi bir yöne kayabildiğimi fark ediyorum. haha

 
ilbanin00 2024-12-07

Bir framework kullandığınız için, aynı framework’ü kullanan diğer geliştiricilerle ortak bir paradigma paylaşabilmeniz gibi bir noktanın, böyle şeyleri kullanmayın diyen yazılarda her zaman göz ardı edildiğini düşünüyorum.

 
dothx 2024-12-06

Tablo sayısı çoksa ve kolonlar da fazlaysa (örneğin 50 tablo ve tablo başına 100’den fazla kolon) SQL’i doğrudan kullanınca resmen cehennem başlıyor.

Ama küçük bir servis yaparken JPA/Hibernate kullanmak bana göre çok büyük bir israf.

Sonuçta bu tür görüşler de yine tamamen duruma göre değişiyor gibi.

(Burada verilen örnek de 3-4 kolonlu bir şey zaten...)

 
jpumpkin94 2024-12-06

Yukarıdaki yazıda son sorunun biraz düzeltilmesi gerekiyor gibi görünüyor.

Java ekosisteminde bunu 1. ORM ve 2. ORM dışı olarak özetleyebiliriz.

  1. ORM tarafında fiilen yalnızca JPA/Hibernate kombinasyonunun kullanıldığını söyleyebiliriz.
  2. MyBatis, JOOQ, SpringDataJDBC gibi seçenekler var. Bunlarda genelde SQL’i doğrudan siz yönetirsiniz.

Hem 1’in hem 2’nin belirgin artıları ve eksileri olduğu için, yukarıdaki yazıdaki gibi uç bir sonuca varmak uygun değil.

Bizim durumda ise,
ORM olan JPA/Hibernate/QueryDSL kullanırken aynı zamanda MyBatis de kullanıyoruz.

ORM ile mümkün olduğunca verimliliği artırırken,
ORM’in kapsamakta zorlandığı sorgular için MyBatis kullanıyoruz.

Ayrıca yukarıda 1 veya 2’den hangisini seçerseniz seçin, SQL’i iyi bilmeniz gerekir.

 
carnoxen 2024-12-06

Ben de düzeltmek isterdim ama sitede öyle bir özellik yok...

 
kallare 2024-12-06

Sanırım ORM’nin başta neden popüler hale geldiğini görmezden geliyor gibiler.

Öğrenme maliyeti biraz olsa da, alışınca üretkenlik artışının çok net olduğu bir gerçek.

SQL basitmiş gibi görünebilir ama SQL’i satır satır elle yazmanın yorgunluğu var... Üstelik tablo değişince ilgili sorguların da hepsini tek tek değiştirmek gerekiyor; bu yüzden SQL bakımı da asla kolay bir iş değil. Küçük ve basit göründüğü kadar iş yükü artıyor (zaten bu yüzden üretkenlik konusu sürekli gündeme geliyor).

Ayrıca SQL’de ortaya çıkan hatalar runtime’da patladığı için yakalaması da zor oluyor. SQL injection gibi saldırılara karşı savunmayı da tek tek elle yaparken, sonuçta sorgu üreten kodlar eklenmeye başlanıyor (genelde basit şablonlarla başlayıp...). Böyle devam edince sonunda yine ORM benzeri bir şey ortaya çıkacak; o zaman doğrudan ORM kullanmak daha mantıklı değil mi?

Birkaç gün önce paylaşılmış olan yazı aklıma geldi.
https://tr.news.hada.io/topic?id=17955

 
laracool 2024-12-06

Katılıyorum.
İnsanların ORM kullanma nedenini ve avantajlarını çoğu zaman yeterince iyi anlamadığını düşünüyorum.

Ayrıca, ORM üzerinden gerçekte çalıştırılan SQL’i analiz etmeye ya da anlamaya çalışan kişi sayısı da çok fazla değil gibi görünüyor.
Bunun, yalnızca bir kullanım kolaylığının ötesinde, SQL optimizasyonunu ve veritabanının nasıl çalıştığını derinlemesine anlamaya da yardımcı olabileceğinin daha fazla bilinmesi iyi olur.

 
jamsya 2024-12-06

Bence "kullanılmalı" ya da "kullanılmamalı" gibi iki uç noktaya kaymaya gerek yok haha;;
Ben, üretkenlik gerekiyorsa ORM'den yararlanıyorum,
ancak ORM ile karşılanamayan karmaşık sorguları veya daha fazla optimizasyon gerektiren sorguları raw query ile ele alıyorum.
Bence meselenin ORM mi yoksa raw query mi olduğu değil; hangi durumda neyi nasıl geliştireceğine göre uygun olanı seçmek.

 
xhfleodhkd 2024-12-06

Genel olarak, veritabanı normalizasyonu iyi yapılmışsa ve büyük ölçüde join gerektirmeyen veriler için bunun mümkün olduğunu düşünüyorum.
Ancak veritabanı normalizasyonundan başlayarak her şeyi bir DBA üzerinden düzgün şekilde yönetemiyorsanız, ORM de iyi bir seçenek olabilir diye düşünüyorum. Özellikle join ile alınan tarafta relationship olarak getirmenin sağladığı avantajlar, insanı neden ORM kullanmaya yönelttiğini gösteren çok iyi bir örnek bence.
Elbette framework'lerin geliştiricinin gelişimini sınırlayabildiği ve bu yüzden framework bağımlılığını azaltmamız gerektiği görüşüne katılıyorum ama
kesin bir şekilde ORM hiç kullanmayalım denmesi fikrine kolay kolay katılamıyorum.
Sanki bütün şirketlerde DBA varmış ve hepsi DDD ya da TDD gibi düzgün metodolojilerle geliştirme yapıyormuş varsayımı yapılıyor gibi geliyor.
Pratikte iş ortamında gerçekten öyle yapılacak olsa, kodun ne kadar daha büyük bir karmaşaya dönüşeceğini kestiremiyorum.

 
aer0700 2024-12-06

Backend’i PYTHON ile geliştirirken neredeyse her seferinde SQLALCHEMY ya da DJANGO ORM kullanıyorum.
Doğrudan SQL yazmakla ORM kullanmak arasında, ikisine de alışınca çok fark yokmuş gibi geldiği için bunu pek düşünmemiştim. Ama ORM kullanmamak gerektiğini savunan görüşler de varmış.
Framework bağımlılığını azaltma fikrine katılıyorum. Sadece DJANGO ORM kullanmayı bilip SQL ile çalışmayı hiç bilmiyor olmamak gerekir...

 
beoks 2024-12-06

Hmm, pek öyle düşünmüyorum; ben karşı taraftayım. Şu anda yaklaşık 3 bin tablosu olan bir servisi işletiyorum ve domain o kadar karmaşık ki tek bir sorgu oluşturmak için bile temel olarak onlarca satır yazmam gerekiyordu. Buna dinamik sorguları da ekleyince iş gerçekten baş ağrıtıcı hale geliyor. Karmaşıklık yüzünden çok hata çıkıyor ve bakım da zorlaşıyordu. Ben karmaşık domainlerde ORM'nin daha avantajlı olduğunu düşünüyorum.

 
xhfleodhkd 2024-12-06

Benim durumumda normalleştirilmemiş bir db’yi bakımını yapma deneyimim oldu.
O zaman dinamik sorguları ORM kullanmadan, normal SQL ile yazıyordum,
Böyle olunca kodun daha da anlaşılması zor hale geldiği durumlar oluyordu.
Yalnızca karmaşık domainlerde değil, normalleştirmenin yetersiz olduğu domainlerde de bunu uygulamaya almak için yeterince alan olduğunu düşünüyorum.

 
carnoxen 2024-12-06

Oh, o kadar da kötü bakmaya gerek yok sanırım.

 
tsboard 2024-12-06

Ben de kişisel olarak sadece SQL kullanmanızı tavsiye etmek isterim. JS dünyasında Prisma gibi araçlar çok kullanılıyor, ancak SQL o kadar da zor bir dil değil ve veritabanı I/O'su için fazla gereksiz soyutlama gerektiriyor gibi geldiğinden buna biraz mesafeli yaklaşıyorum.

 
znjadong 2024-12-06

Sanırım bunun nedeni, js/ts tarafındaki ORM'lerin özellikle çok aksak ürünler olması.

 
carnoxen 2024-12-06

Jdbc gibi bir şey yeterli olur herhalde, değil mi? Daha önce birlikte çalıştığım birinin "JPA yavaş, başka bir şey kullan" dediğini hatırladım.

 
roxie 2024-12-06

Efsane gibi bir hikâye.

 
caniel 2024-12-06

Framework'ler yerine temellere geri dönmek mi trend oluyor diye düşündürüyor.
HTMX, SQL falan...

 
carnoxen 2024-12-06

Ama tekerleği yeniden icat etmek zorunda kalma dezavantajı var.

 
misolab 2024-12-06

Avantajları da var tabii..
2. MyBatis (ORM değil ama haha)

 
carnoxen 2024-12-06

ORM yerine DAO'ya geçseymişim keşke.