फरवरी के अंत में, हमने Kaspersky Mobile Talks के Android डेवलपर्स की बैठकों के लिए एक नया प्रारूप लॉन्च किया। साधारण रैलियों से मुख्य अंतर यह है कि सैकड़ों श्रोताओं और सुंदर प्रस्तुतियों के बजाय, "अनुभवी" डेवलपर्स सिर्फ एक विषय पर चर्चा करने के लिए कई अलग-अलग विषयों पर एकत्र हुए: वे अपने अनुप्रयोगों में बहु-मॉड्यूलरता को कैसे लागू करते हैं, वे किन समस्याओं का सामना करते हैं, और कैसे वे उनका सामना करते हैं।

सामग्री
- प्रागितिहास
- हेडहंटर में मध्यस्थ। अलेक्जेंडर ब्लिनोव
- Tinkoff डोमेन मॉड्यूल व्लादिमीर कोखनोव, अलेक्जेंडर ज़ूकोव
- Avito में प्रभाव विश्लेषण। एवगेनी क्रिवोबोकोव, मिखाइल युडिन
- जैसा कि टिंकॉफ में उन्होंने पीआर के लिए विधानसभा का समय चालीस मिनट से घटाकर चार कर दिया। व्लादिमीर कोखनोव
- उपयोगी लिंक
कास्परस्की लैब कार्यालय में बैठक की तत्काल सामग्री के लिए आगे बढ़ने से पहले, आइए याद करें कि आवेदन में मॉड्यूल को विभाजित करने के लिए मॉड कहां से आया (इसके बाद, मॉड्यूल को ग्रैगल मॉड्यूल माना जाता है, न कि डैगर, जब तक कि कहा नहीं जाता)।
बहु-प्रतिरूपता का विषय Android समुदाय के मन में वर्षों से रहा है। मूलभूत में से एक को डेनिस नेक्लाइडोव द्वारा पिछले साल के सेंट पीटर्सबर्ग "मोबियस" की एक रिपोर्ट माना जा सकता है। उन्होंने मोनोलिथिक एप्लिकेशन को विभाजित करने का प्रस्ताव दिया था, जो बिल्ड स्पीड बढ़ाने के लिए लंबे समय तक एक पतले ग्राहक के रूप में था।
रिपोर्ट का लिंक: प्रस्तुति , वीडियो
तब यैंडेक्स से व्लादिमीर टेगाकोव की एक रिपोर्ट थी। डैगर का उपयोग करके मॉड्यूल को जोड़ने के बारे में। इस प्रकार, वे कई अन्य यैंडेक्स अनुप्रयोगों में पुन: उपयोग के लिए कार्ड के एक घटक को आवंटित करने की समस्या को हल करते हैं।
रिपोर्ट का लिंक: प्रस्तुति , वीडियो
कैस्परस्की लैब भी प्रवृत्ति से अलग नहीं खड़ा था: सितंबर में एवगेनी मात्सयुक ने डैगर का उपयोग करके मॉड्यूल को जोड़ने के तरीके पर एक लेख लिखा था और एक ही समय में क्षैतिज रूप से एक मल्टी-मॉड्यूल आर्किटेक्चर का निर्माण किया था, क्लीन आर्किटेक्चर के सिद्धांतों का पालन करना न भूलें।
लेख का लिंक
और सर्दियों में मोबिअस पर एक साथ दो रिपोर्टें थीं। सबसे पहले, अलेक्जेंडर ब्लिनोव ने हेडहंटर आवेदन में मल्टी-मोड्युलैरिटी के बारे में बात की, टूथपिक को डीआई के रूप में इस्तेमाल किया, और उसके ठीक बाद आर्टेम ज़िनाटुलिन ने Lyft में 800+ मॉड्यूल से दर्द के बारे में बात की। साशा ने बहु-प्रतिरूपता के बारे में बात करना शुरू कर दिया, आवेदन की वास्तुकला में सुधार करने के तरीके के रूप में, और न केवल विधानसभा को गति देना।
ब्लिनोव रिपोर्ट: प्रस्तुति , वीडियो
ज़िनाटुलिन रिपोर्ट: वीडियो
मैंने एक पूर्वव्यापी के साथ लेख क्यों शुरू किया? यदि आप पहली बार मल्टी-मोड्युलैरिटी के बारे में पढ़ रहे हैं, तो सबसे पहले, यह आपको उस विषय का बेहतर अध्ययन करने में मदद करेगा। और दूसरी बात, हमारी बैठक में पहला भाषण स्ट्रीम कंपनी के एलेक्सी कैलाडा द्वारा एक मिनी-प्रस्तुति के साथ शुरू हुआ, जिसमें दिखाया गया कि कैसे उन्होंने अपने आवेदन को जेन्या के लेख के आधार पर मॉड्यूल में विभाजित किया (और कुछ बिंदु मुझे व्लादिमीर के दृष्टिकोण के समान लगते हैं)।
इस दृष्टिकोण की मुख्य विशेषता यूआई के लिए बाध्यकारी थी: प्रत्येक मॉड्यूल एक अलग स्क्रीन के रूप में जुड़ा हुआ है - एक टुकड़ा जिसके लिए निर्भरता को मुख्य ऐप-मॉड्यूल से स्थानांतरित किया जाता है, जिसमें फ्रैगमेंट मैनजर भी शामिल है। पहले, सहकर्मियों ने प्रॉक्सी इंजेक्टरों के माध्यम से बहु-मॉड्यूलरता को लागू करने की कोशिश की, जिसे झेन्या ने लेख में प्रस्तावित किया। लेकिन यह दृष्टिकोण भारी लग रहा था: जब एक विशेषता दूसरे पर निर्भर थी, तो समस्याएं थीं, जो तीसरे पर निर्भर थी - हमें प्रत्येक फीचर मॉड्यूल के लिए एक प्रॉक्सी इंजेक्टर लिखना था। यूआई घटकों पर आधारित दृष्टिकोण आपको किसी भी इंजेक्टर को लिखने की अनुमति नहीं देता है, जिससे लक्ष्य टुकड़ों के निर्भरता स्तर पर निर्भरता की अनुमति मिलती है।
इस कार्यान्वयन की मुख्य सीमाएँ: एक सुविधा का एक टुकड़ा (या कोई अन्य दृश्य) होना चाहिए; नेस्टेड टुकड़ों की उपस्थिति, जो एक बड़े बॉयलरप्लेट की ओर जाता है। यदि कोई सुविधा अन्य सुविधाओं को लागू करती है, तो इसे निर्भरता मानचित्र में जोड़ा जाना चाहिए, जिसे डैगर इसे संकलित करते समय जांचता है। जब ऐसी कई विशेषताएं होती हैं, तो निर्भरता ग्राफ को जोड़ने के समय कठिनाइयां आती हैं।
एलेक्सी की रिपोर्ट के बाद, अलेक्जेंडर ब्लिनोव ने मंजिल ले ली। उनकी राय में, यूआई से जुड़ा हुआ कार्यान्वयन फ्लटर में डीआई कंटेनरों के लिए उपयुक्त होगा। तब चर्चा हेडहंटर में एक बहु-मॉड्यूल चर्चा में बदल गई। मॉड्यूल में उनके विभाजन का उद्देश्य सुविधाओं के वास्तु अलगाव और विधानसभा की गति बढ़ाने की संभावना था।
मॉड्यूल में विभाजित करने से पहले, तैयार करना महत्वपूर्ण है। सबसे पहले, आप एक निर्भरता ग्राफ बना सकते हैं - उदाहरण के लिए, इस तरह के उपकरण का उपयोग करके। यह घटकों को न्यूनतम संख्या पर निर्भरता के साथ अलग करने और अनावश्यक लोगों (काट) से छुटकारा पाने में मदद करेगा। इसके बाद ही, कम से कम जुड़े घटकों को मॉड्यूल में चुना जा सकता है।
अलेक्जेंडर ने मुख्य बिंदुओं को याद किया, जिसके बारे में उन्होंने मोबियस में अधिक विस्तार से बात की। आर्किटेक्चर को ध्यान में रखने वाले जटिल कार्यों में से एक आवेदन में विभिन्न स्थानों से एक मॉड्यूल का पुन: उपयोग करना है। Hh एप्लिकेशन के साथ उदाहरण में, यह एक फिर से शुरू मॉड्यूल है, जो कि रिक्ति सूची मॉड्यूल (VacanciesList) दोनों के लिए सुलभ होना चाहिए, जब उपयोगकर्ता उस रिज्यूमे में जाता है जो उसने इस रिक्ति के लिए प्रस्तुत किया है, और नकारात्मक प्रतिक्रिया मॉड्यूल (Neutiation) के लिए। स्पष्टता के लिए, मैंने उस तस्वीर को फिर से तैयार किया जिसे साशा ने एक फ्लिपकार्ट पर दर्शाया था।

