Meta ने Android डेवलपमेंट को Java से Kotlin में क्यों और कैसे बदला
(engineering.fb.com)- Meta का Android repo एक विशाल repository है, जिसमें Facebook, Instagram, Messenger, Quest आदि शामिल हैं
- इसमें इस समय लगभग 1 करोड़ से अधिक lines का Kotlin code शामिल है
Kotlin में बदलने के कारण
- लोकप्रियता के अलावा इसके कुछ प्रमुख फायदे
- Nullability : NPE, Meta में एक सामान्य समस्या थी, इसलिए इसके लिए कई तरह के उपाय किए गए थे, लेकिन Kotlin का built-in nullability handling कहीं अधिक शक्तिशाली है और इस पर काम करना आसान है
- Functional programming : Kotlin के inline functions और lambda expressions, execution speed कम किए बिना FP style अपनाने की सुविधा देते हैं
- छोटा code
- DSL / Type-safe Builder
- बेशक कुछ ऐसे नुकसान भी हैं जिन्हें नज़रअंदाज़ नहीं किया जा सकता
- दूसरी language लाने का मतलब है कि mixed codebase को काफ़ी लंबे समय तक बनाए रखना पड़ेगा
- Kotlin लोकप्रिय है, लेकिन लोकप्रियता के मामले में अभी भी Java से अंतर है। इसलिए tools कम हैं, और कई Kotlin tools को Kotlin और Java interoperability को ध्यान में रखना पड़ता है, जिससे implementation जटिल हो जाता है
- सबसे बड़ी चिंता build time थी। शुरू से ही पता था कि Kotlin का build time, Java से धीमा हो सकता है। धीमा build time developer experience के लिए अच्छा नहीं है
Migration के लिए अपनाया गया तरीका
- Kotlin में migration हैरान करने वाली तरह से आसान भी था, और बहुत जटिल भी
- J2K(Java To Kotlin Converter) होने से सुविधा तो थी, लेकिन फिर भी यह जटिल था
- J2K हमेशा सटीक नहीं होता, और Java तथा Kotlin की interoperability कुछ edge cases पैदा करती है
- Migration के लिए दो विकल्प थे
- सिर्फ नया code Kotlin में लिखा जाए और बाकी ज़्यादातर code Java में ही रहे
- इसका फ़ायदा यह है कि काम कम है, लेकिन दो languages के मिश्रण की वजह से Kotlin में platform types का इस्तेमाल करना पड़ता है, जिससे null pointer dereference होकर crash हो सकता है
- इसके अलावा, Java में type parameters को Nullable के रूप में tag नहीं किया जा सकता था (कम-से-कम हाल तक), और Kotlin के overloading rules null की अनुमति को ध्यान में रखते हैं, जबकि Java के overloading rules ऐसा नहीं करते — ऐसी समस्याएँ भी थीं
- सभी in-house code को Kotlin में बदलने की कोशिश की जाए
- सिर्फ नया code Kotlin में लिखा जाए और बाकी ज़्यादातर code Java में ही रहे
Migration कैसे किया गया
- दोनों विकल्पों पर विचार किया गया, और लक्ष्य के रूप में सभी code को Kotlin में बदलने का फ़ैसला लिया गया
- शुरुआत में यह थोड़ा धीमा था, लेकिन कुछ blockers हल करने के बाद बड़े पैमाने पर conversion संभव हो गया
- अभी Facebook, Messenger, और Instagram के Android apps में से प्रत्येक में 10 लाख lines का Kotlin code शामिल है, और conversion rate लगातार बढ़ रहा है
- अभी पूरे Android codebase में 1 करोड़ lines का Kotlin code है
Unblocking
- Conversion शुरू करते ही कुछ issues सामने आए
- bytecode patterns की वजह से Redex को update करने की ज़रूरत पड़ी
- कुछ internal libraries, performance की वजह से bytecode transforming करती थीं, और यह Kotlin में काम नहीं कर रहा था
- अगर अंदरूनी तौर पर बहुत optimization किया गया है, तो ऐसे ही issues आ सकते हैं
- मौजूदा tools में भी समस्याएँ आईं
- code review/wiki आदि में Kotlin syntax highlighting नहीं हो रही थी, इसलिए Pygments को update किया गया
- Kotlin formatter Ktfmt अलग से विकसित किया गया
Migration को तेज़ करना
- tools तैयार हो गए थे, इसलिए code को Kotlin में बदलने के लिए तैयारी पूरी थी
- लेकिन हर migration में काफ़ी boilerplate code था, जिसे manually करना पड़ता था
- J2K एक सामान्य tool है, इसलिए उसे code की समझ नहीं होती। इसी कारण बहुत manual work की ज़रूरत पड़ती है
- उदाहरण के लिए JUnit testing rules जैसी चीज़ें
- इसलिए J2K को 3-stage pipeline के बीच में रखा गया
- पहला, किसी एक Java package को लेकर उसे Kotlin में बदलने की तैयारी की जाती थी। इसमें bug fixes और internal tools के लिए ज़रूरी conversions शामिल थे
- दूसरा, script के ज़रिए J2K को स्वचालित रूप से चलाया जाता था
- तीसरा, नए Kotlin files पर post-processing की जाती थी। यह सबसे महत्वपूर्ण था। इसमें automatic refactoring/linter आदि को headless mode में चलाया जाता था
- Automation सभी समस्याएँ हल नहीं कर सकता, लेकिन सामान्य चीज़ों को प्राथमिकता दी गई
Kotlin migration से सीखी गई बातें
- code की लंबाई कम हुई
- execution speed बनी रही
- build size कोई समस्या नहीं है
- बढ़े हुए build time की समस्या का समाधान : KSP(Kotlin Symbol Processing API) का उपयोग
4 टिप्पणियां
अच्छा लेख साझा करने के लिए धन्यवाद। व्यक्तिगत रूप से, जब मैंने पहली बार Kotlin इस्तेमाल किया, तो Java की तुलना में इसमें कई सुविधाजनक बातें लगीं, इसलिए यह भी लगा कि आगे चलकर शायद Kotlin ही मुख्यधारा बन जाएगा। लेकिन कुछ समय इस्तेमाल करने के बाद लगा कि अभी भी कई पहलू ऐसे हैं जहाँ Java बेहतर लगता है।
Android में Kotlin अपनाना ठीक लगता है, लेकिन दूसरे environments (जैसे Spring आदि) में, अगर stability महत्वपूर्ण है, तो अभी के लिए Java बेहतर विकल्प लगता है।
क्या आप स्थिरता का सिर्फ़ एक उदाहरण बता सकते हैं? मेरा अनुभव अभी कम है, इसलिए अभी तक मुझे ऐसा कोई उदाहरण नहीं मिला है, और मैं इसे लेकर बहुत उत्सुक हूँ।
शायद इसलिए कि JetBrains बहुत तेज़ी से रिलीज़ निकाल रहा है, लेकिन हैरानी की बात यह है कि compiler bug fixes काफ़ी ज़्यादा हैं.
https://github.com/JetBrains/kotlin/releases/tag/v1.7.20
कभी-कभी compiler खुद ही crash हो जाता है (यह तो फिर भी pre-release में हो तो ठीक है), और output artifacts में भी अक्सर bugs शामिल होते हैं.
ऊपर से, Android के मामले में R8 bytecode optimiser भी Kotlin version के हिसाब से फ़र्क करता है.
क्योंकि Kotlin code के लिए dedicated optimization feature है, लेकिन इसके लिए कोई आधिकारिक compatibility table document (Android Gradle Plugin : Kotlin Version) नहीं है..
इसलिए Android project में Kotlin version बदलते समय सावधान रहना चाहिए;;;
संबंधित bug report : https://issuetracker.google.com/issues/207397158
धन्यवाद। सचमुच यह एक गहरी और व्यापक दुनिया है..