Monorepo vs polyrepo: web, mobile, backend का समन्वय बनाए रखना
वेब, मोबाइल और बैकएंड ऐप्स भेजने वाली टीमों के लिए monorepo बनाम polyrepo समझाइए। निर्भरताएँ, रिलीज़ समन्वय और CI रणनीतियों की तुलना करें ताकि आप तेज़ बने रहें।

असली समस्या: तीन कोडबेस में परिवर्तन भेजना
टीमें monorepo और polyrepo पर इसलिए बहस नहीं करतीं क्योंकि उन्हें Git दर्शन की परवाह है। वे बहस इसलिए करती हैं क्योंकि एक छोटा प्रोडक्ट बदलाव वेब, मोबाइल और बैकएंड में तीन अलग बदलाव में बदल जाता है, और बीच में कुछ टूट जाता है।
जो सबसे पहले टूटता है वह शायद UI नहीं होता। अक्सर यह अदृश्य ग्लू होता है: एक API कॉन्ट्रैक्ट बदला बिना मिलते-जुलते बदलाव के, एक साझा लाइब्रेरी एक जगह अपडेट हुई पर दूसरी जगह नहीं, या बिल्ड पाइपलाइन को अचानक एक नया कदम चाहिए। जब एक हिस्सा दूसरे से पहले शिप होता है, तो यूज़र इसे बग की तरह महसूस करते हैं—"वेब पर बटन है पर मोबाइल ऐप कहता है unsupported" या "एप लोड नहीं हो रहा क्योंकि बैकएंड रिस्पॉन्स बदल गया।"
वेब, मोबाइल और बैकएंड अलग रिलीज़ क्लॉक्स पर चलते हैं। वेब दिन में कई बार शिप कर सकता है। बैकएंड अक्सर शिप कर सकता है, पर रोलआउट सावधानी मांगता है। मोबाइल सबसे धीमा है क्योंकि ऐप स्टोर समीक्षा और यूज़र अपडेट में असली देरी आती है। फील्ड का नाम बदलना जैसी “सादी” चीज़ आपको सबसे धीमी लाइन के मुताबिक़ प्लान करवा सकती है, भले ही सिर्फ़ एक स्क्रीन को जरूरत हो।
यदि ये समस्याएँ बार-बार हो रही हैं तो आप शायद रिपो समन्वय टैक्स दे रहे हैं:
- ब्रेकिंग API बदलाव मर्ज के बाद मिलते हैं।
- वर्ज़न अलाइनमेंट मैनुअल रिमाइंडर और स्प्रेडशीट पर निर्भर है।
- एक फीचर के लिए कई समन्वित पुल रिक्वेस्ट चाहिए जो एक-दूसरे का इंतज़ार करते रहते हैं।
- CI धीमा है क्योंकि यह बदल से बहुत अधिक चीज़ बनाता और टेस्ट करता है।
- रोलबैक रिस्की लगता है क्योंकि यह स्पष्ट नहीं होता कि कौन सा कमिट किस रिलीज़ से मेल खाता है।
टीम का आकार और प्रोडक्ट की परिपक्वता सही जवाब बदल देती है। शुरू में अधिकतर टीमों के लिए coordination सस्ता और visibility हाई रखना बेहतर होता है, भले ही चीज़ें थोड़ी गड़बड़ हों। जैसे-जैसे टीम बढ़ती है, सीमाएँ महत्वपूर्ण हो जाती हैं—पर तभी जब इंटरफेस स्थिर हों और ownership स्पष्ट हो।
अगर हर महत्वपूर्ण बदलाव को तीन जगह लैंड करना पड़ता है, तो आप किसी न किसी तरह वह टैक्स चुकाएँगे। रिपो रणनीति मूल रूप से यह तय करती है कि आप इसे कैसे भुगतान करना चाहते हैं।
Monorepo और polyrepo बुनियादी बातें (जैगरनरी के बिना)
एक रिपो बस वह जगह है जहाँ आपका कोड रहता है और उसकी हिस्ट्री। जब आपके पास web, mobile, और backend हों, विकल्प साफ़ है: सब एक साथ रखें या अलग कर दें।
एक monorepo एक ही रिपो है जिसमें कई ऐप्स और अक्सर साझा कोड भी होते हैं। Web, iOS/Android, backend सेवाएँ और शेयर की गई लाइब्रेरी साथ-साथ रहती हैं।
एक polyrepo इसका उल्टा है: हर ऐप (और कभी-कभी हर सर्विस) का अपना रिपो होता है। साझा कोड अलग पैकेज बन जाता है या टीमें ज़रूरत पड़ने पर छोटे हिस्से कॉपी कर लेती हैं।
दिन-प्रतिदिन में monorepo सामान्यतः ऐसा लगता है: कोड साझा करना आसान है, क्रॉस-एप बदलाव एक ही पुल रिक्वेस्ट में हो सकते हैं, और नियम लगातार होते हैं। ट्रेडऑफ़ सामाजिक होता है: ownership धुंधला हो सकता है जब तक आप स्पष्ट सीमाएँ न रखें, और पूरे रिपो के चेक सख्त लग सकते हैं।
Polyrepos आम तौर पर ऐसा महसूस कराते हैं: हर टीम स्वतंत्र रूप से तेज़ी से आगे बढ़ सकती है, रिपोज़ फोकस्ड रहते हैं, और एक्सेस कंट्रोल सरल हो सकता है। ट्रेडऑफ़ समन्वय है: कोड शेयर करना प्लानिंग मांगता है, और क्रॉस-ऐप बदलाव अक्सर कई पुल रिक्वेस्ट बन जाते हैं जिनका सावधानी से टाइमिंग करना पड़ता है।
कई टीमें हाइब्रिड के साथ खत्म होती हैं: ऐप्स अलग रिपोज़ में और साझा कॉन्ट्रैक्ट्स एक जगह; या एक monorepo जिसमें मजबूत सीमाएँ हों ताकि प्रत्येक टीम ज्यादातर अपने ही क्षेत्र में रहे।
यदि आप कोई प्लेटफ़ॉर्म इस्तेमाल करते हैं जो एक स्रोत से बैकएंड, वेब और मोबाइल जनरेट करता है, तो आप drift घटाते हैं क्योंकि कॉन्ट्रैक्ट्स और लॉजिक एक साथ रहते हैं। AppMaster, उदाहरण के लिए, एक मॉडल से production-ready backend, web और native mobile ऐप्स जनरेट करता है। यह रिलीज़ की वास्तविकताओं (मोबाइल अभी भी धीमा है) को नहीं हटाता, पर यह अक्सर “क्या हमने तीनों अपडेट कर दिए?” का बहुत सारा ओवरहेड मिटा देता है।
डिपेंडेंसी प्रबंधन: साझा कोड को सुरक्षित रखना
साझा कोड वही जगह है जहाँ टीमें समय खो देती हैं, चाहे रिपो लेआउट कुछ भी हो। एक छोटी सी बदल shared लाइब्रेरी या API कॉन्ट्रैक्ट में वेब बिल्ड, मोबाइल रिलीज़ और बैकएंड डिप्लॉय को अलग तरीकों से तोड़ सकती है।
जब आप लाइब्रेरी शेयर करते हैं (UI कंपोनेंट्स, वैलिडेशन रूल्स, auth हेल्पर्स), तो आप या तो सबके लिए एक ही वर्ज़न चुनते हैं या समय के साथ कई वर्ज़न रखते हैं।
- एक वर्ज़न सरल है और "मेरी ब्रांच में चलता है" जैसी आश्चर्य से बचाता है।
- कई वर्ज़न टीमें अपनी रफ्तार से बढ़ने देते हैं, पर क्लटर बनाते हैं और सिक्योरिटी फिक्स दोगुना मुश्किल कर देते हैं।
API क्लाइंट्स और स्कीमाज़ को अतिरिक्त ध्यान चाहिए। मैनुअल अपडेट धीमे और त्रुटिपूर्ण होते हैं। बेहतर पैटर्न यह है कि API स्कीमा को source of truth मानकर क्लाइंट उससे जनरेट करें, फिर उन्हें चेक-इन करें या CI में जनरेट करें। मकसद है जल्दी फेल होना: अगर बैकएंड ने एक required फ़ील्ड जोड़ दिया, तो मोबाइल क्लाइंट बिल्ड में टूट जाना चाहिए, QA में तीन दिन बाद नहीं।
जब व्यवहार बिना सुरक्षित मार्ग के बदला जाता है तो ब्रेकिंग बदलाव फैलते हैं। पहले additive changes पसंद करें (नए फ़ील्ड, नए एंडपॉइंट), फिर बाद में deprecate करें। अगर कुछ तोड़ना ही पड़े तो versioned endpoints या एक छोटा compatibility विंडो रखें।
ठोस उदाहरण: बैकएंड ने status का नाम बदलकर state कर दिया। अगर वेब आज अपडेट कर ले पर मोबाइल एक सप्ताह में ही शिप कर सके, तो बैकएंड को एक सप्ताह तक दोनों फ़ील्ड स्वीकार करना चाहिए, या एक adapter शिप करनी चाहिए जो पुराने फ़ील्ड को नए से मैप करे।
कुछ नियम जो डिपेंडेंसी अपडेट्स को बोरिंग (अच्छे मायने में) बनाए रखते हैं:
- कैडेंस पर अपडेट करें। छोटे साप्ताहिक अपडेट बड़े त्रैमासिक वाले से बेहतर हैं।
- ब्रेकिंग बदलाव के लिए स्पष्ट मंजूरी और एक छोटा migration नोट चाहिए।
- चेक्स ऑटोमेट करें: dependency bumps, क्लाइंट regeneration, और बेसिक contract tests।
- “डन” की परिभाषा रखें: “web, mobile, और backend बिल्ड ग्रीन हैं,” न कि “मेरी रिपो पास है।”
जनरेटेड कोड drift घटा सकता है, पर यह अनुशासन की जगह नहीं लेता। आपको अभी भी एक कॉन्ट्रैक्ट, स्पष्ट deprecations, और पूर्वानुमानित अपडेट्स चाहिए।
रिलीज समन्वय: web, mobile और backend को संरेखित करना
रिलीज़ समन्वय वह जगह है जहाँ रिपो रणनीति सैद्धांतिक से वास्तविक बनती है। अगर बैकएंड ने एक API फ़ील्ड नाम बदला, वेब आम तौर पर उसी दिन अपडेट और शिप कर सकता है। मोबाइल अलग है: ऐप स्टोर समीक्षा और यूज़र अपडेट का समय एक छोटे मिसमैच को समर्थन टिकटों के एक सप्ताह में बदल सकता है।
व्यवहारिक लक्ष्य सरल है: किसी भी यूज़र एक्शन को काम करना चाहिए चाहे कौन सा हिस्सा पहले अपडेट हो। इसका अर्थ है mixed वर्ज़न को प्लान करना, परफ़ेक्ट सिंक्रोनाइज़्ड रिलीज़ की अपेक्षा नहीं रखना।
टीमें जो असल में इस्तेमाल करती हैं वो वर्ज़निंग पैटर्न
ज्यादातर टीमें इन में से किसी एक पर टिक जाती हैं:
-
एक साझा रिलीज ट्रेन: वेब, मोबाइल, और बैकएंड एक वर्ज़न्ड यूनिट के रूप में शिप करते हैं।
-
प्रति-सेवा वर्ज़न्स और compatibility नियम: हर ऐप/सर्विस की अपनी वर्ज़निंग, और बैकएंड एक परिभाषित क्लाइंट वर्ज़न रेंज का समर्थन करता है।
एक साझा रिलीज ट्रेन साफ़ दिखती है, पर मोबाइल देरी के चलते यह अक्सर टूट जाती है। प्रति-सेवा वर्ज़न कागज़ पर गड़बड़ लग सकते हैं, पर वे वास्तविकता से मेल खाते हैं। अगर आप per-service जाते हैं तो एक नियम लिखें और लागू करें: कौन से बैकएंड वर्ज़न किस मोबाइल वर्ज़न का समर्थन करेंगे और कितने समय तक।
मोबाइल की देरी यह भी बदल देती है कि आप hotfixes कैसे संभालते हैं। बैकएंड hotfix तेजी से जा सकता है; मोबाइल hotfix यूज़र्स तक पहुंचने में दिनों लग सकते हैं। सर्वर-साइड फिक्स पसंद करें जो पुराने मोबाइल बिल्ड्स को काम करने दें। जब क्लाइंट बदलना जरूरी हो, feature flags का उपयोग करें और तब तक पुराने फ़ील्ड न हटाएँ जब तक अधिकांश उपयोगकर्ता अपडेट न कर लें।
उदाहरण: आपने ऑर्डर फ़्लो में “delivery instructions” जोड़ी। बैकएंड ने एक optional फ़ील्ड जोड़ी, वेब ने उसे तुरंत दिखाया, और मोबाइल ने अगले स्प्रिंट में दिखाया। अगर बैकएंड पुराने रिक्वेस्ट स्वीकार करे और फ़ील्ड को optional रखे, तो सब कुछ तब तक चलता रहेगा जब तक मोबाइल पकड़ न ले।
रिलीज कैलेंडर का मालिक कौन हो
समन्वय तब फेल होता है जब “सबका” मालिक होता है और कोई नहीं होता। मालिक कोई tech lead, release manager, या strong इंजीनियरिंग सपोर्ट वाला product manager हो सकता है। इनका काम है चौंका देने वाले बदलावों को रोकना और रिलीज़ अपेक्षाओं को दृश्यमान व सुसंगत रखना।
उन्हें जटिल प्रक्रिया की ज़रूरत नहीं है। उन्हें कुछ दोहराने योग्य आदतें चाहिए: कटऑफ और फ्रीज़ विंडो के साथ एक सरल रिलीज कैलेंडर, API बदलाव से पहले एक त्वरित क्रॉस-टीम चेक, और मोबाइल देरी होने पर क्या होगा उसका स्पष्ट प्लान (बैकएंड रोकना बनाम compatibility बनाए रखना)।
अगर आपका वर्कफ़्लो web, mobile, और backend को एक मॉडल से जनरेट करता है, तब भी आपको एक रिलीज मालिक चाहिए। आप आम तौर पर कम “क्या हमने तीनों जगह अपडेट किए?” वाले क्षण देखेंगें, पर मोबाइल टाइमिंग से बचना नहीं मिलेगा।
CI समय नियंत्रित रखना
CI दोनों सेटअप में धीमा होता है क्योंकि आप बहुत अधिक चीज़ फिर से बनाते हैं, dependencies बार-बार इंस्टॉल करते हैं, और हर बदलाव पर हर टेस्ट चलाते हैं।
सामान्य समय नुकसान करने वाले कारण: छोटे बदलाव पर पूरा बिल्ड, कैश मिस होना, टेस्ट सूट जो सब कुछ चलाता है, और सीरियल जॉब्स जो पैरेलल चल सकते हैं।
सबसे पहले उन सुधारों से शुरू करें जो हर जगह मदद करें:
- dependency downloads और build outputs को cache करें।
- lint, unit tests, और builds को जहां संभव हो पैरेलल चलाएँ।
- तेज़ चेक्स (हर कमिट) और धीरे चेक्स (main, nightly, pre-release) अलग रखें।
Monorepo तक्टिक्स जो मदद करते हैं
Monorepo तब मुश्किल बनता है जब हर कमिट "दुनिया बनाओ" पाइपलाइन ट्रिगर करे। समाधान है केवल प्रभावित हिस्सों को बनाना और टेस्ट करना।
path filters और affected-only दृष्टिकोण अपनाएँ: अगर आपने मोबाइल UI कोड बदला है तो बैकएंड इमेजेस न बनाएं। अगर आपने साझा लाइब्रेरी बदली है तो केवल उन ऐप्स को बनाएं और टेस्ट करें जो उस पर निर्भर हैं। कई टीमें इसे एक सरल dependency graph के साथ औपचारिक बनाती हैं ताकि CI अनुमान लगाने के बजाय निर्णय ले सके।
Polyrepo तक्टिक्स जो drift रोकते हैं
Polyrepos तेज़ हो सकते हैं क्योंकि हर रिपो छोटा होता है, पर वे अक्सर duplication और inconsistent tooling से समय बर्बाद करते हैं।
एक साझा सेट CI टेम्पलेट्स रखें (एक जैसे कदम, एक जैसे कैश, एक जैसी conventions) ताकि हर रिपो pipeline को फिर से आविष्कार न करे। टूलचेन पिन करें (रनटाइम वर्ज़न, build tools, linters) ताकि "एक रिपो में चलता है" की समस्याएँ न हों। अगर dependency downloads बाधा हैं तो shared caches या internal mirrors सेट करें ताकि हर रिपो दुनिया से सब कुछ बार-बार न खींचे।
ठोस उदाहरण: एक फीचर नया "status" फ़ील्ड जोड़ता है। बैकएंड बदलता है, वेब दिखाता है, मोबाइल दिखाता है। Monorepo में CI बैकएंड टेस्ट चलाएगा और केवल वेब/मोबाइल हिस्सों को रन करेगा जो API क्लाइंट पर निर्भर हैं। Polyrepo सेटअप में, हर रिपो अपना तेज़ चेक चलाएगा, और एक अलग integration pipeline पुष्टि करेगा कि तीनों रिलीज़ अभी भी मेल खाते हैं।
अगर आप स्रोत को एक्स्पोर्ट करके अपनी CI चलाते हैं तो नियम वही है: केवल जो बदला उसे बनाएं, कैशेज़ का agresive reuse करें, और धीमे चेक्स को तभी चलाएँ जब वे असली वैल्यू जोड़ें।
चरण-दर-चरण: अपनी टीम के अनुसार रिपो रणनीति चुनें
फैसला आसान होगा जब आप सिद्धांत की जगह अपने रोज़मर्रा के काम से शुरू करें।
1) लिखें कि क्या साथ में बदलना चाहिए
5–10 हालिया फीचर्स चुनें और नोट करें कि क्या उन्हें लॉकस्टेप में मूव करना पड़ा। मार्क करें कि हर एक ने UI स्क्रीन्स, API endpoints, डेटा टेबल्स, authentication rules, या shared validation को छुआ या नहीं। अगर ज़्यादातर फीचर्स तीनों क्षेत्रों में समन्वित बदलाव मांगते हैं, तो अलग सेटअप दर्द देगा जब तक आपकी रिलीज प्रक्रिया बहुत अनुशासित न हो।
2) साझा कोड और साझा निर्णयों का ट्रेस करें
साझा कोड केवल लाइब्रेरी नहीं है—यह कॉन्ट्रैक्ट्स (API स्कीमा), UI पैटर्न, और बिजनेस रूल्स भी हैं। नोट करें कि वे आज कहाँ रहते हैं, कौन उन्हें एडिट करता है, और बदलाव कैसे अप्रूव होते हैं। अगर साझा हिस्से रिपोज़ के बीच कॉपी होते हैं, तो यह संकेत है कि आपको बेहतर नियंत्रण चाहिए, या तो monorepo के साथ या कड़े वर्ज़निंग नियमों के साथ।
3) सीमाएँ और ओनर्स परिभाषित करें
निर्धारित करें कि यूनिट्स क्या हैं (ऐप्स, सर्विसेज, लाइब्रेरी), फिर हर यूनिट को एक ओनर असाइन करें। सीमाएँ रिपो लेआउट से ज़्यादा मायने रखती हैं। बिना ओनर्स के monorepo शोरगरम हो जाता है। बिना ओनर्स के polyrepo कट-ऑफ़ हो जाता है।
सरल चेकलिस्ट के लिए लक्ष्य रखें: प्रति deployable service/app एक रिपो या फोल्डर, साझा कॉन्ट्रैक्ट्स के लिए एक जगह, सचमुच साझा UI कंपोनेंट्स के लिए एक जगह, बिजनेस लॉजिक कहाँ रहता है इसका स्पष्ट नियम, और हर एक के लिए दस्तावेज़ित ओनर।
4) एक रिलीज मॉडल चुनें जिसे आप फॉलो कर सकें
अगर मोबाइल रिलीज़ बैकएंड बदल से पीछे हैं, तो compatibility प्लान चाहिए (versioned APIs, backward-compatible फ़ील्ड, या एक निर्धारित support window)। अगर हर चीज़ एक साथ शिप करनी है तो रिलीज ट्रेन काम कर सकती है, पर यह समन्वय बढ़ाती है।
ब्रांचिंग नियम साधारण रखें: शॉर्ट-लाइव्ड ब्रांच, छोटे मर्ज, और एक स्पष्ट hotfix पथ।
5) CI को सामान्य बदलावों के आसपास डिज़ाइन करें
पहले से ही worst-case के लिए CI डिज़ाइन न करें। इसे उसी के लिए डिज़ाइन करें जो लोग रोज़ करते हैं।
अगर ज़्यादातर commits केवल वेब UI छूते हैं, तो डिफ़ॉल्ट रूप से वेब lint और unit tests चलाएँ, और फुल end-to-end टेस्ट शेड्यूल या रिलीज़ से पहले चलाएँ। अगर incidents अक्सर API drift से आते हैं, तो पहले contract tests और client generation में निवेश करें।
उदाहरण: एक फीचर जो वेब, मोबाइल और बैकएंड को छूता है
एक छोटी टीम सोचिए जो तीन चीज़ें बना रही है: ग्राहक पोर्टल (web), फील्ड ऐप (mobile), और एक API (backend)। एक अनुरोध आता है: जॉब्स में नया “Service status” फ़ील्ड जोड़ें और हर जगह दिखाएँ।
यह बदलाव छोटा लगता है, पर यह एक समन्वय परिक्षण है। बैकएंड फ़ील्ड जोड़ता है और वैलिडेशन/रिस्पोंस अपडेट करता है। वेब इसे दिखाता और फ़िल्टर अपडेट करता है। मोबाइल को ऑफलाइन दिखाना, सिंक करना और एज केस हैंडल करने होंगे।
असली मुद्दा: API बदलाव ब्रेकिंग है। फ़ील्ड नाम status से बदलकर service_status हो गया, और पुराने क्लाइंट्स क्रैश कर जाते हैं अगर वे हैंडल न करें।
Monorepo में क्या बदलता है
यहाँ monorepo अक्सर शांत लगता है। बैकएंड, वेब और मोबाइल अपडेट एक ही पुल रिक्वेस्ट में (या समन्वित कमिट्स के सेट में) लैंड हो सकते हैं। CI प्रभावित टेस्ट चला सकता है, और आप एक टैग्ड रिलीज कर सकते हैं जिसमें तीनों अपडेट शामिल हों।
मुख्य जोखिम सामाजिक है, तकनीकी नहीं: एक रिपो में ब्रेकिंग बदलाव जल्दी मर्ज हो जाना आसान है, इसलिए आपके review नियम मजबूत होने चाहिए।
Polyrepo में क्या बदलता है
अलग रिपोज़ में हर ऐप अपनी गति पर रहता है। बैकएंड पहले शिप कर सकता है, और वेब/मोबाइल पकड़ने के लिए भागते हैं। अगर मोबाइल रिलीज़ के लिए ऐप स्टोर समीक्षा चाहिए, तो “फिक्स” को दिनों लग सकते हैं भले ही कोड छोटा हो।
टीमें आम तौर पर इसे अधिक संरचना के साथ हल करती हैं: versioned endpoints, backward-compatible responses, लंबे deprecation विंडो, और स्पष्ट rollout स्टेप्स। यह काम करता है पर लगातार प्रयास मांगता है।
साक्ष्य के आधार पर निर्णय लेते समय पिछले कुछ महीनों पर नज़र डालें:
- अगर incidents अक्सर mismatched वर्ज़न से आते हैं, तो कड़ा समन्वय अपनाएँ।
- अगर रिलीज़ तेज़ और समय-संवेदी हैं (खासतौर पर मोबाइल), तो ब्रेकिंग बदलाव टालें या उन्हें केंद्रीकृत करें।
- अगर टीमें स्वतंत्र हैं और अक्सर एक ही फीचर को नहीं छेड़तीं, तो polyrepo का ओवरहेड योग्य हो सकता है।
सामान्य गलतियाँ और जाल जिनसे बचें
अधिकतर टीमें इसलिए फेल होती हैं क्योंकि उन्होंने “गलत” रिपो स्ट्रक्चर नहीं चुना, बल्कि रोज़मर्रा की आदतें धीरे-धीरे friction जोड़ देती हैं जब तक हर बदलाव रिस्की न लगने लगे।
साझा कोड dumping ground बन जाता है
एक साझा लाइब्रेरी प्रलोभन देती है: हेल्पर्स, टाइप्स, UI बिट्स, “अस्थायी” वर्कअराउंड। जल्दी ही यह वह जगह बन जाता है जहाँ पुराना कोड छिप जाता है और कोई नहीं जानता कि क्या बदलना सुरक्षित है।
साझा कोड को छोटा और सख्त रखें। “साझा” का अर्थ होना चाहिए कि कई टीमें इसका उपयोग करती हैं, इसे सावधानी से समीक्षा किया जाता है, और इरादे से बदला जाता है।
छिपी हुई धारणाओं के जरिए कड़ा coupling
अलग रिपोज़ में भी सिस्टम कड़े जुड़े हो सकते हैं; coupling बस धारणाओं में चला जाता है: date formats, enum values, permission rules, और “यह फ़ील्ड हमेशा मौजूद है” जैसी बातें।
इसे रोकने के लिए कॉन्ट्रैक्ट्स दस्तावेज़ करें (फ़ील्ड का क्या मतलब है, किन मानों की अनुमति है) और इन्हें product rules की तरह मानें, ना कि trivia।
अस्पष्ट ownership
जब हर कोई कुछ भी बदल सकता है तो reviews उथले हो जाते हैं और गलतियाँ निकल जाती हैं। जब कोई क्षेत्र किसी का नहीं होता तो बग हफ्तों तक पड़े रहते हैं।
वेब, मोबाइल, बैकएंड, और साझा मॉड्यूल्स के लिए ओनर्स परिभाषित करें। ownership योगदान को रोकता नहीं; यह सुनिश्चित करता है कि बदलाव सही आँखों से गुजरें।
CI बिना pruning के बढ़ता रहता है
CI अक्सर छोटे से शुरू होता है, फिर हर घटना एक नया जॉब जोड़ देती है “सुरक्षित रहने के लिए।” महीनों बाद यह धीमा और महंगा बन जाता है, और लोग इससे बचते हैं।
एक सरल नियम मदद करता है: हर CI जॉब का स्पष्ट लक्ष्य और एक ओनर होना चाहिए, और अगर वह असली मुद्दों को पकड़ना बंद कर दे तो उसे हटा दें।
सतर्कता संकेत: जॉब्स में duplicate tests, दिनों तक रेड रहने वाले जॉब्स, “तेजी से बदलाव” जिनकी वेरिफ़िकेशन बिल्ड करने से ज़्यादा समय लेती है, और पाइपलाइन्स जो backend-only बदलाव पर मोबाइल बिल्ड ट्रिगर करते हैं।
रिलीज समन्वय आदिवासी ज्ञान पर निर्भर करता है
अगर रिलीज़ किसी व्यक्ति की याददाश्त और गुप्त नॉलेज पर निर्भर है, तो आप धीरे-धीरे धीमे शिप करेंगे और चीज़ें टूटेंगी।
रिलीज़ स्टेप्स लिखें, उन्हें दोहराने योग्य बनाएं, और उबाऊ चेक्स ऑटोमेट करें। भले ही आपका टूलिंग consistent backends और क्लाइंट्स जनरेट करे, फिर भी स्पष्ट रिलीज़ नियम चाहिए होंगे।
कमिट करने से पहले त्वरित जाँच
रिपोज़ पुनर्गठन से पहले यह जाँचें कि आपकी टीम आज कैसे शिप करती है। लक्ष्य कोई परफेक्ट स्ट्रक्चर नहीं है—यह है कि जब एक बदलाव वेब, मोबाइल, और बैकएंड को छूता है तो आश्चर्य कम हों।
पाँच सवाल पूछें:
- स्वतंत्र शिपिंग: क्या आप बैकएंड फिक्स रिलीज़ कर सकते हैं बिना उसी दिन मोबाइल अपडेट के दबाव के?
- API परिवर्तन नियम: क्या आपके पास deprecations के लिए लिखित कॉन्ट्रैक्ट है और पुराना व्यवहार कितनी देर तक समर्थित रहेगा?
- साझा कोड अनुशासन: क्या साझा लाइब्रेरी (UI कंपोनेंट्स, API क्लाइंट्स, बिजनेस रूल्स) सुसंगत तरीके से समीक्षा और वर्ज़निंग के साथ हैं?
- CI जो मायने रखता चलाता है: क्या CI बता सकता है कि क्या बदला और केवल प्रभावित हिस्सों के बिल्ड/टेस्ट चलते हैं?
- एक रिलीज़ दृश्य: क्या एक जगह है जहाँ वेब, मोबाइल, और बैकएंड पर जाने वाली चीज़ें, ओनर्स और तिथियाँ दिखाई दें?
सरल उदाहरण: चेकआउट में नया “address” फ़ील्ड जोड़ा गया। अगर बैकएंड पहले शिप होता है तो पुराना मोबाइल ऐप भी काम करना चाहिए। इसका मतलब आम तौर पर है कि API कुछ समय के लिए दोनों पुराना और नया payload स्वीकार करे और क्लाइंट अपडेट optional रहे, mandatory न हो।
अगले कदम: समन्वय काम घटाएँ और आत्मविश्वास के साथ शिप करें
लक्ष्य “सही” रिपो स्ट्रक्चर नहीं है। लक्ष्य है कम हैंडऑफ, कम आश्चर्य, और कम “किस वर्ज़न लाइव है?” के पल।
एक छोटा निर्णय रिकॉर्ड लिखें: आपने अपना मौजूदा तरीका क्यों चुना, आप क्या बेहतर होने की उम्मीद करते हैं, और आप कौन से ट्रेडऑफ़ स्वीकार कर रहे हैं। इसे हर 6–12 महीने में या टीम साइज/रिलीज़ कैडेंस बदलने पर फिर से देखें।
फाइलें हटाने-डालने से पहले वह सबसे छोटा बदलाव चुनें जो असली दर्द कम करे:
- साझा पैकेजों के लिए वर्ज़निंग नियम जोड़ें और उनका पालन करें।
- API कॉन्ट्रैक्ट्स परिभाषित करें और CI में contract tests लागू करें।
- वेब, मोबाइल, और बैकएंड के लिए एक सामान्य रिलीज चेकलिस्ट पर सहमति बनाएं।
- उन बदलावों के लिए preview environments का उपयोग करें जो कई हिस्सों को छूते हैं।
- CI समय बजट रखें (उदाहरण: PR चेक 15 मिनट से कम)।
यदि क्रॉस-कोडबेस coupling असली बाधा है, तो बदलने वाली जगहों की संख्या घटाना रिपो लेआउट से ज़्यादा मायने रख सकता है। कुछ टीमें यह एकल स्रोत-ऑफ़-ट्रुथ में और अधिक लॉजिक व डेटा मॉडल को स्थानांतरित करके करती हैं।
अगर आप उस दृष्टिकोण को एक्सप्लोर करना चाहते हैं, तो AppMaster (appmaster.io) बैकएंड सर्विसेज़, वेब ऐप और नेटिव मोबाइल ऐप्स साझा डेटा मॉडल और बिजनेस लॉजिक के साथ जनरेट करने के लिए बनाया गया है। एक कम-जोखिम तरीका यह है कि पहले एक छोटा internal टूल बनाकर आज़माएँ, फिर तय करें कि इसने कितना समन्वय काम कम कर दिया।
आत्मविश्वासी रास्ता जानबूझकर उबाऊ है: निर्णय दस्तावेज़ करें, coupling घटाएँ, चेक्स ऑटोमेट करें, और रिपो संरचना केवल तब बदलें जब आँकड़े कहें कि यह मदद करेगा।
सामान्य प्रश्न
सबसे पहले देखें कि एक फीचर कितनी बार web, mobile और backend में एक साथ बदलाव मांगता है। अगर ज़्यादातर काम क्रॉस-कटिंग हैं और समन्वय प्रमुख समस्या है, तो monorepo या एक मजबूत “single contract” तरीका अक्सर टूट-फूट कम करता है। अगर टीमें अलग-अलग क्षेत्रों को ही छेड़ती हैं और स्वतंत्र रिलीज़/पहुँच चाहिए, तो polyrepo सख्त compatibility नियमों के साथ अच्छा काम कर सकता है।
आम रूप से यह API drift, shared लाइब्रेरी के वर्जन मेल न खाने, और रिलीज़ समय का फर्क (खासकर mobile app store देरी) होता है। समाधान यह है कि आप वास्तविक दुनिया में mixed वर्ज़न के लिए योजना बनाएं, ना कि हमेशा परफ़ेक्ट सिंक की उम्मीद रखें, और ब्रेकिंग बदलाव दुर्लभ व जानबूझ कर करें।
API schema को source of truth मानें और उससे क्लाइंट बनाएं ताकि mismatch बिल्ड में ही फ़ेल हो, QA या प्रोडक्शन में नहीं। पहले additive changes (नए फ़ील्ड, नए एंडपॉइंट) पसंद करें, फिर पुराने फ़ील्ड को deprecated करें। अगर rename/remove करना ज़रूरी हो तो एक छोटा compatibility विंडो रखें।
छोटे, नियमित अपडेट रखें (साप्ताहिक बेहतर है चार्टरिक की बजाय) और ब्रेकिंग बदलाव के लिए स्पष्ट approval ज़रूरी करें। हर बदल के साथ एक छोटा migration नोट दें और “done” की परिभाषा रखें: “web, mobile और backend के बिल्ड पास हैं,” न कि सिर्फ़ एक रिपो।
डिफ़ॉल्ट तौर पर per-service versions रखें और एक साफ compatibility नियम तय करें: कौन से backend वर्ज़न किस client वर्ज़न का समर्थन करेंगे और कितने समय तक। शुरुआती दौर में एक shared release train काम कर सकता है, पर mobile देरी अक्सर इसे कठिन बना देती है जब तक कि आप app store टाइम्मिंग के लिए इंतज़ार कर सकें।
Backend को backward-compatible रखें ताकि पुराने mobile बिल्ड काम करते रहें जब तक उपयोगकर्ता अपडेट नहीं कर लेते। additive फ़ील्ड रखें, पुरानी व्यवहार जल्दी न हटाएँ, और क्लाइंट-वीज़िबल बदलाव gradual रोलआउट के लिए feature flags का उपयोग करें।
इसका जिम्मा किसी के लिए स्पष्ट रूप से रखें—अक्सर कोई tech lead, release manager, या product owner जिसकी इंजीनियरिंग सपोर्ट हो। काम है एक साधारण, दोहराने योग्य कैलेंडर रखना और देरी पर साफ़ निर्णय नियम (रिलीज़ रोकें बनाम compatibility बनाए रखें) लागू करना।
केवल वही बनाएं जो बदलता है—और जितना हो सके cache करें। बदल पर सिर्फ़ प्रभावित हिस्सों को बिल्ड/टेस्ट करें और तेज़ चेक्स (प्रत्येक कमिट) को धीमे चेक्स (main, nightly, pre-release) से अलग रखें ताकि डेवलपर्स को जल्दी फीडबैक मिले।
path filters और affected-only दृष्टिकोण अपनाएँ ताकि छोटे बदलाव पर पूरा सिस्टम न बहे। shared मॉड्यूल बदला तो केवल उनसे जुड़े ऐप्स के चेक्स चलाएँ। साथ ही review नियम स्पष्ट रखें ताकि एक रिपो सबका गारबेज डिब्बा न बन जाए।
टूलिंग व CI टेम्पलेट्स मानकीकृत रखें ताकि हर रिपो अलग pipeline न बनाये। एक integration चेक जोड़ें जो रिलीज़ के दौरान मुख्य कॉन्ट्रैक्ट्स को वेलिडेट करे और टूलचेन वर्ज़न पिन करें ताकि “एक रिपो में काम करता है” की समस्याएँ न हों।