प्रत्येक मॉड्यूल में दो मुख्य इकाइयाँ शामिल होती हैं: निर्भरताएँ - निर्भरताएँ जिन्हें इस मॉड्यूल की आवश्यकता होती है, और एपीआई - वे विधियाँ जो मॉड्यूल अन्य मॉड्यूलों को बाहर की ओर प्रदान करती हैं। मॉड्यूल के बीच संचार मध्यस्थों द्वारा किया जाता है, जो मुख्य ऐप-मॉड्यूल में एक सपाट संरचना है। प्रत्येक सुविधा में एक पिक है। मध्यस्थ स्वयं प्रोजेक्ट एप्लिकेशन-मॉड्यूल में एक निश्चित मध्यस्थ में शामिल होते हैं। कोड में, यह कुछ इस तरह दिखता है:
object MediatorManager { val chatMediator: ChatMediator by lazy { ChatMediator() } val someMediator: ... } class TechSupportMediator { fun provideComponent(): SuppportComponent { val deps = object : SuppportComponentDependencies { override fun getInternalChat{ MediatorManager.rootMediator.api.openInternalChat() } } } } class SuppportComponent(val dependencies) { val api: SupportComponentApi = ... init { SupportDI.keeper.installComponent(this) } } interface SuppportComponentDependencies { fun getSmth() fun close() { scopeHolder.destroyCoordinator < -ref count } }
अलेक्जेंडर ने जल्द ही एंड्रॉइड स्टूडियो में मॉड्यूल बनाने के लिए एक प्लग-इन प्रकाशित करने का वादा किया, जिसका उपयोग उनकी कंपनी में कॉपी-पेस्ट से छुटकारा पाने के लिए किया जाता है, साथ ही साथ एक कंसोल मल्टी-मॉड्यूल प्रोजेक्ट का एक उदाहरण है।
Hh अनुप्रयोग मॉड्यूल पृथक्करण के वर्तमान परिणामों के बारे में कुछ और तथ्य:
- ~ 83 सुविधा मॉड्यूल।
- ए / बी टेस्ट आयोजित करने के लिए, सुविधाओं को मध्यस्थ स्तर पर पूरी तरह से फीचर मॉड्यूल द्वारा बदला जा सकता है।
- ग्रैडल स्कैन के ग्राफ से पता चलता है कि समानांतर में मॉड्यूल के संकलन के बाद, एप्लिकेशन को हटाने की एक लंबी प्रक्रिया होती है (इस मामले में, दो: नौकरी चाहने वालों और नियोक्ताओं के लिए):

