JPA/Hibernate को छोड़ दें
(stemlaur.com)सारांश
JPA/Hibernate एक ऐसा framework बन गया है जिसका व्यापक उपयोग इस वजह से होता है कि Java code में अब SQL लिखने की ज़रूरत नहीं पड़ती। लेकिन मैं यह तर्क देना चाहता हूँ कि नए project में इसका उपयोग नहीं करना चाहिए।
कारण
बहुत लंबा आधिकारिक दस्तावेज़
आधिकारिक दस्तावेज़ को PDF में बदलें तो वह पूरे 406 पेज का है, जो The Lord of the Rings (231 पेज) और SQL standard document (288 पेज) से भी बड़ा है। Database query सीखने के लिए master’s degree करने की ज़रूरत नहीं होनी चाहिए।
परिवर्तनशीलता
- भले ही किसी entity को किसी एक तत्व की आवश्यकता हो, फिर भी वह बिना किसी argument वाले constructor को मजबूर करता है।
- Entity class में
final,abstractkeyword लगाने पर भी inheritance को रोका नहीं जा सकता। - Reflection/Introspection, OOP के encapsulation सिद्धांत को नज़रअंदाज़ करता है।
- कोई व्यक्ति दुर्भावनापूर्ण code डालकर पूरे data को पूरी तरह मिटा सकता है।
Lazy loading और cache
@Lazyannotation शुरुआती लोगों के लिए सबसे खराब तकनीकों में से एक है। लेकिन जब domain design Hibernate के साथ मेल नहीं खाता या query नहीं लिखी जा सकती, तब इससे बचना संभव नहीं होता।- Cache mechanism को समझना कठिन है। और यदि समझ भी लें, तब भी query result की जगह entity खुद को cache में रखना पड़ता है।
Memory-database synchronization (Flush)
Flush नाम की तकनीक memory में stored object और database को synchronize करती है। इससे दो समस्याएँ पैदा होती हैं।
- Flush काम करते ही memory के भीतर का edit समाप्त हो जाता है, इसलिए Hibernate के अलावा किसी दूसरे persistence tool की कल्पना भी नहीं की जा सकती, और
- Flush के दौरान conflict होने पर code से असंबंधित Stack Trace error आ सकती है।
एक table के केवल किसी खास column को प्राप्त करना
यदि आप किसी entity में केवल एक column तक पहुँचना चाहते हैं, तो SQL का तरीका इस तरह सरल है।
select url from image
where id = 'F462E8D9-9DF7-4A58-9112-EDE0434B4ACE';
लेकिन Hibernate हर हाल में entity के सभी column को query करता है। इससे बचने के लिए जटिल प्रक्रिया से गुजरना पड़ता है।
Column के लिए constraint परिभाषित करना
किसी एक column के लिए constraint परिभाषित करने के लिए नीचे की तरह कई annotation लगाने पड़ते हैं।
...
@NotNull
@NotEmpty
@Email
private String email;
...
यह तरीका निम्नलिखित समस्याएँ पैदा करता है।
- इस condition के लिए unit test नहीं किया जा सकता।
- Flush operation के दौरान इस प्रक्रिया को समझने के लिए तब तक बहुत देर हो चुकी होती है।
- जो exception आ सकते हैं वे सामान्य होते हैं और उपयोगी नहीं होते।
- Business rule को केवल technical rule की तरह संभाला जाता है।
रणनीति से जुड़ी समस्याएँ
- Framework का update सबसे खराब होता है, यह backward compatibility की अनदेखी करता है और बिना शर्त dependency पैदा करता है। इसे बनाने वाली company इस सोच को बढ़ावा देती है कि monopoly के लिए अपने framework का उपयोग करना स्वाभाविक है। इस vicious cycle को रोकना चाहिए।
- Proof of Concept को ज़बरदस्ती framework के माध्यम से ही हासिल करना केवल आपकी दृष्टि को सीमित करेगा, और खास तौर पर JPA/Hibernate के मामले में तो और भी ज़्यादा। इसे रत्ती भर भी स्वीकार नहीं करना चाहिए।
क्या करना चाहिए?
SQL का उपयोग करें
सिर्फ SQL से सब कुछ संभव है। हर programmer इसे जानता है, query सहज होती है, और किसी framework की आवश्यकता नहीं होती।
अगर manager Hibernate उपयोग करने को कहे तो?
नौकरी छोड़ दें, या code को framework से अलग करने का काम करें।
अगर पहले से उपयोग कर रहे हैं...
- Default constructor और setter की access level को
publicमत बनाइए। - SQL-generated ID की जगह UUID जैसी string का उपयोग कीजिए।
XXXRepositoryनाम की जगहXXXDaoनाम का उपयोग कीजिए।@SequenceGeneratorannotation का उपयोग मत कीजिए।- Domain class और DAO class को
interfaceसे अलग कीजिए। - *many-side relation (
@OneToManyआदि) का उपयोग मत कीजिए, बल्कि बेहतर है कि entity mapping से ही बचें।
निष्कर्ष
JPA/Hibernate को छोड़ दें।
- Business problem हल करने के लिए इससे छोटे और बेहतर दस्तावेज़ मौजूद हैं।
- Design को केवल बहुत तेज़ तरीकों तक सीमित मत रखिए।
- आपके code को संभालने वाले अगले developer पर दया कीजिए।
आप लोग क्या उपयोग करते हैं?
- JPA/Hibernate
- कोई दूसरी ORM तकनीक
22 टिप्पणियां
मैं JPA/Hibernate को छोड़ देने वाली राय से सहमत नहीं हूँ.
"बहुत लंबा official documentation" वाला हिस्सा
SQL भी जब पहली बार सीखते हैं तो मुश्किल लगता है. क्या complex join, subquery, procedure function वगैरह को पूरी तरह समझना आसान है?
JPA में शुरुआत में सिर्फ core concepts समझकर शुरू करना भी पर्याप्त है. ज़्यादा गहराई वाली बातें ज़रूरत पड़ने पर देखी जा सकती हैं.
और LLM भी हैं.
"mutability और Reflection की समस्या"
यह चिंता framework के काम करने के तरीके को न समझने से आती है.
व्यावहारिक काम में इसकी वजह से वास्तविक समस्या होने के मामले लगभग नहीं के बराबर हैं.
उल्टा Reflection की वजह से object mapping automate हो जाती है, जिससे productivity काफ़ी बढ़ती है.
"lazy loading और cache"
@Lazy को "सबसे खराब तकनीक" कहा जा रहा है? यह N+1 समस्या को हल करने और performance optimize करने में बहुत उपयोगी feature है.
cache mechanism भी performance बेहतर करने में काफ़ी मदद करता है.
"एक table के सिर्फ कुछ column लाना"
JPQL या Projection का उपयोग करें तो ज़रूरी columns को आसानी से query किया जा सकता है.
और इसे QueryDSL के साथ इस्तेमाल किया जा सकता है.
मेरे हिसाब से ORM का उद्देश्य SQL को पूरी तरह replace करना नहीं, बल्कि developer को business logic पर ज़्यादा ध्यान देने में मदद करना है..
मैं ORM का निराशावादी हूँ, लेकिन लगता है कि उन्होंने कोई पर्याप्त विकल्प भी पेश नहीं किया।
अगर आप बहुत ज़्यादा ORM-heavy तरीके से जाते हैं, तो सच में इसका कोई अंत नहीं होता, और ऊपर की बात की तरह आप SQL दस्तावेज़ों से भी कहीं ज़्यादा बड़े दस्तावेज़ों के दायरे में जूझते-जूझते सूख सकते हैं।
हाल ही में मैं एक personal project में ORM का इस्तेमाल किए बिना डेवलप कर रहा हूँ, लेकिन reusability को ध्यान में रखकर design करते-करते कभी-कभी ऐसा लगता है कि मैं बस खुद ही एक ORM बना रहा हूँ, haha.
किसी framework का इस्तेमाल करने से हम उसी framework का उपयोग करने वाले दूसरे डेवलपर्स के साथ एक साझा paradigm रख पाते हैं—मुझे लगता है कि कुछ भी इस्तेमाल न करने की बात करने वाले लेखों में इस बात को हमेशा नज़रअंदाज़ किया जाता है।
जब टेबल बहुत ज़्यादा हों और कॉलम भी बहुत हों (उदाहरण के लिए 50 टेबल हों, और हर टेबल में 100 से ज़्यादा कॉलम हों), तब अगर सीधे SQL लिखें तो हालात सचमुच नर्क जैसे हो जाते हैं.
लेकिन छोटे सर्विस बनाते समय JPA/Hibernate का इस्तेमाल करना मुझे बहुत बड़ी बर्बादी लगता है.
आखिरकार, ऐसे विचार भी केस-बाय-केस अलग लगते हैं.
(यहाँ जो उदाहरण दिया गया है, उसमें भी सिर्फ 3~4 कॉलम हैं...)
ऊपर के लेख में आख़िरी सवाल को थोड़ा संशोधित किया जाना चाहिए।
Java इकोसिस्टम में इसे 1. ORM बनाम 2. Non-ORM के रूप में व्यवस्थित करके देखा जा सकता है।
1 और 2, दोनों के फायदे और नुकसान स्पष्ट हैं, इसलिए ऊपर के लेख की तरह कोई चरम निष्कर्ष निकालना उचित नहीं है।
हमारे मामले में,
ORM के तौर पर JPA/Hibernate/QueryDSL का उपयोग करते हुए साथ में MyBatis भी इस्तेमाल करते हैं।
ORM का इस्तेमाल करके अधिकतम प्रोडक्टिविटी बढ़ाते हैं,
और जिन queries को ORM से कवर करना मुश्किल होता है, उनके लिए MyBatis का उपयोग करते हैं।
और ऊपर 1 या 2 में से जो भी चुनें, SQL की अच्छी समझ होना ज़रूरी है।
मैं भी इसे संपादित करना चाहता हूँ, लेकिन साइट पर ऐसी कोई सुविधा नहीं है...
लगता है कि लोग यह अनदेखा कर रहे हैं कि शुरुआत में ORM लोकप्रिय क्यों हुआ था।
सीखने की लागत थोड़ी होती है, लेकिन एक बार इसकी आदत पड़ जाए तो productivity में बढ़ोतरी साफ़ दिखती है।
SQL ऊपर से भले सरल लगे, लेकिन SQL को एक-एक लाइन हाथ से लिखते समय जो थकान होती है... ऊपर से अगर table बदल जाए तो उससे जुड़े query भी एक-एक करके बदलने पड़ते हैं, इसलिए SQL maintenance भी बिल्कुल आसान काम नहीं है। छोटा और सरल दिखने के बावजूद काम की मात्रा बढ़ जाती है (इसीलिए productivity की बात बार-बार साथ आती है)।
इसके अलावा, SQL में होने वाली errors runtime पर फटती हैं, इसलिए उन्हें पकड़ना भी मुश्किल होता है। SQL injection जैसे हमलों से बचाव भी एक-एक करके करना पड़ता है... ऐसा करते-करते अंत में query generate करने वाला code फिर से जुड़ जाता है (अक्सर किसी simple template के रूप में शुरू होकर...) और आगे बढ़ते-बढ़ते आखिरकार ORM जैसी कोई चीज़ फिर निकल आती है। तो फिर उसकी बजाय सीधे ORM का इस्तेमाल करना बेहतर नहीं है..?
मुझे कुछ दिन पहले यहाँ आया एक लेख याद आ गया।
https://hi.news.hada.io/topic?id=17955
मैं सहमत हूँ।
लगता है कि अक्सर लोग ORM का उपयोग करने के कारण और उसके फ़ायदों को पर्याप्त रूप से नहीं समझते।
इसके अलावा, ORM के ज़रिए वास्तव में चलने वाले SQL का विश्लेषण या उसे समझने की कोशिश करने वाले लोग भी ज़्यादा नहीं दिखते।
उम्मीद है कि यह बात और अधिक जानी जाएगी कि यह सिर्फ सुविधा से आगे बढ़कर SQL optimization और database के काम करने के तरीके को गहराई से समझने में भी मदद कर सकता है।
मुझे लगता है कि इसे इस्तेमाल करना ही चाहिए या बिल्कुल नहीं करना चाहिए—इन दो चरम सीमाओं में जाने की ज़रूरत नहीं है, हाहा;;
मेरे लिए, अगर productivity चाहिए तो मैं ORM का उपयोग करता हूँ,
और जिन complex queries को ORM से cover नहीं किया जा सकता, या जिन queries में और optimization चाहिए, उन्हें raw query से संभालता हूँ।
मुझे लगता है कि ORM या raw query में से क्या चुनना है, यह इस बात पर उचित रूप से निर्भर करता है कि किस स्थिति में क्या और कैसे बनाना है।
आम तौर पर, जिन डेटा का DB normalization अच्छी तरह से किया गया हो और जिनमें बड़े join की ज़रूरत न पड़ती हो, उनके लिए ऐसा हो सकता है,
लेकिन अगर DB normalization से शुरू करके हर चीज़ को DBA के जरिए सही तरह से मैनेज करना संभव न हो, तो ORM भी एक अच्छा विकल्प हो सकता है। खासकर, join के जरिए लाने वाली चीज़ों को relationship के रूप में लाते समय जो फायदे मिलते हैं, वे मुझे लगता है कि यह दिखाने का बहुत अच्छा उदाहरण हैं कि लोग ORM क्यों इस्तेमाल करते हैं।
बेशक, मैं इस बात से सहमत हूँ कि framework डेवलपर की growth को सीमित कर सकते हैं, और framework dependency को कम किया जाना चाहिए,
लेकिन इस राय से कि बिना शर्त ORM का इस्तेमाल ही न किया जाए, मैं आसानी से सहमत नहीं हो सकता।
मुझे लगता है कि यह इस धारणा पर आधारित है कि हर कंपनी में DBA होता है और development DDD या TDD जैसी सही methodology के साथ किया जा रहा है।
अगर वास्तव में practical काम में चीज़ें इस तरह की जाएँ, तो पता नहीं code और कितना ज़्यादा बिखर जाएगा।
जब Python से backend बनाते हैं, तो लगभग हर बार SQLAlchemy या Django ORM का इस्तेमाल करते हैं।
सीधे SQL लिखना हो या ORM इस्तेमाल करना, दोनों की आदत पड़ने के बाद मुझे खास फर्क महसूस नहीं हुआ, इसलिए मैंने इस बारे में ज़्यादा सोचा ही नहीं था। लेकिन ORM का इस्तेमाल न करने की राय भी है।
framework पर निर्भरता कम करने वाली बात से मैं सहमत हूँ। सिर्फ Django ORM ही आना और SQL संभालना न आना ठीक नहीं होगा...
उम्, खैर, मैं इससे सहमत नहीं हूँ। मैं अभी लगभग 3,000 tables वाले एक service को चला रहा हूँ, और domain इतना जटिल है कि एक query बनाने में ही आमतौर पर दर्जनों lines लिखनी पड़ती हैं। अगर इसमें dynamic queries भी जोड़ दें, तो सच में सिर दर्द हो जाता है। जटिलता की वजह से bugs भी बहुत आते थे और maintenance भी मुश्किल था। मेरा मानना है कि जटिल domains में ORM ज़्यादा फायदेमंद होता है।
मेरे मामले में, मुझे एक non-normalized DB का maintenance करने का अनुभव रहा है
उस समय dynamic queries को ORM का इस्तेमाल किए बिना सामान्य SQL में लिखता था,
ऐसा करते-करते कई बार कोड और भी कम समझ में आने वाला हो जाता था
मेरा मानना है कि सिर्फ complex domains ही नहीं, बल्कि normalization की कमी वाले domains में भी इसे अपनाने की पर्याप्त गुंजाइश है
ओह, फिर इसे बुरा मानने की ज़रूरत नहीं होगी।
मैं भी व्यक्तिगत रूप से सिर्फ़ SQL इस्तेमाल करने की सलाह देना चाहूँगा। JS दुनिया में Prisma जैसे tools का काफ़ी इस्तेमाल होता है, लेकिन SQL इतनी भी मुश्किल language नहीं है, और database I/O के लिए यह बहुत ज़्यादा अनावश्यक abstraction माँगता हुआ लगता है, इसलिए मुझे इससे थोड़ी झिझक होती है।
लगता है कि js/ts वाले ORM खास तौर पर काफ़ी अधूरे-से products होते हैं, इसलिए ऐसा लगता है।
Jdbc जैसा कुछ हो तो चल जाएगा, है न? मुझे याद आ रहा है कि पहले मेरे साथ काम कर चुके एक व्यक्ति ने कहा था, "JPA धीमा है, इसलिए कुछ और इस्तेमाल करो।"
यह किसी दंतकथा जैसी लगती है।
लगता है कि trend framework नहीं, बल्कि basics पर वापस जाने का बन रहा है।
HTMX, SQL वगैरह..
हालाँकि इसमें पहिया फिर से नया बनाना पड़ने की कमी है
फ़ायदे भी हैं..
2. MyBatis (हालाँकि यह ORM नहीं है, हा)
लगता है ORM की जगह DAO पर स्विच कर लेना चाहिए था।