निम्नलिखित ने अलेक्जेंडर और व्लादिमीर से टिंकॉफ से फर्श लिया:
उनकी बहु-मॉड्यूल वास्तुकला की योजना इस प्रकार है:

मॉड्यूल को दो श्रेणियों में विभाजित किया गया है: फीचर मॉड्यूल और डोमेन मॉड्यूल।
फ़ीचर मॉड्यूल में व्यावसायिक तर्क और UI विशेषताएं शामिल हैं। वे डोमेन मॉड्यूल पर निर्भर करते हैं, लेकिन एक दूसरे पर निर्भर नहीं हो सकते।
डोमेन मॉड्यूल में डेटा स्रोतों के साथ काम करने के लिए कोड होता है, अर्थात, कुछ मॉडल, डीएओ (डेटाबेस के साथ काम करने के लिए), एपीआई (नेटवर्क के साथ काम करने के लिए) और रिपॉजिटरी (एपीआई और डीएओ के काम को मिलाते हैं)। डोमेन-मॉड्यूल, फीचर-मॉड्यूल के विपरीत, एक-दूसरे पर निर्भर हो सकते हैं।
डोमेन और फ़ीचर मॉड्यूल के बीच का कनेक्शन पूरी तरह से फ़ीचर मॉड्यूल के अंदर होता है (जो कि hh की शब्दावली में, डोमेन मॉड्यूल की निर्भरता और API निर्भरता पूरी तरह से उन्हें उपयोग करने वाले फीचर मॉड्यूल में मध्यस्थों जैसे अतिरिक्त संस्थाओं के उपयोग के बिना हल किया जाता है)।
इसके बाद प्रश्नों की एक श्रृंखला थी, जिसे मैं यहां "प्रश्न-उत्तर" प्रारूप में अपरिवर्तित रखूंगा:
- प्राधिकरण कैसे किया जाता है? आप इसे फीचर मॉड्यूल में कैसे खींचें?
- हमारे साथ सुविधाएँ प्राधिकरण पर निर्भर नहीं करती हैं, क्योंकि आवेदन के लगभग सभी कार्य अधिकृत क्षेत्र में होते हैं।
- अप्रयुक्त घटकों को कैसे ट्रैक और साफ करना है?
- हमारे पास InjectorRefCount (WeakHashMap के माध्यम से कार्यान्वित) के रूप में ऐसी इकाई है, जो इस घटक का उपयोग करते हुए अंतिम गतिविधि (या टुकड़ा) को हटाते हुए इसे हटा देता है।
- "स्वच्छ" स्कैन और समय बनाने के लिए कैसे मापें? यदि कैश चालू होते हैं, तो एक गंदा स्कैन प्राप्त किया जाता है।
- आप ग्रेडल कैश (org.gradle.caching in gradle.properties) को अक्षम कर सकते हैं।
- डिबग मोड में सभी मॉड्यूल से यूनिट टेस्ट कैसे चलाएं? यदि आप बस ग्रेडल टेस्ट चलाते हैं, तो सभी फ्लेवर और बिल्ड टाइप से परीक्षण खींच लिए जाते हैं।
(इस सवाल ने बैठक में कई प्रतिभागियों की चर्चा छेड़ दी।)
- आप टेस्टडबग चलाने की कोशिश कर सकते हैं।
- तब मॉड्यूल जिसके लिए कोई डीबग कॉन्फ़िगरेशन नहीं है, को कड़ा नहीं किया जाएगा। यह या तो बहुत कम या बहुत कम शुरू होता है।
- आप एक ग्रैडल कार्य लिख सकते हैं, जो इस तरह के मॉड्यूल के लिए टेस्टडबग को ओवरराइड करेगा, या मॉड्यूल build.gradle में नकली डिबग कॉन्फ़िगरेशन कर सकता है।
- आप इस तरह से इस दृष्टिकोण को लागू कर सकते हैं:
withAndroidPlugin(project) { _, applicationExtension -> applicationExtension.testVariants.all { testVariant -> val testVariantSuffix = testVariant.testedVariant.name.capitalize() } } val task = project.tasks.register < SomeTask > ( "doSomeTask", SomeTask::class.java ) { task.dependsOn("${project.path}:taskName$testVariantSuffix") }

अगली कामचलाऊ प्रस्तुति एवितो के इवगेनी क्रिवोबोकोव और मिखाइल युडिन द्वारा की गई थी।
उन्होंने अपनी कहानी की कल्पना करने के लिए माइंडमैप का इस्तेमाल किया।
अब कंपनी के प्रोजेक्ट में> 300 मॉड्यूल हैं, जिसमें कोडिन का 97% कोडिन लिखा गया है। मॉड्यूल में टूटने का मुख्य उद्देश्य परियोजना की विधानसभा में तेजी लाना था। मॉड्यूल में ब्रेकडाउन धीरे-धीरे हुआ, कोड के कम से कम निर्भर भागों को मॉड्यूल के लिए आवंटित किया जा रहा है। ऐसा करने के लिए, प्रभाव विश्लेषण के लिए ग्राफ में स्रोत कोड की निर्भरता को चिह्नित करने के लिए एक उपकरण विकसित किया गया था ( Avito में प्रभाव विश्लेषण के बारे में रिपोर्ट )।
इस उपकरण का उपयोग करके, आप एक फीचर मॉड्यूल को अंतिम रूप से चिह्नित कर सकते हैं ताकि अन्य मॉड्यूल उस पर निर्भर न हो सकें। इस संपत्ति को प्रभाव विश्लेषण के दौरान जांचा जाएगा और मॉड्यूल के लिए जिम्मेदार टीमों के साथ स्पष्ट निर्भरता और समझौतों का एक पदनाम प्रदान करेगा। निर्मित ग्राफ के आधार पर, प्रभावित कोड के लिए यूनिट परीक्षण चलाने के लिए परिवर्तनों का वितरण भी जांचा जाता है।
कंपनी एक मोनो-रिपॉजिटरी का उपयोग करती है, लेकिन केवल एंड्रॉइड स्रोतों के लिए। अन्य प्लेटफार्मों का कोड अलग-अलग रहता है।
ग्रेड का उपयोग परियोजना के निर्माण के लिए किया जाता है (हालांकि सहकर्मी पहले से ही बक या बाजेल जैसे बिल्डर के बारे में सोच रहे हैं जो मल्टी-मॉड्यूल परियोजनाओं के लिए अधिक उपयुक्त है)। उन्होंने पहले से ही कोटलिन डीएसएल की कोशिश की, और फिर ग्रैड स्क्रिप्ट में ग्रूवी पर लौट आए, क्योंकि ग्रैडल और प्रोजेक्ट में कोटलिन के विभिन्न संस्करणों का समर्थन करना असुविधाजनक है - सामान्य तर्क को प्लगइन्स में डाल दिया गया है।
ग्रैड कार्यों को संचित कर सकता है, कैश और बाइनरी निर्भरता को फिर से इकट्ठा नहीं कर सकता है यदि उनका एबीआई नहीं बदला है, जो एक मल्टी-मॉड्यूल प्रोजेक्ट के तेजी से विधानसभा सुनिश्चित करता है। अधिक कुशल कैशिंग के लिए, मेनफ्रेमर और कई स्व-लिखित समाधान उपयोग किए जाते हैं:
- शाखा से शाखा में स्विच करते समय, Git कैशिंग को तोड़ने वाले खाली फ़ोल्डर छोड़ सकता है ( ग्रेडल इशू # 2463 )। इसलिए, उन्हें मैन्युअल रूप से गिट हुक का उपयोग करके हटा दिया जाता है।
- यदि आप डेवलपर्स की मशीनों पर पर्यावरण को नियंत्रित नहीं करते हैं, तो एंड्रॉइड एसडीके और अन्य मापदंडों के विभिन्न संस्करण कैशिंग को नीचा दिखा सकते हैं। परियोजना के निर्माण के दौरान, स्क्रिप्ट पर्यावरण मापदंडों की अपेक्षा लोगों के साथ करती है: यदि गलत संस्करण या पैरामीटर स्थापित किए जाते हैं, तो निर्माण बंद हो जाएगा।
- एनालिटिक्स चालू / बंद मापदंडों और पर्यावरण पर चल रहा है। यह डेवलपर्स की निगरानी और मदद करने के लिए है।
- बिल्ड एरर को एनालिटिक्स को भी भेजा जाता है। ज्ञात और लोकप्रिय समस्याओं को एक विशेष पृष्ठ पर एक समाधान के साथ दर्ज किया जाता है।
यह सब CI पर 15% कैश मिस और 60-80% स्थानीय स्तर पर हासिल करने में मदद करता है।
यदि आपकी परियोजना में बड़ी संख्या में मॉड्यूल दिखाई देते हैं, तो निम्नलिखित ग्रेड टिप्स भी उपयोगी हो सकते हैं:
- आईडीई झंडे के माध्यम से मॉड्यूल को अक्षम करना असुविधाजनक है, इन झंडे को रीसेट किया जा सकता है। इसलिए, सेटिंग्स settings.gradle के माध्यम से अक्षम हैं।
- स्टूडियो 3.3.1 में एक चेकबॉक्स है "ग्रेड सिंक पर स्रोत को छोड़ें यदि एक परियोजना में 1 से अधिक मॉड्यूल हैं"। डिफ़ॉल्ट रूप से, इसे बंद कर दिया जाता है, इसे चालू करना बेहतर होता है।
- सभी मॉड्यूल में पुन: उपयोग करने के लिए निर्भरता buildSrc में पंजीकृत हैं। एक अन्य विकल्प प्लगइन्स डीएसएल है , लेकिन फिर आप प्लगइन के आवेदन को एक अलग फाइल में नहीं डाल सकते।
हमारी बैठक व्लादिमीर के साथ टिंकऑफ से रिपोर्ट के क्लिकबैट शीर्षक के साथ समाप्त हुई, "40 मिनट से चार तक पीआर पर विधानसभा कैसे कम करें । " वास्तव में, हम ग्रेड-प्लग की शुरुआत के वितरण के बारे में बात कर रहे थे: एपीके बिल्ड, परीक्षण और स्थिर विश्लेषक।
प्रारंभ में, प्रत्येक पुल अनुरोध पर लोगों ने सीधे विधानसभा और परीक्षणों का स्थैतिक विश्लेषण किया। इस प्रक्रिया में 40 मिनट लगे, जिनमें से केवल लिंट और सोनारक्यूब को 25 लगे और लॉन्च का केवल 7% हिस्सा गिर गया।
इस प्रकार, उनके लॉन्च को एक अलग जॉब में रखने का निर्णय लिया गया, जो हर दो घंटे में एक शेड्यूल पर चलता है और, एक त्रुटि के मामले में, स्लैक को एक संदेश भेजता है।
विपरीत स्थिति डिटेक्ट का उपयोग कर रही थी। यह लगभग लगातार दुर्घटनाग्रस्त हो गया, यही वजह है कि इसे प्रारंभिक प्री-पुश चेक में डाल दिया गया।
इसलिए, केवल apk असेंबली और यूनिट परीक्षण पुल अनुरोध सत्यापन में बने रहे। परीक्षण चलने से पहले स्रोतों को संकलित करते हैं, लेकिन संसाधन एकत्र नहीं करते हैं। चूंकि संसाधनों का विलय लगभग हमेशा सफल रहा, इसलिए एपीके असेंबली को भी छोड़ दिया गया।
नतीजतन, केवल यूनिट परीक्षण का प्रक्षेपण पुल अनुरोध पर बना रहा, जिसने हमें संकेतित 4 मिनट हासिल करने की अनुमति दी। बिल्ड एपीके को देव में मर्जर पुल अनुरोध के साथ किया जाता है।
इस तथ्य के बावजूद कि बैठक लगभग 4 घंटे तक चली, हमने मल्टी-मॉड्यूल प्रोजेक्ट में नेविगेशन के आयोजन के ज्वलंत मुद्दे पर चर्चा करने का प्रबंधन नहीं किया। शायद यह अगले Kaspersky मोबाइल वार्ता के लिए विषय है। इसके अलावा, प्रतिभागियों को वास्तव में प्रारूप पसंद आया। हमें बताएं कि आप सर्वेक्षण में या टिप्पणियों में क्या बात करना चाहेंगे।
और अंत में, उसी चैट से उपयोगी लिंक: